xref: /illumos-gate/usr/src/uts/sun4u/io/sbd.c (revision d5ebc493)
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
525e8c5aaSvikram  * Common Development and Distribution License (the "License").
625e8c5aaSvikram  * 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 /*
2356f33205SJonathan Adams  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
273fe80ca4SDan Cross /*
283fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
293fe80ca4SDan Cross  */
303fe80ca4SDan Cross 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * safari system board DR module.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <sys/debug.h>
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <sys/errno.h>
387c478bd9Sstevel@tonic-gate #include <sys/cred.h>
397c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
407c478bd9Sstevel@tonic-gate #include <sys/devops.h>
417c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
427c478bd9Sstevel@tonic-gate #include <sys/poll.h>
437c478bd9Sstevel@tonic-gate #include <sys/conf.h>
447c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
457c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
467c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
477c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
487c478bd9Sstevel@tonic-gate #include <sys/stat.h>
497c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
507c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
517c478bd9Sstevel@tonic-gate #include <sys/mem_config.h>
527c478bd9Sstevel@tonic-gate #include <sys/mem_cage.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
557c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
587c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
597c478bd9Sstevel@tonic-gate #include <sys/param.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #include <sys/sbdpriv.h>
627c478bd9Sstevel@tonic-gate #include <sys/sbd_io.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /* start sbd includes */
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #include <sys/systm.h>
677c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
687c478bd9Sstevel@tonic-gate #include <sys/x_call.h>
697c478bd9Sstevel@tonic-gate #include <sys/membar.h>
707c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate extern int nulldev();
737c478bd9Sstevel@tonic-gate extern int nodev();
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate typedef struct {		/* arg to sbd_get_handle */
767c478bd9Sstevel@tonic-gate 	dev_t	dev;
777c478bd9Sstevel@tonic-gate 	int	cmd;
787c478bd9Sstevel@tonic-gate 	int	mode;
797c478bd9Sstevel@tonic-gate 	sbd_ioctl_arg_t *ioargp;
807c478bd9Sstevel@tonic-gate } sbd_init_arg_t;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * sbd support operations.
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate static void	sbd_exec_op(sbd_handle_t *hp);
877c478bd9Sstevel@tonic-gate static void	sbd_dev_configure(sbd_handle_t *hp);
887c478bd9Sstevel@tonic-gate static int	sbd_dev_release(sbd_handle_t *hp);
897c478bd9Sstevel@tonic-gate static int	sbd_dev_unconfigure(sbd_handle_t *hp);
907c478bd9Sstevel@tonic-gate static void	sbd_attach_cpu(sbd_handle_t *hp, sbderror_t *ep,
917c478bd9Sstevel@tonic-gate 				dev_info_t *dip, int unit);
927c478bd9Sstevel@tonic-gate static void	sbd_detach_cpu(sbd_handle_t *hp, sbderror_t *ep,
937c478bd9Sstevel@tonic-gate 				dev_info_t *dip, int unit);
947c478bd9Sstevel@tonic-gate static int	sbd_detach_mem(sbd_handle_t *hp, sbderror_t *ep, int unit);
957c478bd9Sstevel@tonic-gate static void	sbd_cancel(sbd_handle_t *hp);
96*d5ebc493SDan Cross void	sbd_errno_decode(int err, sbderror_t *ep, dev_info_t *dip);
977c478bd9Sstevel@tonic-gate int		sbd_dealloc_instance(sbd_board_t *sbp, int max_boards);
987c478bd9Sstevel@tonic-gate int		sbd_errno2ecode(int error);
997c478bd9Sstevel@tonic-gate #pragma weak sbdp_cpu_get_impl
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate #ifdef DEBUG
1027c478bd9Sstevel@tonic-gate uint_t	sbd_debug	=	(uint_t)0x0;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate #ifdef SBD_DEBUG_ERRS
1057c478bd9Sstevel@tonic-gate /* controls which errors are injected */
1067c478bd9Sstevel@tonic-gate uint_t	sbd_err_debug	=	(uint_t)0x0;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /* controls printing about error injection */
1097c478bd9Sstevel@tonic-gate uint_t	sbd_print_errs	=	(uint_t)0x0;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate #endif /* SBD_DEBUG_ERRS */
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate char	*sbd_state_str[] = {
1167c478bd9Sstevel@tonic-gate 	"EMPTY", "OCCUPIED", "CONNECTED", "UNCONFIGURED",
1177c478bd9Sstevel@tonic-gate 	"PARTIAL", "CONFIGURED", "RELEASE", "UNREFERENCED",
1187c478bd9Sstevel@tonic-gate 	"FATAL"
1197c478bd9Sstevel@tonic-gate };
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*	Note: this must be changed in tandem with sbd_ioctl.h	*/
1227c478bd9Sstevel@tonic-gate char	*sbd_ct_str[] = {
1237c478bd9Sstevel@tonic-gate 	"NONE", "CPU", "MEM", "IO", "UNKNOWN"
1247c478bd9Sstevel@tonic-gate };
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /*	Note: this must also be changed in tandem with sbd_ioctl.h */
1277c478bd9Sstevel@tonic-gate #define	SBD_CMD_STR(c) \
1287c478bd9Sstevel@tonic-gate 	(((c) == SBD_CMD_ASSIGN)	? "ASSIGN"	: \
1297c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_UNASSIGN)	? "UNASSIGN"	: \
1307c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_POWERON)	? "POWERON"	: \
1317c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_POWEROFF)	? "POWEROFF"	: \
1327c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_TEST)		? "TEST"	: \
1337c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_CONNECT)	? "CONNECT"	: \
1347c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_CONFIGURE)	? "CONFIGURE"	: \
1357c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_UNCONFIGURE)	? "UNCONFIGURE"	: \
1367c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_DISCONNECT)	? "DISCONNECT"	: \
1377c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_STATUS)		? "STATUS"	: \
1387c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_GETNCM)		? "GETNCM"	: \
1397c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_PASSTHRU)	? "PASSTHRU"	: "unknown")
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate  * Defines and structures for device tree naming and mapping
1437c478bd9Sstevel@tonic-gate  * to node types
1447c478bd9Sstevel@tonic-gate  */
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate sbd_devattr_t *sbd_devattr;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /* defines to access the attribute struct */
1497c478bd9Sstevel@tonic-gate #define	SBD_DEVNAME(i)		sbd_devattr[i].s_devname
1507c478bd9Sstevel@tonic-gate #define	SBD_OTYPE(i)		sbd_devattr[(i)].s_obp_type
1517c478bd9Sstevel@tonic-gate #define	SBD_COMP(i)		sbd_devattr[i].s_dnodetype
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate  * State transition table.  States valid transitions for "board" state.
1557c478bd9Sstevel@tonic-gate  * Recall that non-zero return value terminates operation, however
1567c478bd9Sstevel@tonic-gate  * the herrno value is what really indicates an error , if any.
1577c478bd9Sstevel@tonic-gate  */
1587c478bd9Sstevel@tonic-gate static int
_cmd2index(int c)1597c478bd9Sstevel@tonic-gate _cmd2index(int c)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	/*
1627c478bd9Sstevel@tonic-gate 	 * Translate DR CMD to index into sbd_state_transition.
1637c478bd9Sstevel@tonic-gate 	 */
1647c478bd9Sstevel@tonic-gate 	switch (c) {
1657c478bd9Sstevel@tonic-gate 	case SBD_CMD_CONNECT:		return (0);
1667c478bd9Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:	return (1);
1677c478bd9Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:		return (2);
1687c478bd9Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:	return (3);
1697c478bd9Sstevel@tonic-gate 	case SBD_CMD_POWEROFF:		return (4);
1707c478bd9Sstevel@tonic-gate 	case SBD_CMD_POWERON:		return (5);
1717c478bd9Sstevel@tonic-gate 	case SBD_CMD_UNASSIGN:		return (6);
1727c478bd9Sstevel@tonic-gate 	case SBD_CMD_ASSIGN:		return (7);
1737c478bd9Sstevel@tonic-gate 	case SBD_CMD_TEST:		return (8);
1747c478bd9Sstevel@tonic-gate 	default:			return (-1);
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate #define	CMD2INDEX(c)	_cmd2index(c)
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate static struct sbd_state_trans {
1817c478bd9Sstevel@tonic-gate 	int	x_cmd;
1827c478bd9Sstevel@tonic-gate 	struct {
1837c478bd9Sstevel@tonic-gate 		int	x_rv;		/* return value of pre_op */
1847c478bd9Sstevel@tonic-gate 		int	x_err;		/* errno, if any */
1857c478bd9Sstevel@tonic-gate 	} x_op[SBD_NUM_STATES];
1867c478bd9Sstevel@tonic-gate } sbd_state_transition[] = {
1877c478bd9Sstevel@tonic-gate 	{ SBD_CMD_CONNECT,
1887c478bd9Sstevel@tonic-gate 		{
1897c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* empty */
1907c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
1917c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
1927c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
1937c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
1947c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
1957c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
1967c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
1977c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
1987c478bd9Sstevel@tonic-gate 		}
1997c478bd9Sstevel@tonic-gate 	},
2007c478bd9Sstevel@tonic-gate 	{ SBD_CMD_DISCONNECT,
2017c478bd9Sstevel@tonic-gate 		{
2027c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
2037c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
2047c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* connected */
2057c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* unconfigured */
2067c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
2077c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
2087c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
2097c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
2107c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
2117c478bd9Sstevel@tonic-gate 		}
2127c478bd9Sstevel@tonic-gate 	},
2137c478bd9Sstevel@tonic-gate 	{ SBD_CMD_CONFIGURE,
2147c478bd9Sstevel@tonic-gate 		{
2157c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
2167c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* occupied */
2177c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* connected */
2187c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* unconfigured */
2197c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* partial */
2207c478bd9Sstevel@tonic-gate 			{ 1, 0 },	/* configured */
2217c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* release */
2227c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* unreferenced */
2237c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
2247c478bd9Sstevel@tonic-gate 		}
2257c478bd9Sstevel@tonic-gate 	},
2267c478bd9Sstevel@tonic-gate 	{ SBD_CMD_UNCONFIGURE,
2277c478bd9Sstevel@tonic-gate 		{
2287c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
2297c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* occupied */
2307c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
2317c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
2327c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
2337c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* configured */
2347c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* release */
2357c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* unreferenced */
2367c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 	},
2397c478bd9Sstevel@tonic-gate 	{ SBD_CMD_POWEROFF,
2407c478bd9Sstevel@tonic-gate 		{
2417c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
2427c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
2437c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
2447c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
2457c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
2467c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
2477c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
2487c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
2497c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
2507c478bd9Sstevel@tonic-gate 		}
2517c478bd9Sstevel@tonic-gate 	},
2527c478bd9Sstevel@tonic-gate 	{ SBD_CMD_POWERON,
2537c478bd9Sstevel@tonic-gate 		{
2547c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
2557c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
2567c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
2577c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
2587c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
2597c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
2607c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
2617c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
2627c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
2637c478bd9Sstevel@tonic-gate 		}
2647c478bd9Sstevel@tonic-gate 	},
2657c478bd9Sstevel@tonic-gate 	{ SBD_CMD_UNASSIGN,
2667c478bd9Sstevel@tonic-gate 		{
2677c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
2687c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
2697c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
2707c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
2717c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
2727c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
2737c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
2747c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
2757c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
2767c478bd9Sstevel@tonic-gate 		}
2777c478bd9Sstevel@tonic-gate 	},
2787c478bd9Sstevel@tonic-gate 	{ SBD_CMD_ASSIGN,
2797c478bd9Sstevel@tonic-gate 		{
2807c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
2817c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
2827c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
2837c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
2847c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
2857c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
2867c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
2877c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
2887c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
2897c478bd9Sstevel@tonic-gate 		}
2907c478bd9Sstevel@tonic-gate 	},
2917c478bd9Sstevel@tonic-gate 	{ SBD_CMD_TEST,
2927c478bd9Sstevel@tonic-gate 		{
2937c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
2947c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
2957c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
2967c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
2977c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
2987c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
2997c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
3007c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
3017c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
3027c478bd9Sstevel@tonic-gate 		}
3037c478bd9Sstevel@tonic-gate 	},
3047c478bd9Sstevel@tonic-gate };
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate /*
3077c478bd9Sstevel@tonic-gate  * Global R/W lock to synchronize access across
3087c478bd9Sstevel@tonic-gate  * multiple boards.  Users wanting multi-board access
3097c478bd9Sstevel@tonic-gate  * must grab WRITE lock, others must grab READ lock.
3107c478bd9Sstevel@tonic-gate  */
3117c478bd9Sstevel@tonic-gate krwlock_t	sbd_grwlock;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate /*
3147c478bd9Sstevel@tonic-gate  * Global to determine if an event needs to be sent
3157c478bd9Sstevel@tonic-gate  */
3167c478bd9Sstevel@tonic-gate char send_event = 0;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate /*
3197c478bd9Sstevel@tonic-gate  * Required/Expected functions.
3207c478bd9Sstevel@tonic-gate  */
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate static sbd_handle_t	*sbd_get_handle(dev_t dev, sbd_softstate_t *softsp,
3237c478bd9Sstevel@tonic-gate 				intptr_t arg, sbd_init_arg_t *iap);
3247c478bd9Sstevel@tonic-gate static void		sbd_release_handle(sbd_handle_t *hp);
3257c478bd9Sstevel@tonic-gate static int		sbd_pre_op(sbd_handle_t *hp);
3267c478bd9Sstevel@tonic-gate static void		sbd_post_op(sbd_handle_t *hp);
3277c478bd9Sstevel@tonic-gate static int		sbd_probe_board(sbd_handle_t *hp);
3287c478bd9Sstevel@tonic-gate static int		sbd_deprobe_board(sbd_handle_t *hp);
3297c478bd9Sstevel@tonic-gate static void		sbd_connect(sbd_handle_t *hp);
3307c478bd9Sstevel@tonic-gate static void		sbd_assign_board(sbd_handle_t *hp);
3317c478bd9Sstevel@tonic-gate static void		sbd_unassign_board(sbd_handle_t *hp);
3327c478bd9Sstevel@tonic-gate static void		sbd_poweron_board(sbd_handle_t *hp);
3337c478bd9Sstevel@tonic-gate static void		sbd_poweroff_board(sbd_handle_t *hp);
3347c478bd9Sstevel@tonic-gate static void		sbd_test_board(sbd_handle_t *hp);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate static int		sbd_disconnect(sbd_handle_t *hp);
3377c478bd9Sstevel@tonic-gate static sbd_devlist_t	*sbd_get_attach_devlist(sbd_handle_t *hp,
3387c478bd9Sstevel@tonic-gate 					int32_t *devnump, int32_t pass);
3397c478bd9Sstevel@tonic-gate static int		sbd_pre_attach_devlist(sbd_handle_t *hp,
3407c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
3417c478bd9Sstevel@tonic-gate static int		sbd_post_attach_devlist(sbd_handle_t *hp,
3427c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
3437c478bd9Sstevel@tonic-gate static sbd_devlist_t	*sbd_get_release_devlist(sbd_handle_t *hp,
3447c478bd9Sstevel@tonic-gate 					int32_t *devnump, int32_t pass);
3457c478bd9Sstevel@tonic-gate static int		sbd_pre_release_devlist(sbd_handle_t *hp,
3467c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
3477c478bd9Sstevel@tonic-gate static int		sbd_post_release_devlist(sbd_handle_t *hp,
3487c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
3497c478bd9Sstevel@tonic-gate static void		sbd_release_done(sbd_handle_t *hp,
3507c478bd9Sstevel@tonic-gate 					sbd_comp_type_t nodetype,
3517c478bd9Sstevel@tonic-gate 					dev_info_t *dip);
3527c478bd9Sstevel@tonic-gate static sbd_devlist_t	*sbd_get_detach_devlist(sbd_handle_t *hp,
3537c478bd9Sstevel@tonic-gate 					int32_t *devnump, int32_t pass);
3547c478bd9Sstevel@tonic-gate static int		sbd_pre_detach_devlist(sbd_handle_t *hp,
3557c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
3567c478bd9Sstevel@tonic-gate static int		sbd_post_detach_devlist(sbd_handle_t *hp,
3577c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
3587c478bd9Sstevel@tonic-gate static void		sbd_status(sbd_handle_t *hp);
3597c478bd9Sstevel@tonic-gate static void		sbd_get_ncm(sbd_handle_t *hp);
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate /*
3637c478bd9Sstevel@tonic-gate  * Support functions.
3647c478bd9Sstevel@tonic-gate  */
3657c478bd9Sstevel@tonic-gate static sbd_devset_t	sbd_dev2devset(sbd_comp_id_t *cid);
3667c478bd9Sstevel@tonic-gate static int		sbd_copyin_ioarg(sbd_handle_t *hp, int mode, int cmd,
3677c478bd9Sstevel@tonic-gate 				sbd_cmd_t *cmdp, sbd_ioctl_arg_t *iap);
3687c478bd9Sstevel@tonic-gate static int		sbd_copyout_errs(int mode, sbd_ioctl_arg_t *iap,
3697c478bd9Sstevel@tonic-gate 					void *arg);
3707c478bd9Sstevel@tonic-gate static int		sbd_copyout_ioarg(int mode, int cmd, sbd_cmd_t *scp,
3717c478bd9Sstevel@tonic-gate 				sbd_ioctl_arg_t *iap);
3727c478bd9Sstevel@tonic-gate static int		sbd_check_transition(sbd_board_t *sbp,
3737c478bd9Sstevel@tonic-gate 					sbd_devset_t *devsetp,
3747c478bd9Sstevel@tonic-gate 					struct sbd_state_trans *transp);
3757c478bd9Sstevel@tonic-gate static sbd_devlist_t	*sbd_get_devlist(sbd_handle_t *hp,
3767c478bd9Sstevel@tonic-gate 					sbd_board_t *sbp,
3777c478bd9Sstevel@tonic-gate 					sbd_comp_type_t nodetype,
3787c478bd9Sstevel@tonic-gate 					int max_units, uint_t uset,
3797c478bd9Sstevel@tonic-gate 					int *count, int present_only);
3807c478bd9Sstevel@tonic-gate static int		sbd_mem_status(sbd_handle_t *hp, sbd_devset_t devset,
3817c478bd9Sstevel@tonic-gate 					sbd_dev_stat_t *dsp);
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate static int		sbd_init_devlists(sbd_board_t *sbp);
3847c478bd9Sstevel@tonic-gate static int		sbd_name_to_idx(char *name);
3857c478bd9Sstevel@tonic-gate static int		sbd_otype_to_idx(char *otpye);
3867c478bd9Sstevel@tonic-gate static int		sbd_setup_devlists(dev_info_t *dip, void *arg);
3877c478bd9Sstevel@tonic-gate static void		sbd_init_mem_devlists(sbd_board_t *sbp);
3887c478bd9Sstevel@tonic-gate static void		sbd_init_cpu_unit(sbd_board_t *sbp, int unit);
3897c478bd9Sstevel@tonic-gate static void		sbd_board_discovery(sbd_board_t *sbp);
3907c478bd9Sstevel@tonic-gate static void		sbd_board_init(sbd_board_t *sbp,
3917c478bd9Sstevel@tonic-gate 				sbd_softstate_t *softsp,
3927c478bd9Sstevel@tonic-gate 				int bd, dev_info_t *dip, int wnode);
3937c478bd9Sstevel@tonic-gate static void		sbd_board_destroy(sbd_board_t *sbp);
3947c478bd9Sstevel@tonic-gate static int		sbd_check_unit_attached(sbd_board_t *sbp,
3957c478bd9Sstevel@tonic-gate 				dev_info_t *dip, int unit,
3967c478bd9Sstevel@tonic-gate 				sbd_comp_type_t nodetype, sbderror_t *ep);
3977c478bd9Sstevel@tonic-gate 
398*d5ebc493SDan Cross static sbd_state_t	rstate_cvt(sbd_istate_t state);
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate  * Autoconfiguration data structures
4027c478bd9Sstevel@tonic-gate  */
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
4077c478bd9Sstevel@tonic-gate 	&mod_miscops,
408903a11ebSrh 	"System Board DR"
4097c478bd9Sstevel@tonic-gate };
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
4127c478bd9Sstevel@tonic-gate 	MODREV_1,
4137c478bd9Sstevel@tonic-gate 	(void *)&modlmisc,
4147c478bd9Sstevel@tonic-gate 	NULL
4157c478bd9Sstevel@tonic-gate };
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate static int sbd_instances = 0;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate  * dr Global data elements
4217c478bd9Sstevel@tonic-gate  */
4227c478bd9Sstevel@tonic-gate sbd_global sbd_g;
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate /*
4257c478bd9Sstevel@tonic-gate  * We want to be able to unload the module when we wish to do so, but we don't
4267c478bd9Sstevel@tonic-gate  * want anything else to unload it.  Unloading cannot occur until
4277c478bd9Sstevel@tonic-gate  * sbd_teardown_instance is called by an explicit IOCTL into the parent node.
4287c478bd9Sstevel@tonic-gate  * This support is for debugging purposes and should it be expected to work
4297c478bd9Sstevel@tonic-gate  * on the field, it should be enhanced:
4307c478bd9Sstevel@tonic-gate  * Currently, there is still a window where sbd_teardow_instance gets called,
4317c478bd9Sstevel@tonic-gate  * sbd_prevent_unloading now = 0, the driver doesn't get unloaded, and
4327c478bd9Sstevel@tonic-gate  * sbd_setup_instance gets called.  This may cause a panic.
4337c478bd9Sstevel@tonic-gate  */
4347c478bd9Sstevel@tonic-gate int sbd_prevent_unloading = 1;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate /*
4377c478bd9Sstevel@tonic-gate  * Driver entry points.
4387c478bd9Sstevel@tonic-gate  */
4397c478bd9Sstevel@tonic-gate int
_init(void)4407c478bd9Sstevel@tonic-gate _init(void)
4417c478bd9Sstevel@tonic-gate {
4427c478bd9Sstevel@tonic-gate 	int	err;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	/*
4457c478bd9Sstevel@tonic-gate 	 * If you need to support multiple nodes (instances), then
4467c478bd9Sstevel@tonic-gate 	 * whatever the maximum number of supported nodes is would
4477c478bd9Sstevel@tonic-gate 	 * need to passed as the third parameter to ddi_soft_state_init().
4487c478bd9Sstevel@tonic-gate 	 * Alternative would be to dynamically fini and re-init the
4497c478bd9Sstevel@tonic-gate 	 * soft state structure each time a node is attached.
4507c478bd9Sstevel@tonic-gate 	 */
4517c478bd9Sstevel@tonic-gate 	err = ddi_soft_state_init((void **)&sbd_g.softsp,
452*d5ebc493SDan Cross 	    sizeof (sbd_softstate_t), SBD_MAX_INSTANCES);
4537c478bd9Sstevel@tonic-gate 	if (err)
4547c478bd9Sstevel@tonic-gate 		return (err);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	if ((err = mod_install(&modlinkage)) != 0) {
4577c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini((void **)&sbd_g.softsp);
4587c478bd9Sstevel@tonic-gate 		return (err);
4597c478bd9Sstevel@tonic-gate 	}
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	/* Get the array of names from platform helper routine */
4627c478bd9Sstevel@tonic-gate 	sbd_devattr = sbdp_get_devattr();
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	return (err);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate int
_fini(void)4687c478bd9Sstevel@tonic-gate _fini(void)
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate 	int	err;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	if (sbd_prevent_unloading)
4737c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	ASSERT(sbd_instances == 0);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	if ((err = mod_remove(&modlinkage)) != 0)
4787c478bd9Sstevel@tonic-gate 		return (err);
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini((void **)&sbd_g.softsp);
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	return (0);
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)4867c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate int
sbd_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,char * event)4927c478bd9Sstevel@tonic-gate sbd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, char *event)
4937c478bd9Sstevel@tonic-gate {
4947c478bd9Sstevel@tonic-gate 	int		rv = 0, instance;
4957c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp;
4967c478bd9Sstevel@tonic-gate 	sbd_softstate_t	*softsp;
4977c478bd9Sstevel@tonic-gate 	sbd_init_arg_t	init_arg;
4987c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_ioctl";
4997c478bd9Sstevel@tonic-gate 	int		dr_avail;
5007c478bd9Sstevel@tonic-gate 
50104580fdfSmathue 	PR_BYP("sbd_ioctl cmd=%x, arg=%lx\n", cmd, arg);
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	/* Note: this must also be changed in tandem with sbd_ioctl.h */
5047c478bd9Sstevel@tonic-gate 	switch (cmd) {
5057c478bd9Sstevel@tonic-gate 		case SBD_CMD_ASSIGN:
5067c478bd9Sstevel@tonic-gate 		case SBD_CMD_UNASSIGN:
5077c478bd9Sstevel@tonic-gate 		case SBD_CMD_POWERON:
5087c478bd9Sstevel@tonic-gate 		case SBD_CMD_POWEROFF:
5097c478bd9Sstevel@tonic-gate 		case SBD_CMD_TEST:
5107c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONNECT:
5117c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONFIGURE:
5127c478bd9Sstevel@tonic-gate 		case SBD_CMD_UNCONFIGURE:
5137c478bd9Sstevel@tonic-gate 		case SBD_CMD_DISCONNECT:
5147c478bd9Sstevel@tonic-gate 		case SBD_CMD_STATUS:
5157c478bd9Sstevel@tonic-gate 		case SBD_CMD_GETNCM:
5167c478bd9Sstevel@tonic-gate 		case SBD_CMD_PASSTHRU:
5177c478bd9Sstevel@tonic-gate 			break;
5187c478bd9Sstevel@tonic-gate 		default:
5197c478bd9Sstevel@tonic-gate 			return (ENOTTY);
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	instance = SBD_GET_MINOR2INST(getminor(dev));
5237c478bd9Sstevel@tonic-gate 	if ((softsp = (sbd_softstate_t *)GET_SOFTC(instance)) == NULL) {
5247c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
525*d5ebc493SDan Cross 		    "sbd:%s:%d: module not yet attached", f, instance);
5267c478bd9Sstevel@tonic-gate 		return (ENXIO);
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	init_arg.dev = dev;
5307c478bd9Sstevel@tonic-gate 	init_arg.cmd = cmd;
5317c478bd9Sstevel@tonic-gate 	init_arg.mode = mode;
5327c478bd9Sstevel@tonic-gate 	init_arg.ioargp = (sbd_ioctl_arg_t *)arg;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	hp = sbd_get_handle(dev, softsp, arg, &init_arg);
5357c478bd9Sstevel@tonic-gate 	/* Check to see if we support dr */
5367c478bd9Sstevel@tonic-gate 	dr_avail = sbdp_dr_avail();
5377c478bd9Sstevel@tonic-gate 	if (dr_avail != 1) {
5387c478bd9Sstevel@tonic-gate 		switch (hp->h_cmd) {
5397c478bd9Sstevel@tonic-gate 			case SBD_CMD_STATUS:
5407c478bd9Sstevel@tonic-gate 			case SBD_CMD_GETNCM:
5417c478bd9Sstevel@tonic-gate 			case SBD_CMD_PASSTHRU:
5427c478bd9Sstevel@tonic-gate 				break;
5437c478bd9Sstevel@tonic-gate 			default:
5447c478bd9Sstevel@tonic-gate 				sbd_release_handle(hp);
5457c478bd9Sstevel@tonic-gate 				return (ENOTSUP);
5467c478bd9Sstevel@tonic-gate 		}
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	switch (hp->h_cmd) {
5507c478bd9Sstevel@tonic-gate 	case SBD_CMD_STATUS:
5517c478bd9Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
5527c478bd9Sstevel@tonic-gate 	case SBD_CMD_PASSTHRU:
5537c478bd9Sstevel@tonic-gate 		/* no locks needed for these commands */
5547c478bd9Sstevel@tonic-gate 		break;
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	default:
5577c478bd9Sstevel@tonic-gate 		rw_enter(&sbd_grwlock, RW_WRITER);
5587c478bd9Sstevel@tonic-gate 		mutex_enter(&SBDH2BD(hp->h_sbd)->sb_mutex);
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 		/*
5617c478bd9Sstevel@tonic-gate 		 * If we're dealing with memory at all, then we have
5627c478bd9Sstevel@tonic-gate 		 * to keep the "exclusive" global lock held.  This is
5637c478bd9Sstevel@tonic-gate 		 * necessary since we will probably need to look at
5647c478bd9Sstevel@tonic-gate 		 * multiple board structs.  Otherwise, we only have
5657c478bd9Sstevel@tonic-gate 		 * to deal with the board in question and so can drop
5667c478bd9Sstevel@tonic-gate 		 * the global lock to "shared".
5677c478bd9Sstevel@tonic-gate 		 */
5687c478bd9Sstevel@tonic-gate 		/*
5697c478bd9Sstevel@tonic-gate 		 * XXX This is incorrect. The sh_devset has not
5707c478bd9Sstevel@tonic-gate 		 * been set at this point - it is 0.
5717c478bd9Sstevel@tonic-gate 		 */
5727c478bd9Sstevel@tonic-gate 		rv = DEVSET_IN_SET(HD2MACHHD(hp)->sh_devset,
5737c478bd9Sstevel@tonic-gate 		    SBD_COMP_MEM, DEVSET_ANYUNIT);
5747c478bd9Sstevel@tonic-gate 		if (rv == 0)
5757c478bd9Sstevel@tonic-gate 			rw_downgrade(&sbd_grwlock);
5767c478bd9Sstevel@tonic-gate 		break;
5777c478bd9Sstevel@tonic-gate 	}
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	/*
5807c478bd9Sstevel@tonic-gate 	 * Before any operations happen, reset the event flag
5817c478bd9Sstevel@tonic-gate 	 */
5827c478bd9Sstevel@tonic-gate 	send_event = 0;
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	if (sbd_pre_op(hp) == 0) {
5857c478bd9Sstevel@tonic-gate 		sbd_exec_op(hp);
5867c478bd9Sstevel@tonic-gate 		sbd_post_op(hp);
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	rv = SBD_GET_ERRNO(SBD_HD2ERR(hp));
5907c478bd9Sstevel@tonic-gate 	*event = send_event;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	/* undo locking, if any, done before sbd_pre_op */
5937c478bd9Sstevel@tonic-gate 	switch (hp->h_cmd) {
5947c478bd9Sstevel@tonic-gate 	case SBD_CMD_STATUS:
5957c478bd9Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
5967c478bd9Sstevel@tonic-gate 	case SBD_CMD_PASSTHRU:
5977c478bd9Sstevel@tonic-gate 		break;
5987c478bd9Sstevel@tonic-gate 	default:
5997c478bd9Sstevel@tonic-gate 		mutex_exit(&SBDH2BD(hp->h_sbd)->sb_mutex);
6007c478bd9Sstevel@tonic-gate 		rw_exit(&sbd_grwlock);
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	sbd_release_handle(hp);
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	return (rv);
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate int
sbd_setup_instance(int instance,dev_info_t * root,int max_boards,int wnode,caddr_t sbdp_arg)6097c478bd9Sstevel@tonic-gate sbd_setup_instance(int instance, dev_info_t *root, int max_boards, int wnode,
610*d5ebc493SDan Cross     caddr_t sbdp_arg)
6117c478bd9Sstevel@tonic-gate {
612*d5ebc493SDan Cross 	int		b;
6137c478bd9Sstevel@tonic-gate 	sbd_softstate_t	*softsp;
6147c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbd_boardlist;
6157c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_setup_instance";
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	sbd_instances++;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	if (sbdp_setup_instance(sbdp_arg) != DDI_SUCCESS) {
6207c478bd9Sstevel@tonic-gate 		sbd_instances--;
6217c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if (ALLOC_SOFTC(instance) != DDI_SUCCESS) {
6257c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
626*d5ebc493SDan Cross 		    "sbd:%s:%d: failed to alloc soft-state", f, instance);
62707d06da5SSurya Prakki 		(void) sbdp_teardown_instance(sbdp_arg);
6287c478bd9Sstevel@tonic-gate 		sbd_instances--;
6297c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	softsp = (sbd_softstate_t *)GET_SOFTC(instance);
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	if (softsp == NULL) {
6357c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
636*d5ebc493SDan Cross 		    "sbd:%s:%d: failed to get soft-state instance",
637*d5ebc493SDan Cross 		    f, instance);
6387c478bd9Sstevel@tonic-gate 		goto exit;
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	sbd_boardlist = GETSTRUCT(sbd_board_t, max_boards);
6427c478bd9Sstevel@tonic-gate 	if (sbd_boardlist == NULL) {
6437c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
644*d5ebc493SDan Cross 		    "sbd:%s: failed to alloc board list %d", f, instance);
6457c478bd9Sstevel@tonic-gate 		goto exit;
6467c478bd9Sstevel@tonic-gate 	}
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	softsp->sbd_boardlist  = (void *)sbd_boardlist;
6507c478bd9Sstevel@tonic-gate 	softsp->max_boards  = max_boards;
6517c478bd9Sstevel@tonic-gate 	softsp->wnode  = wnode;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	for (b = 0; b < max_boards; b++) {
6557c478bd9Sstevel@tonic-gate 		sbd_board_init(sbd_boardlist++, softsp, b, root, wnode);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6607c478bd9Sstevel@tonic-gate exit:
6617c478bd9Sstevel@tonic-gate 	(void) sbdp_teardown_instance(sbdp_arg);
6627c478bd9Sstevel@tonic-gate 	FREE_SOFTC(instance);
6637c478bd9Sstevel@tonic-gate 	sbd_instances--;
6647c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate int
sbd_teardown_instance(int instance,caddr_t sbdp_arg)6687c478bd9Sstevel@tonic-gate sbd_teardown_instance(int instance, caddr_t sbdp_arg)
6697c478bd9Sstevel@tonic-gate {
6707c478bd9Sstevel@tonic-gate 	sbd_softstate_t	*softsp;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	if (sbdp_teardown_instance(sbdp_arg) != DDI_SUCCESS)
6737c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	softsp = (sbd_softstate_t *)GET_SOFTC(instance);
6767c478bd9Sstevel@tonic-gate 	if (softsp == NULL) {
6777c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	(void) sbd_dealloc_instance((sbd_board_t *)softsp->sbd_boardlist,
681*d5ebc493SDan Cross 	    softsp->max_boards);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	FREE_SOFTC(instance);
6847c478bd9Sstevel@tonic-gate 	sbd_instances--;
6857c478bd9Sstevel@tonic-gate 	sbd_prevent_unloading = 0;
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate static void
sbd_exec_op(sbd_handle_t * hp)6917c478bd9Sstevel@tonic-gate sbd_exec_op(sbd_handle_t *hp)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
6947c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_exec_op";
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	switch (hp->h_cmd) {
6977c478bd9Sstevel@tonic-gate 		int	dev_canceled;
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	case SBD_CMD_CONNECT:
7007c478bd9Sstevel@tonic-gate 		if (sbd_probe_board(hp))
7017c478bd9Sstevel@tonic-gate 			break;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 		sbd_connect(hp);
7047c478bd9Sstevel@tonic-gate 		break;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:
7077c478bd9Sstevel@tonic-gate 		sbd_dev_configure(hp);
7087c478bd9Sstevel@tonic-gate 		break;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:
7117c478bd9Sstevel@tonic-gate 		if (((dev_canceled = sbd_dev_release(hp)) == 0) &&
7127c478bd9Sstevel@tonic-gate 		    (SBD_GET_ERRNO(SBD_HD2ERR(hp)) == 0 &&
7137c478bd9Sstevel@tonic-gate 		    SBD_GET_ERR(SBD_HD2ERR(hp)) == 0))
7147c478bd9Sstevel@tonic-gate 			dev_canceled = sbd_dev_unconfigure(hp);
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		if (dev_canceled)
7177c478bd9Sstevel@tonic-gate 			sbd_cancel(hp);
7187c478bd9Sstevel@tonic-gate 		break;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:
7217c478bd9Sstevel@tonic-gate 		mutex_enter(&sbp->sb_slock);
7227c478bd9Sstevel@tonic-gate 		if (sbd_disconnect(hp) == 0)
7237c478bd9Sstevel@tonic-gate 			(void) sbd_deprobe_board(hp);
7247c478bd9Sstevel@tonic-gate 		mutex_exit(&sbp->sb_slock);
7257c478bd9Sstevel@tonic-gate 		break;
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	case SBD_CMD_STATUS:
7287c478bd9Sstevel@tonic-gate 		sbd_status(hp);
7297c478bd9Sstevel@tonic-gate 		break;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
7327c478bd9Sstevel@tonic-gate 		sbd_get_ncm(hp);
7337c478bd9Sstevel@tonic-gate 		break;
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	case SBD_CMD_ASSIGN:
7367c478bd9Sstevel@tonic-gate 		sbd_assign_board(hp);
7377c478bd9Sstevel@tonic-gate 		break;
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	case SBD_CMD_UNASSIGN:
7407c478bd9Sstevel@tonic-gate 		sbd_unassign_board(hp);
7417c478bd9Sstevel@tonic-gate 		break;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	case SBD_CMD_POWEROFF:
7447c478bd9Sstevel@tonic-gate 		sbd_poweroff_board(hp);
7457c478bd9Sstevel@tonic-gate 		break;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	case SBD_CMD_POWERON:
7487c478bd9Sstevel@tonic-gate 		sbd_poweron_board(hp);
7497c478bd9Sstevel@tonic-gate 		break;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	case SBD_CMD_TEST:
7527c478bd9Sstevel@tonic-gate 		sbd_test_board(hp);
7537c478bd9Sstevel@tonic-gate 		break;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	case SBD_CMD_PASSTHRU:
7567c478bd9Sstevel@tonic-gate 	{
7577c478bd9Sstevel@tonic-gate 		int			rv;
7587c478bd9Sstevel@tonic-gate 		sbdp_handle_t		*hdp;
7597c478bd9Sstevel@tonic-gate 		sbderror_t		*ep = SBD_HD2ERR(hp);
7607c478bd9Sstevel@tonic-gate 		sbdp_ioctl_arg_t	ia, *iap;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 		iap = &ia;
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 		iap->h_dev = hp->h_dev;
7657c478bd9Sstevel@tonic-gate 		iap->h_cmd = hp->h_cmd;
7667c478bd9Sstevel@tonic-gate 		iap->h_iap = (intptr_t)hp->h_iap;
7677c478bd9Sstevel@tonic-gate 		iap->h_mode = hp->h_mode;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 		hdp = sbd_get_sbdp_handle(sbp, hp);
7707c478bd9Sstevel@tonic-gate 		rv = sbdp_ioctl(hdp, iap);
7717c478bd9Sstevel@tonic-gate 		if (rv != 0) {
7727c478bd9Sstevel@tonic-gate 			SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
7737c478bd9Sstevel@tonic-gate 			ep->e_errno = rv;
7747c478bd9Sstevel@tonic-gate 		}
7757c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
7767c478bd9Sstevel@tonic-gate 		break;
7777c478bd9Sstevel@tonic-gate 	}
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	default:
7807c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(SBD_HD2ERR(hp), ENOTTY);
781*d5ebc493SDan Cross 		cmn_err(CE_WARN, "sbd:%s: unknown command (%d)", f, hp->h_cmd);
7827c478bd9Sstevel@tonic-gate 		break;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	}
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERR(SBD_HD2ERR(hp)))
7877c478bd9Sstevel@tonic-gate 		PR_BYP("XXX e_code=%d", SBD_GET_ERR(SBD_HD2ERR(hp)));
7887c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERRNO(SBD_HD2ERR(hp)))
7897c478bd9Sstevel@tonic-gate 		PR_BYP("XXX errno=%d", SBD_GET_ERRNO(SBD_HD2ERR(hp)));
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate sbd_comp_type_t
sbd_get_devtype(sbd_handle_t * hp,dev_info_t * dip)7937c478bd9Sstevel@tonic-gate sbd_get_devtype(sbd_handle_t *hp, dev_info_t *dip)
7947c478bd9Sstevel@tonic-gate {
7957c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = hp ? SBDH2BD(hp->h_sbd) : NULL;
7967c478bd9Sstevel@tonic-gate 	sbd_istate_t	bstate;
7977c478bd9Sstevel@tonic-gate 	dev_info_t	**devlist;
7987c478bd9Sstevel@tonic-gate 	int		i;
7997c478bd9Sstevel@tonic-gate 	char		device[OBP_MAXDRVNAME];
8007c478bd9Sstevel@tonic-gate 	int		devicelen;
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	devicelen = sizeof (device);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	bstate = sbp ? SBD_BOARD_STATE(sbp) : SBD_STATE_EMPTY;
8057c478bd9Sstevel@tonic-gate 	/*
8067c478bd9Sstevel@tonic-gate 	 * if the board's connected or configured, search the
8077c478bd9Sstevel@tonic-gate 	 * devlists.  Otherwise check the device tree
8087c478bd9Sstevel@tonic-gate 	 */
8097c478bd9Sstevel@tonic-gate 	switch (bstate) {
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONNECTED:
8127c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONFIGURED:
8137c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNREFERENCED:
8147c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNCONFIGURED:
8157c478bd9Sstevel@tonic-gate 		devlist = sbp->sb_devlist[NIX(SBD_COMP_MEM)];
8167c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++)
8177c478bd9Sstevel@tonic-gate 			if (devlist[i] == dip)
8187c478bd9Sstevel@tonic-gate 				return (SBD_COMP_MEM);
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 		devlist = sbp->sb_devlist[NIX(SBD_COMP_CPU)];
8217c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++)
8227c478bd9Sstevel@tonic-gate 			if (devlist[i] == dip)
8237c478bd9Sstevel@tonic-gate 				return (SBD_COMP_CPU);
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 		devlist = sbp->sb_devlist[NIX(SBD_COMP_IO)];
8267c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++)
8277c478bd9Sstevel@tonic-gate 			if (devlist[i] == dip)
8287c478bd9Sstevel@tonic-gate 				return (SBD_COMP_IO);
8297c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	default:
8327c478bd9Sstevel@tonic-gate 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
8337c478bd9Sstevel@tonic-gate 		    OBP_DEVICETYPE,  (caddr_t)device, &devicelen))
8347c478bd9Sstevel@tonic-gate 			break;
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 		for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) {
8377c478bd9Sstevel@tonic-gate 			if (strcmp(device, SBD_OTYPE(i)) != 0)
8387c478bd9Sstevel@tonic-gate 				continue;
8397c478bd9Sstevel@tonic-gate 			return (SBD_COMP(i));
8407c478bd9Sstevel@tonic-gate 		}
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 		break;
8437c478bd9Sstevel@tonic-gate 	}
8447c478bd9Sstevel@tonic-gate 	return (SBD_COMP_UNKNOWN);
8457c478bd9Sstevel@tonic-gate }
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate static void
sbd_dev_configure(sbd_handle_t * hp)8487c478bd9Sstevel@tonic-gate sbd_dev_configure(sbd_handle_t *hp)
8497c478bd9Sstevel@tonic-gate {
8507c478bd9Sstevel@tonic-gate 	int		n, unit;
8517c478bd9Sstevel@tonic-gate 	int32_t		pass, devnum;
8527c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
8537c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*devlist;
8547c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
8557c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
8567c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	pass = 1;
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
8617c478bd9Sstevel@tonic-gate 	while ((devlist = sbd_get_attach_devlist(hp, &devnum, pass)) != NULL) {
8627c478bd9Sstevel@tonic-gate 		int	err;
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 		err = sbd_pre_attach_devlist(hp, devlist, devnum);
8657c478bd9Sstevel@tonic-gate 		if (err < 0) {
8667c478bd9Sstevel@tonic-gate 			break;
8677c478bd9Sstevel@tonic-gate 		} else if (err > 0) {
8687c478bd9Sstevel@tonic-gate 			pass++;
8697c478bd9Sstevel@tonic-gate 			continue;
8707c478bd9Sstevel@tonic-gate 		}
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 		for (n = 0; n < devnum; n++) {
8737c478bd9Sstevel@tonic-gate 			sbderror_t	*ep;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 			ep = &devlist[n].dv_error;
8767c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, 0);
8777c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(ep, 0);
8787c478bd9Sstevel@tonic-gate 			dip = devlist[n].dv_dip;
8797c478bd9Sstevel@tonic-gate 			nodetype = sbd_get_devtype(hp, dip);
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 			unit = sbdp_get_unit_num(hdp, dip);
8827c478bd9Sstevel@tonic-gate 			if (unit < 0) {
8837c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
8847c478bd9Sstevel@tonic-gate 				break;
8857c478bd9Sstevel@tonic-gate 			}
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 			switch (nodetype) {
8887c478bd9Sstevel@tonic-gate 			case SBD_COMP_MEM:
8897c478bd9Sstevel@tonic-gate 				sbd_attach_mem(hp, ep);
8907c478bd9Sstevel@tonic-gate 				if (SBD_GET_ERR(ep) == ESBD_CPUONLINE) {
8917c478bd9Sstevel@tonic-gate 					FREESTRUCT(devlist, sbd_devlist_t,
892*d5ebc493SDan Cross 					    MAX_MEM_UNITS_PER_BOARD);
8937c478bd9Sstevel@tonic-gate 					sbd_release_sbdp_handle(hdp);
8947c478bd9Sstevel@tonic-gate 					return;
8957c478bd9Sstevel@tonic-gate 				}
8967c478bd9Sstevel@tonic-gate 				break;
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 			case SBD_COMP_CPU:
8997c478bd9Sstevel@tonic-gate 				sbd_attach_cpu(hp, ep, dip, unit);
9007c478bd9Sstevel@tonic-gate 				break;
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 			case SBD_COMP_IO:
9037c478bd9Sstevel@tonic-gate 				sbd_attach_io(hp, ep, dip, unit);
9047c478bd9Sstevel@tonic-gate 				break;
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 			default:
9077c478bd9Sstevel@tonic-gate 				SBD_SET_ERRNO(ep, ENOTTY);
9087c478bd9Sstevel@tonic-gate 				break;
9097c478bd9Sstevel@tonic-gate 			}
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 			if (sbd_set_err_in_hdl(hp, ep) == 0)
9127c478bd9Sstevel@tonic-gate 				continue;
9137c478bd9Sstevel@tonic-gate 		}
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 		err = sbd_post_attach_devlist(hp, devlist, devnum);
9167c478bd9Sstevel@tonic-gate 		if (err < 0)
9177c478bd9Sstevel@tonic-gate 			break;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 		pass++;
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate static int
sbd_dev_release(sbd_handle_t * hp)9257c478bd9Sstevel@tonic-gate sbd_dev_release(sbd_handle_t *hp)
9267c478bd9Sstevel@tonic-gate {
9277c478bd9Sstevel@tonic-gate 	int		n, unit;
9287c478bd9Sstevel@tonic-gate 	int32_t		pass, devnum;
9297c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
9307c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
9317c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
9327c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*devlist;
9337c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
9347c478bd9Sstevel@tonic-gate 	int		err = 0;
9357c478bd9Sstevel@tonic-gate 	int		dev_canceled;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	pass = 1;
9387c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	sbp->sb_busy = 1;
941*d5ebc493SDan Cross 	while ((devlist = sbd_get_release_devlist(hp, &devnum, pass)) != NULL) {
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 		err = sbd_pre_release_devlist(hp, devlist, devnum);
9447c478bd9Sstevel@tonic-gate 		if (err < 0) {
9457c478bd9Sstevel@tonic-gate 			dev_canceled = 1;
9467c478bd9Sstevel@tonic-gate 			break;
9477c478bd9Sstevel@tonic-gate 		} else if (err > 0) {
9487c478bd9Sstevel@tonic-gate 			pass++;
9497c478bd9Sstevel@tonic-gate 			continue;
9507c478bd9Sstevel@tonic-gate 		}
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 		dev_canceled = 0;
9537c478bd9Sstevel@tonic-gate 		for (n = 0; n < devnum; n++) {
9547c478bd9Sstevel@tonic-gate 			dip = devlist[n].dv_dip;
9557c478bd9Sstevel@tonic-gate 			nodetype = sbd_get_devtype(hp, dip);
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 			unit = sbdp_get_unit_num(hdp, dip);
9587c478bd9Sstevel@tonic-gate 			if (unit < 0) {
9597c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
9607c478bd9Sstevel@tonic-gate 				break;
9617c478bd9Sstevel@tonic-gate 			}
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 			if ((nodetype == SBD_COMP_MEM) &&
9647c478bd9Sstevel@tonic-gate 			    sbd_release_mem(hp, dip, unit)) {
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 				dev_canceled++;
9677c478bd9Sstevel@tonic-gate 			}
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 			sbd_release_done(hp, nodetype, dip);
9707c478bd9Sstevel@tonic-gate 		}
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 		err = sbd_post_release_devlist(hp, devlist, devnum);
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 		if (err < 0)
9757c478bd9Sstevel@tonic-gate 			break;
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 		if (dev_canceled)
9787c478bd9Sstevel@tonic-gate 			break;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 		pass++;
9817c478bd9Sstevel@tonic-gate 	}
9827c478bd9Sstevel@tonic-gate 	sbp->sb_busy = 0;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	if (dev_canceled)
9877c478bd9Sstevel@tonic-gate 		return (dev_canceled);
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	return (err);
9907c478bd9Sstevel@tonic-gate }
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate static int
sbd_dev_unconfigure(sbd_handle_t * hp)9937c478bd9Sstevel@tonic-gate sbd_dev_unconfigure(sbd_handle_t *hp)
9947c478bd9Sstevel@tonic-gate {
9957c478bd9Sstevel@tonic-gate 	int		n, unit;
9967c478bd9Sstevel@tonic-gate 	int32_t		pass, devnum;
9977c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
9987c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*devlist;
9997c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
10007c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
10017c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
10027c478bd9Sstevel@tonic-gate 	int		dev_canceled = 0;
10037c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_dev_unconfigure";
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	pass = 1;
10087c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	while ((devlist = sbd_get_detach_devlist(hp, &devnum, pass)) != NULL) {
10117c478bd9Sstevel@tonic-gate 		int	err, detach_err = 0;
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 		err = sbd_pre_detach_devlist(hp, devlist, devnum);
10147c478bd9Sstevel@tonic-gate 		if (err) {
10157c478bd9Sstevel@tonic-gate 			/*
10167c478bd9Sstevel@tonic-gate 			 * Only cancel the operation for memory in
10177c478bd9Sstevel@tonic-gate 			 * case of failure.
10187c478bd9Sstevel@tonic-gate 			 */
10197c478bd9Sstevel@tonic-gate 			nodetype = sbd_get_devtype(hp, devlist->dv_dip);
10207c478bd9Sstevel@tonic-gate 			if (nodetype == SBD_COMP_MEM)
10217c478bd9Sstevel@tonic-gate 				dev_canceled = 1;
10227c478bd9Sstevel@tonic-gate 			(void) sbd_post_detach_devlist(hp, devlist, devnum);
10237c478bd9Sstevel@tonic-gate 			break;
10247c478bd9Sstevel@tonic-gate 		}
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 		for (n = 0; n < devnum; n++) {
10277c478bd9Sstevel@tonic-gate 			sbderror_t	*ep;
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 			ep = &devlist[n].dv_error;
10307c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, 0);
10317c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(ep, 0);
10327c478bd9Sstevel@tonic-gate 			dip = devlist[n].dv_dip;
10337c478bd9Sstevel@tonic-gate 			nodetype = sbd_get_devtype(hp, dip);
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 			unit = sbdp_get_unit_num(hdp, dip);
10367c478bd9Sstevel@tonic-gate 			if (unit < 0) {
10377c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
10387c478bd9Sstevel@tonic-gate 				break;
10397c478bd9Sstevel@tonic-gate 			}
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 			switch (nodetype) {
10427c478bd9Sstevel@tonic-gate 			case SBD_COMP_MEM:
10437c478bd9Sstevel@tonic-gate 				dev_canceled = sbd_detach_mem(hp, ep, unit);
10447c478bd9Sstevel@tonic-gate 				break;
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 			case SBD_COMP_CPU:
10477c478bd9Sstevel@tonic-gate 				sbd_detach_cpu(hp, ep, dip, unit);
10487c478bd9Sstevel@tonic-gate 				break;
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 			case SBD_COMP_IO:
10517c478bd9Sstevel@tonic-gate 				sbd_detach_io(hp, ep, dip, unit);
10527c478bd9Sstevel@tonic-gate 				break;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 			default:
10557c478bd9Sstevel@tonic-gate 				SBD_SET_ERRNO(ep, ENOTTY);
10567c478bd9Sstevel@tonic-gate 				break;
10577c478bd9Sstevel@tonic-gate 			}
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 			if (sbd_set_err_in_hdl(hp, ep) == 0) {
10607c478bd9Sstevel@tonic-gate 				detach_err = -1;
10617c478bd9Sstevel@tonic-gate 				break;
10627c478bd9Sstevel@tonic-gate 			}
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 		}
10657c478bd9Sstevel@tonic-gate 		err = sbd_post_detach_devlist(hp, devlist, devnum);
10667c478bd9Sstevel@tonic-gate 		if ((err < 0) || (detach_err < 0))
10677c478bd9Sstevel@tonic-gate 			break;
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 		pass++;
10707c478bd9Sstevel@tonic-gate 	}
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
10737c478bd9Sstevel@tonic-gate 	return (dev_canceled);
10747c478bd9Sstevel@tonic-gate }
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate int
sbd_errno2ecode(int error)10777c478bd9Sstevel@tonic-gate sbd_errno2ecode(int error)
10787c478bd9Sstevel@tonic-gate {
10797c478bd9Sstevel@tonic-gate 	int	rv;
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	switch (error) {
10827c478bd9Sstevel@tonic-gate 	case EBUSY:
10837c478bd9Sstevel@tonic-gate 		rv = ESBD_BUSY;
10847c478bd9Sstevel@tonic-gate 		break;
10857c478bd9Sstevel@tonic-gate 	case EINVAL:
10867c478bd9Sstevel@tonic-gate 		rv = ESBD_INVAL;
10877c478bd9Sstevel@tonic-gate 		break;
10887c478bd9Sstevel@tonic-gate 	case EALREADY:
10897c478bd9Sstevel@tonic-gate 		rv = ESBD_ALREADY;
10907c478bd9Sstevel@tonic-gate 		break;
10917c478bd9Sstevel@tonic-gate 	case ENODEV:
10927c478bd9Sstevel@tonic-gate 		rv = ESBD_NODEV;
10937c478bd9Sstevel@tonic-gate 		break;
10947c478bd9Sstevel@tonic-gate 	case ENOMEM:
10957c478bd9Sstevel@tonic-gate 		rv = ESBD_NOMEM;
10967c478bd9Sstevel@tonic-gate 		break;
10977c478bd9Sstevel@tonic-gate 	default:
10987c478bd9Sstevel@tonic-gate 		rv = ESBD_INVAL;
10997c478bd9Sstevel@tonic-gate 	}
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 	return (rv);
11027c478bd9Sstevel@tonic-gate }
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate static void
sbd_attach_cpu(sbd_handle_t * hp,sbderror_t * ep,dev_info_t * dip,int unit)11057c478bd9Sstevel@tonic-gate sbd_attach_cpu(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit)
11067c478bd9Sstevel@tonic-gate {
11077c478bd9Sstevel@tonic-gate 	int rv = 0;
11087c478bd9Sstevel@tonic-gate 	processorid_t	cpuid;
11097c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
11107c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
11117c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_attach_cpu";
11127c478bd9Sstevel@tonic-gate 	char		*pathname;
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	ASSERT(dip);
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	/*
11197c478bd9Sstevel@tonic-gate 	 * With the introduction of CMP devices, the CPU nodes
11207c478bd9Sstevel@tonic-gate 	 * are no longer directly under the top node. Since
11217c478bd9Sstevel@tonic-gate 	 * there is no plan to support CPU attach in the near
11227c478bd9Sstevel@tonic-gate 	 * future, a branch configure operation is not required.
11237c478bd9Sstevel@tonic-gate 	 */
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
11267c478bd9Sstevel@tonic-gate 	cpuid = sbdp_get_cpuid(hdp, dip);
11277c478bd9Sstevel@tonic-gate 	if (cpuid < 0) {
11287c478bd9Sstevel@tonic-gate 		rv = -1;
11297c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
11307c478bd9Sstevel@tonic-gate 	} else if ((rv = cpu_configure(cpuid)) != 0) {
11317c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1132*d5ebc493SDan Cross 		    "sbd:%s: cpu_configure for cpuid %d failed", f, cpuid);
11337c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, sbd_errno2ecode(rv));
11347c478bd9Sstevel@tonic-gate 	}
11357c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	if (rv == 0) {
11387c478bd9Sstevel@tonic-gate 		ASSERT(sbp->sb_cpupath[unit] != NULL);
11397c478bd9Sstevel@tonic-gate 		pathname = sbp->sb_cpupath[unit];
11407c478bd9Sstevel@tonic-gate 		(void) ddi_pathname(dip, pathname);
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate }
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate /*
11457c478bd9Sstevel@tonic-gate  *	translate errno
11467c478bd9Sstevel@tonic-gate  */
11477c478bd9Sstevel@tonic-gate void
sbd_errno_decode(int err,sbderror_t * ep,dev_info_t * dip)11487c478bd9Sstevel@tonic-gate sbd_errno_decode(int err, sbderror_t *ep, dev_info_t *dip)
11497c478bd9Sstevel@tonic-gate {
11507c478bd9Sstevel@tonic-gate 	ASSERT(err != 0);
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	switch (err) {
11537c478bd9Sstevel@tonic-gate 	case ENOMEM:
11547c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_NOMEM);
11557c478bd9Sstevel@tonic-gate 		break;
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	case EBUSY:
11587c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_BUSY);
11597c478bd9Sstevel@tonic-gate 		break;
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	case EIO:
11627c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_IO);
11637c478bd9Sstevel@tonic-gate 		break;
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	case ENXIO:
11667c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_NODEV);
11677c478bd9Sstevel@tonic-gate 		break;
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	case EINVAL:
11707c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_INVAL);
11717c478bd9Sstevel@tonic-gate 		break;
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	case EFAULT:
11747c478bd9Sstevel@tonic-gate 	default:
11757c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_FAULT);
11767c478bd9Sstevel@tonic-gate 		break;
11777c478bd9Sstevel@tonic-gate 	}
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	(void) ddi_pathname(dip, SBD_GET_ERRSTR(ep));
11807c478bd9Sstevel@tonic-gate }
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate static void
sbd_detach_cpu(sbd_handle_t * hp,sbderror_t * ep,dev_info_t * dip,int unit)11837c478bd9Sstevel@tonic-gate sbd_detach_cpu(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit)
11847c478bd9Sstevel@tonic-gate {
11857c478bd9Sstevel@tonic-gate 	processorid_t	cpuid;
11867c478bd9Sstevel@tonic-gate 	int		rv;
11877c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
11887c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
11897c478bd9Sstevel@tonic-gate 	sbd_error_t	*spe;
11907c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_detach_cpu";
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 	ASSERT(dip);
11957c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
11967c478bd9Sstevel@tonic-gate 	spe = hdp->h_err;
11977c478bd9Sstevel@tonic-gate 	cpuid = sbdp_get_cpuid(hdp, dip);
11987c478bd9Sstevel@tonic-gate 	if (cpuid < 0) {
11997c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(spe, ep);
12007c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
12017c478bd9Sstevel@tonic-gate 		return;
12027c478bd9Sstevel@tonic-gate 	}
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	if ((rv = cpu_unconfigure(cpuid)) != 0) {
12057c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, sbd_errno2ecode(rv));
12067c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(ep, sbp->sb_cpupath[unit]);
12077c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1208*d5ebc493SDan Cross 		    "sbd:%s: cpu_unconfigure for cpu %d failed", f, cpuid);
12097c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
12107c478bd9Sstevel@tonic-gate 		return;
12117c478bd9Sstevel@tonic-gate 	}
12127c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	/*
12157c478bd9Sstevel@tonic-gate 	 * Since CPU nodes are no longer configured in CPU
12167c478bd9Sstevel@tonic-gate 	 * attach, the corresponding branch unconfigure
12177c478bd9Sstevel@tonic-gate 	 * operation that would be performed here is also
12187c478bd9Sstevel@tonic-gate 	 * no longer required.
12197c478bd9Sstevel@tonic-gate 	 */
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate int
sbd_detach_mem(sbd_handle_t * hp,sbderror_t * ep,int unit)12247c478bd9Sstevel@tonic-gate sbd_detach_mem(sbd_handle_t *hp, sbderror_t *ep, int unit)
12257c478bd9Sstevel@tonic-gate {
12267c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
12277c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
12287c478bd9Sstevel@tonic-gate 	int		i, rv;
12297c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_detach_mem";
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	if (sbd_detach_memory(hp, ep, mp, unit)) {
12347c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: detach fail", f);
12357c478bd9Sstevel@tonic-gate 		return (-1);
12367c478bd9Sstevel@tonic-gate 	}
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	/*
12397c478bd9Sstevel@tonic-gate 	 * Now detach mem devinfo nodes with status lock held.
12407c478bd9Sstevel@tonic-gate 	 */
12417c478bd9Sstevel@tonic-gate 	for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
12427c478bd9Sstevel@tonic-gate 		dev_info_t	*fdip = NULL;
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 		if (mp->sbm_dip[i] == NULL)
12457c478bd9Sstevel@tonic-gate 			continue;
12467c478bd9Sstevel@tonic-gate 		ASSERT(e_ddi_branch_held(mp->sbm_dip[i]));
12477c478bd9Sstevel@tonic-gate 		mutex_enter(&sbp->sb_slock);
12487c478bd9Sstevel@tonic-gate 		rv = e_ddi_branch_unconfigure(mp->sbm_dip[i], &fdip,
12497c478bd9Sstevel@tonic-gate 		    DEVI_BRANCH_EVENT);
12507c478bd9Sstevel@tonic-gate 		mutex_exit(&sbp->sb_slock);
12517c478bd9Sstevel@tonic-gate 		if (rv) {
12527c478bd9Sstevel@tonic-gate 			/*
12537c478bd9Sstevel@tonic-gate 			 * If non-NULL, fdip is returned held and must be
12547c478bd9Sstevel@tonic-gate 			 * released.
12557c478bd9Sstevel@tonic-gate 			 */
12567c478bd9Sstevel@tonic-gate 			if (fdip != NULL) {
12577c478bd9Sstevel@tonic-gate 				sbd_errno_decode(rv, ep, fdip);
12587c478bd9Sstevel@tonic-gate 				ddi_release_devi(fdip);
12597c478bd9Sstevel@tonic-gate 			} else {
12607c478bd9Sstevel@tonic-gate 				sbd_errno_decode(rv, ep, mp->sbm_dip[i]);
12617c478bd9Sstevel@tonic-gate 			}
12627c478bd9Sstevel@tonic-gate 		}
12637c478bd9Sstevel@tonic-gate 	}
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	return (0);
12667c478bd9Sstevel@tonic-gate }
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate /* start beginning of sbd.c */
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate /*
12717c478bd9Sstevel@tonic-gate  * MDR          memory support - somewhat disabled for now.
12727c478bd9Sstevel@tonic-gate  * UNSAFE       unsafe driver code - I don't think we want this.
12737c478bd9Sstevel@tonic-gate  *              need to check.
12747c478bd9Sstevel@tonic-gate  * DEVNODE      This driver creates attachment points for individual
12757c478bd9Sstevel@tonic-gate  *              components as well as boards.  We only need board
12767c478bd9Sstevel@tonic-gate  *              support.
12777c478bd9Sstevel@tonic-gate  * DEV2DEVSET   Put only present devices in devset.
12787c478bd9Sstevel@tonic-gate  */
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate static sbd_state_t
rstate_cvt(sbd_istate_t state)12827c478bd9Sstevel@tonic-gate rstate_cvt(sbd_istate_t state)
12837c478bd9Sstevel@tonic-gate {
12847c478bd9Sstevel@tonic-gate 	sbd_state_t cs;
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	switch (state) {
12877c478bd9Sstevel@tonic-gate 	case SBD_STATE_EMPTY:
12887c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_EMPTY;
12897c478bd9Sstevel@tonic-gate 		break;
12907c478bd9Sstevel@tonic-gate 	case SBD_STATE_OCCUPIED:
12917c478bd9Sstevel@tonic-gate 	case SBD_STATE_FATAL:
12927c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_DISCONNECTED;
12937c478bd9Sstevel@tonic-gate 		break;
12947c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONFIGURED:
12957c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONNECTED:
12967c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNCONFIGURED:
12977c478bd9Sstevel@tonic-gate 	case SBD_STATE_PARTIAL:
12987c478bd9Sstevel@tonic-gate 	case SBD_STATE_RELEASE:
12997c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNREFERENCED:
13007c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_CONNECTED;
13017c478bd9Sstevel@tonic-gate 		break;
13027c478bd9Sstevel@tonic-gate 	default:
13037c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_NONE;
13047c478bd9Sstevel@tonic-gate 		break;
13057c478bd9Sstevel@tonic-gate 	}
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	return (cs);
13087c478bd9Sstevel@tonic-gate }
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate sbd_state_t
ostate_cvt(sbd_istate_t state)13127c478bd9Sstevel@tonic-gate ostate_cvt(sbd_istate_t state)
13137c478bd9Sstevel@tonic-gate {
13147c478bd9Sstevel@tonic-gate 	sbd_state_t cs;
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	switch (state) {
13177c478bd9Sstevel@tonic-gate 	case SBD_STATE_EMPTY:
13187c478bd9Sstevel@tonic-gate 	case SBD_STATE_OCCUPIED:
13197c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNCONFIGURED:
13207c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONNECTED:
13217c478bd9Sstevel@tonic-gate 	case SBD_STATE_FATAL:
13227c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_UNCONFIGURED;
13237c478bd9Sstevel@tonic-gate 		break;
13247c478bd9Sstevel@tonic-gate 	case SBD_STATE_PARTIAL:
13257c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONFIGURED:
13267c478bd9Sstevel@tonic-gate 	case SBD_STATE_RELEASE:
13277c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNREFERENCED:
13287c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_CONFIGURED;
13297c478bd9Sstevel@tonic-gate 		break;
13307c478bd9Sstevel@tonic-gate 	default:
13317c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_NONE;
13327c478bd9Sstevel@tonic-gate 		break;
13337c478bd9Sstevel@tonic-gate 	}
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	return (cs);
13367c478bd9Sstevel@tonic-gate }
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate int
sbd_dealloc_instance(sbd_board_t * sbp,int max_boards)13397c478bd9Sstevel@tonic-gate sbd_dealloc_instance(sbd_board_t *sbp, int max_boards)
13407c478bd9Sstevel@tonic-gate {
13417c478bd9Sstevel@tonic-gate 	int		b;
13427c478bd9Sstevel@tonic-gate 	sbd_board_t    *list = sbp;
13437c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_dealloc_instance";
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	if (sbp == NULL) {
13487c478bd9Sstevel@tonic-gate 		return (-1);
13497c478bd9Sstevel@tonic-gate 	}
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 	for (b = 0; b < max_boards; b++) {
13527c478bd9Sstevel@tonic-gate 		sbd_board_destroy(sbp++);
13537c478bd9Sstevel@tonic-gate 	}
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	FREESTRUCT(list, sbd_board_t, max_boards);
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 	return (0);
13587c478bd9Sstevel@tonic-gate }
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate static sbd_devset_t
sbd_dev2devset(sbd_comp_id_t * cid)13617c478bd9Sstevel@tonic-gate sbd_dev2devset(sbd_comp_id_t *cid)
13627c478bd9Sstevel@tonic-gate {
13637c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_dev2devset";
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
13667c478bd9Sstevel@tonic-gate 	int		unit = cid->c_unit;
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	switch (cid->c_type) {
13697c478bd9Sstevel@tonic-gate 		case SBD_COMP_NONE:
13707c478bd9Sstevel@tonic-gate 			devset =  DEVSET(SBD_COMP_CPU, DEVSET_ANYUNIT);
13717c478bd9Sstevel@tonic-gate 			devset |= DEVSET(SBD_COMP_MEM, DEVSET_ANYUNIT);
13727c478bd9Sstevel@tonic-gate 			devset |= DEVSET(SBD_COMP_IO,  DEVSET_ANYUNIT);
13737c478bd9Sstevel@tonic-gate 			break;
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 		case SBD_COMP_CPU:
13767c478bd9Sstevel@tonic-gate 			if ((unit > MAX_CPU_UNITS_PER_BOARD) || (unit < 0)) {
1377*d5ebc493SDan Cross 				PR_ALL("%s: invalid cpu unit# = %d", f, unit);
13787c478bd9Sstevel@tonic-gate 				devset = 0;
13797c478bd9Sstevel@tonic-gate 			} else
13807c478bd9Sstevel@tonic-gate 				/*
13817c478bd9Sstevel@tonic-gate 				 * Generate a devset that includes all the
13827c478bd9Sstevel@tonic-gate 				 * cores of a CMP device. If this is not a
13837c478bd9Sstevel@tonic-gate 				 * CMP, the extra cores will be eliminated
13847c478bd9Sstevel@tonic-gate 				 * later since they are not present. This is
13857c478bd9Sstevel@tonic-gate 				 * also true for CMP devices that do not have
13867c478bd9Sstevel@tonic-gate 				 * all cores active.
13877c478bd9Sstevel@tonic-gate 				 */
13887c478bd9Sstevel@tonic-gate 				devset = DEVSET(SBD_COMP_CMP, unit);
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 			break;
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 		case SBD_COMP_MEM:
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 			if ((unit > MAX_MEM_UNITS_PER_BOARD) || (unit < 0)) {
13957c478bd9Sstevel@tonic-gate #ifdef XXX_jeffco
1396*d5ebc493SDan Cross 				PR_ALL("%s: invalid mem unit# = %d", f, unit);
13977c478bd9Sstevel@tonic-gate 				devset = 0;
13987c478bd9Sstevel@tonic-gate #endif
13997c478bd9Sstevel@tonic-gate 				devset = DEVSET(cid->c_type, 0);
14007c478bd9Sstevel@tonic-gate 				PR_ALL("%s: adjusted MEM devset = 0x%x\n",
1401*d5ebc493SDan Cross 				    f, devset);
14027c478bd9Sstevel@tonic-gate 			} else
14037c478bd9Sstevel@tonic-gate 				devset = DEVSET(cid->c_type, unit);
14047c478bd9Sstevel@tonic-gate 			break;
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 		case SBD_COMP_IO:
14077c478bd9Sstevel@tonic-gate 			if ((unit > MAX_IO_UNITS_PER_BOARD) || (unit < 0)) {
14087c478bd9Sstevel@tonic-gate 				PR_ALL("%s: invalid io unit# = %d",
1409*d5ebc493SDan Cross 				    f, unit);
14107c478bd9Sstevel@tonic-gate 				devset = 0;
14117c478bd9Sstevel@tonic-gate 			} else
14127c478bd9Sstevel@tonic-gate 				devset = DEVSET(cid->c_type, unit);
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 			break;
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 		default:
14177c478bd9Sstevel@tonic-gate 		case SBD_COMP_UNKNOWN:
14187c478bd9Sstevel@tonic-gate 			devset = 0;
14197c478bd9Sstevel@tonic-gate 			break;
14207c478bd9Sstevel@tonic-gate 	}
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	return (devset);
14237c478bd9Sstevel@tonic-gate }
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate /*
14267c478bd9Sstevel@tonic-gate  * Simple mutex for covering handle list ops as it is only
14277c478bd9Sstevel@tonic-gate  * used "infrequently". No need to add another mutex to the sbd_board_t.
14287c478bd9Sstevel@tonic-gate  */
14297c478bd9Sstevel@tonic-gate static kmutex_t sbd_handle_list_mutex;
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate static sbd_handle_t *
sbd_get_handle(dev_t dev,sbd_softstate_t * softsp,intptr_t arg,sbd_init_arg_t * iap)14327c478bd9Sstevel@tonic-gate sbd_get_handle(dev_t dev, sbd_softstate_t *softsp, intptr_t arg,
1433*d5ebc493SDan Cross     sbd_init_arg_t *iap)
14347c478bd9Sstevel@tonic-gate {
14357c478bd9Sstevel@tonic-gate 	sbd_handle_t		*hp;
14367c478bd9Sstevel@tonic-gate 	sbderror_t		*ep;
14377c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp;
14387c478bd9Sstevel@tonic-gate 	sbd_board_t		*sbp = softsp->sbd_boardlist;
14397c478bd9Sstevel@tonic-gate 	int			board;
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	board = SBDGETSLOT(dev);
14427c478bd9Sstevel@tonic-gate 	ASSERT(board < softsp->max_boards);
14437c478bd9Sstevel@tonic-gate 	sbp += board;
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	/*
14467c478bd9Sstevel@tonic-gate 	 * Brand-new handle.
14477c478bd9Sstevel@tonic-gate 	 */
14487c478bd9Sstevel@tonic-gate 	shp = kmem_zalloc(sizeof (sbd_priv_handle_t), KM_SLEEP);
14497c478bd9Sstevel@tonic-gate 	shp->sh_arg = (void *)arg;
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	hp = MACHHD2HD(shp);
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	ep = &shp->sh_err;
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 	hp->h_err = ep;
14567c478bd9Sstevel@tonic-gate 	hp->h_sbd = (void *) sbp;
14577c478bd9Sstevel@tonic-gate 	hp->h_dev = iap->dev;
14587c478bd9Sstevel@tonic-gate 	hp->h_cmd = iap->cmd;
14597c478bd9Sstevel@tonic-gate 	hp->h_mode = iap->mode;
14607c478bd9Sstevel@tonic-gate 	sbd_init_err(ep);
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 	mutex_enter(&sbd_handle_list_mutex);
14637c478bd9Sstevel@tonic-gate 	shp->sh_next = sbp->sb_handle;
14647c478bd9Sstevel@tonic-gate 	sbp->sb_handle = shp;
14657c478bd9Sstevel@tonic-gate 	mutex_exit(&sbd_handle_list_mutex);
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 	return (hp);
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate void
sbd_init_err(sbderror_t * ep)14717c478bd9Sstevel@tonic-gate sbd_init_err(sbderror_t *ep)
14727c478bd9Sstevel@tonic-gate {
14737c478bd9Sstevel@tonic-gate 	ep->e_errno = 0;
14747c478bd9Sstevel@tonic-gate 	ep->e_code = 0;
14757c478bd9Sstevel@tonic-gate 	ep->e_rsc[0] = '\0';
14767c478bd9Sstevel@tonic-gate }
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate int
sbd_set_err_in_hdl(sbd_handle_t * hp,sbderror_t * ep)14797c478bd9Sstevel@tonic-gate sbd_set_err_in_hdl(sbd_handle_t *hp, sbderror_t *ep)
14807c478bd9Sstevel@tonic-gate {
14817c478bd9Sstevel@tonic-gate 	sbderror_t	*hep = SBD_HD2ERR(hp);
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	/*
14847c478bd9Sstevel@tonic-gate 	 * If there is an error logged already, don't rewrite it
14857c478bd9Sstevel@tonic-gate 	 */
14867c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERR(hep) || SBD_GET_ERRNO(hep)) {
14877c478bd9Sstevel@tonic-gate 		return (0);
14887c478bd9Sstevel@tonic-gate 	}
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERR(ep) || SBD_GET_ERRNO(ep)) {
14917c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(hep, SBD_GET_ERR(ep));
14927c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(hep, SBD_GET_ERRNO(ep));
14937c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(hep, SBD_GET_ERRSTR(ep));
14947c478bd9Sstevel@tonic-gate 		return (0);
14957c478bd9Sstevel@tonic-gate 	}
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 	return (-1);
14987c478bd9Sstevel@tonic-gate }
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate static void
sbd_release_handle(sbd_handle_t * hp)15017c478bd9Sstevel@tonic-gate sbd_release_handle(sbd_handle_t *hp)
15027c478bd9Sstevel@tonic-gate {
15037c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp, **shpp;
15047c478bd9Sstevel@tonic-gate 	sbd_board_t		*sbp;
15057c478bd9Sstevel@tonic-gate 	static fn_t		f = "sbd_release_handle";
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	if (hp == NULL)
15087c478bd9Sstevel@tonic-gate 		return;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 	shp = HD2MACHHD(hp);
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 	mutex_enter(&sbd_handle_list_mutex);
15157c478bd9Sstevel@tonic-gate 	/*
15167c478bd9Sstevel@tonic-gate 	 * Locate the handle in the board's reference list.
15177c478bd9Sstevel@tonic-gate 	 */
15187c478bd9Sstevel@tonic-gate 	for (shpp = &sbp->sb_handle; (*shpp) && ((*shpp) != shp);
15197c478bd9Sstevel@tonic-gate 	    shpp = &((*shpp)->sh_next))
15207c478bd9Sstevel@tonic-gate 		/* empty */;
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 	if (*shpp == NULL) {
15237c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC,
1524*d5ebc493SDan Cross 		    "sbd:%s: handle not found in board %d", f, sbp->sb_num);
15257c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
15267c478bd9Sstevel@tonic-gate 	} else {
15277c478bd9Sstevel@tonic-gate 		*shpp = shp->sh_next;
15287c478bd9Sstevel@tonic-gate 	}
15297c478bd9Sstevel@tonic-gate 	mutex_exit(&sbd_handle_list_mutex);
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate 	if (hp->h_opts.copts != NULL) {
15327c478bd9Sstevel@tonic-gate 		FREESTRUCT(hp->h_opts.copts, char, hp->h_opts.size);
15337c478bd9Sstevel@tonic-gate 	}
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 	FREESTRUCT(shp, sbd_priv_handle_t, 1);
15367c478bd9Sstevel@tonic-gate }
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate sbdp_handle_t *
sbd_get_sbdp_handle(sbd_board_t * sbp,sbd_handle_t * hp)15397c478bd9Sstevel@tonic-gate sbd_get_sbdp_handle(sbd_board_t *sbp, sbd_handle_t *hp)
15407c478bd9Sstevel@tonic-gate {
15417c478bd9Sstevel@tonic-gate 	sbdp_handle_t		*hdp;
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 	hdp = kmem_zalloc(sizeof (sbdp_handle_t), KM_SLEEP);
15447c478bd9Sstevel@tonic-gate 	hdp->h_err = kmem_zalloc(sizeof (sbd_error_t), KM_SLEEP);
15457c478bd9Sstevel@tonic-gate 	if (sbp == NULL) {
15467c478bd9Sstevel@tonic-gate 		hdp->h_board = -1;
15477c478bd9Sstevel@tonic-gate 		hdp->h_wnode = -1;
15487c478bd9Sstevel@tonic-gate 	} else {
15497c478bd9Sstevel@tonic-gate 		hdp->h_board = sbp->sb_num;
15507c478bd9Sstevel@tonic-gate 		hdp->h_wnode = sbp->sb_wnode;
15517c478bd9Sstevel@tonic-gate 	}
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 	if (hp == NULL) {
15547c478bd9Sstevel@tonic-gate 		hdp->h_flags = 0;
15557c478bd9Sstevel@tonic-gate 		hdp->h_opts = NULL;
15567c478bd9Sstevel@tonic-gate 	} else {
15577c478bd9Sstevel@tonic-gate 		hdp->h_flags = SBD_2_SBDP_FLAGS(hp->h_flags);
15587c478bd9Sstevel@tonic-gate 		hdp->h_opts = &hp->h_opts;
15597c478bd9Sstevel@tonic-gate 	}
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 	return (hdp);
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate void
sbd_release_sbdp_handle(sbdp_handle_t * hdp)15657c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(sbdp_handle_t *hdp)
15667c478bd9Sstevel@tonic-gate {
15677c478bd9Sstevel@tonic-gate 	if (hdp == NULL)
15687c478bd9Sstevel@tonic-gate 		return;
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	kmem_free(hdp->h_err, sizeof (sbd_error_t));
15717c478bd9Sstevel@tonic-gate 	kmem_free(hdp, sizeof (sbdp_handle_t));
15727c478bd9Sstevel@tonic-gate }
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate void
sbd_reset_error_sbdph(sbdp_handle_t * hdp)15757c478bd9Sstevel@tonic-gate sbd_reset_error_sbdph(sbdp_handle_t *hdp)
15767c478bd9Sstevel@tonic-gate {
15777c478bd9Sstevel@tonic-gate 	if ((hdp != NULL) && (hdp->h_err != NULL)) {
15787c478bd9Sstevel@tonic-gate 		bzero(hdp->h_err, sizeof (sbd_error_t));
15797c478bd9Sstevel@tonic-gate 	}
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate static int
sbd_copyin_ioarg(sbd_handle_t * hp,int mode,int cmd,sbd_cmd_t * cmdp,sbd_ioctl_arg_t * iap)15837c478bd9Sstevel@tonic-gate sbd_copyin_ioarg(sbd_handle_t *hp, int mode, int cmd, sbd_cmd_t *cmdp,
1584*d5ebc493SDan Cross     sbd_ioctl_arg_t *iap)
15857c478bd9Sstevel@tonic-gate {
15867c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_copyin_ioarg";
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 	if (iap == NULL)
15897c478bd9Sstevel@tonic-gate 		return (EINVAL);
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cmdp, sizeof (sbd_cmd_t));
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
15947c478bd9Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
15957c478bd9Sstevel@tonic-gate 		sbd_cmd32_t	scmd32;
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 		bzero((caddr_t)&scmd32, sizeof (sbd_cmd32_t));
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)iap, (void *)&scmd32,
1600*d5ebc493SDan Cross 		    sizeof (sbd_cmd32_t), mode)) {
16017c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1602*d5ebc493SDan Cross 			    "sbd:%s: (32bit) failed to copyin sbdcmd-struct",
1603*d5ebc493SDan Cross 			    f);
16047c478bd9Sstevel@tonic-gate 			return (EFAULT);
16057c478bd9Sstevel@tonic-gate 		}
16067c478bd9Sstevel@tonic-gate 		cmdp->cmd_cm.c_id.c_type = scmd32.cmd_cm.c_id.c_type;
16077c478bd9Sstevel@tonic-gate 		cmdp->cmd_cm.c_id.c_unit = scmd32.cmd_cm.c_id.c_unit;
16087c478bd9Sstevel@tonic-gate 		bcopy(&scmd32.cmd_cm.c_id.c_name[0],
1609*d5ebc493SDan Cross 		    &cmdp->cmd_cm.c_id.c_name[0], OBP_MAXPROPNAME);
16107c478bd9Sstevel@tonic-gate 		cmdp->cmd_cm.c_flags = scmd32.cmd_cm.c_flags;
16117c478bd9Sstevel@tonic-gate 		cmdp->cmd_cm.c_len = scmd32.cmd_cm.c_len;
161204580fdfSmathue 		cmdp->cmd_cm.c_opts = (caddr_t)(uintptr_t)scmd32.cmd_cm.c_opts;
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 		if (cmd == SBD_CMD_PASSTHRU) {
1615903a11ebSrh 			PR_BYP("passthru copyin: iap=%p, sz=%ld", (void *)iap,
1616*d5ebc493SDan Cross 			    sizeof (sbd_cmd32_t));
161704580fdfSmathue 			PR_BYP("passthru copyin: c_opts=%x, c_len=%d",
1618*d5ebc493SDan Cross 			    scmd32.cmd_cm.c_opts, scmd32.cmd_cm.c_len);
16197c478bd9Sstevel@tonic-gate 		}
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 		switch (cmd) {
16227c478bd9Sstevel@tonic-gate 		case SBD_CMD_STATUS:
16237c478bd9Sstevel@tonic-gate 			cmdp->cmd_stat.s_nbytes = scmd32.cmd_stat.s_nbytes;
16247c478bd9Sstevel@tonic-gate 			cmdp->cmd_stat.s_statp =
1625*d5ebc493SDan Cross 			    (caddr_t)(uintptr_t)scmd32.cmd_stat.s_statp;
16267c478bd9Sstevel@tonic-gate 			break;
16277c478bd9Sstevel@tonic-gate 		default:
16287c478bd9Sstevel@tonic-gate 			break;
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 		}
16317c478bd9Sstevel@tonic-gate 	} else
16327c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
16337c478bd9Sstevel@tonic-gate 	if (ddi_copyin((void *)iap, (void *)cmdp,
1634*d5ebc493SDan Cross 	    sizeof (sbd_cmd_t), mode) != 0) {
1635*d5ebc493SDan Cross 		cmn_err(CE_WARN, "sbd:%s: failed to copyin sbd cmd_t struct",
1636*d5ebc493SDan Cross 		    f);
16377c478bd9Sstevel@tonic-gate 		return (EFAULT);
16387c478bd9Sstevel@tonic-gate 	}
16397c478bd9Sstevel@tonic-gate 	/*
16407c478bd9Sstevel@tonic-gate 	 * A user may set platform specific options so we need to
16417c478bd9Sstevel@tonic-gate 	 * copy them in
16427c478bd9Sstevel@tonic-gate 	 */
1643*d5ebc493SDan Cross 	if (cmd != SBD_CMD_STATUS &&
1644*d5ebc493SDan Cross 	    (hp->h_opts.size = cmdp->cmd_cm.c_len) > 0) {
16457c478bd9Sstevel@tonic-gate 		hp->h_opts.size += 1;	/* For null termination of string. */
16467c478bd9Sstevel@tonic-gate 		hp->h_opts.copts = GETSTRUCT(char, hp->h_opts.size);
16477c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)cmdp->cmd_cm.c_opts,
16487c478bd9Sstevel@tonic-gate 		    (void *)hp->h_opts.copts,
16497c478bd9Sstevel@tonic-gate 		    cmdp->cmd_cm.c_len, hp->h_mode) != 0) {
16507c478bd9Sstevel@tonic-gate 			/* copts is freed in sbd_release_handle(). */
1651*d5ebc493SDan Cross 			cmn_err(CE_WARN, "sbd:%s: failed to copyin options", f);
16527c478bd9Sstevel@tonic-gate 			return (EFAULT);
16537c478bd9Sstevel@tonic-gate 		}
16547c478bd9Sstevel@tonic-gate 	}
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	return (0);
16577c478bd9Sstevel@tonic-gate }
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate static int
sbd_copyout_ioarg(int mode,int cmd,sbd_cmd_t * scp,sbd_ioctl_arg_t * iap)16607c478bd9Sstevel@tonic-gate sbd_copyout_ioarg(int mode, int cmd, sbd_cmd_t *scp, sbd_ioctl_arg_t *iap)
16617c478bd9Sstevel@tonic-gate {
16627c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_copyout_ioarg";
16637c478bd9Sstevel@tonic-gate 
16647c478bd9Sstevel@tonic-gate 	if ((iap == NULL) || (scp == NULL))
16657c478bd9Sstevel@tonic-gate 		return (EINVAL);
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
16687c478bd9Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
16697c478bd9Sstevel@tonic-gate 		sbd_cmd32_t	scmd32;
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 		scmd32.cmd_cm.c_id.c_type = scp->cmd_cm.c_id.c_type;
16727c478bd9Sstevel@tonic-gate 		scmd32.cmd_cm.c_id.c_unit = scp->cmd_cm.c_id.c_unit;
16737c478bd9Sstevel@tonic-gate 		bcopy(scp->cmd_cm.c_id.c_name,
1674*d5ebc493SDan Cross 		    scmd32.cmd_cm.c_id.c_name, OBP_MAXPROPNAME);
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 		scmd32.cmd_cm.c_flags = scp->cmd_cm.c_flags;
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 		switch (cmd) {
16797c478bd9Sstevel@tonic-gate 		case SBD_CMD_GETNCM:
16807c478bd9Sstevel@tonic-gate 			scmd32.cmd_getncm.g_ncm = scp->cmd_getncm.g_ncm;
16817c478bd9Sstevel@tonic-gate 			break;
16827c478bd9Sstevel@tonic-gate 		default:
16837c478bd9Sstevel@tonic-gate 			break;
16847c478bd9Sstevel@tonic-gate 		}
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 		if (ddi_copyout((void *)&scmd32, (void *)iap,
1687*d5ebc493SDan Cross 		    sizeof (sbd_cmd32_t), mode)) {
16887c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1689*d5ebc493SDan Cross 			    "sbd:%s: (32bit) failed to copyout sbdcmd struct",
1690*d5ebc493SDan Cross 			    f);
16917c478bd9Sstevel@tonic-gate 			return (EFAULT);
16927c478bd9Sstevel@tonic-gate 		}
16937c478bd9Sstevel@tonic-gate 	} else
16947c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
16957c478bd9Sstevel@tonic-gate 	if (ddi_copyout((void *)scp, (void *)iap,
1696*d5ebc493SDan Cross 	    sizeof (sbd_cmd_t), mode) != 0) {
1697*d5ebc493SDan Cross 		cmn_err(CE_WARN, "sbd:%s: failed to copyout sbdcmd struct", f);
16987c478bd9Sstevel@tonic-gate 		return (EFAULT);
16997c478bd9Sstevel@tonic-gate 	}
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	return (0);
17027c478bd9Sstevel@tonic-gate }
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate static int
sbd_copyout_errs(int mode,sbd_ioctl_arg_t * iap,void * arg)17057c478bd9Sstevel@tonic-gate sbd_copyout_errs(int mode, sbd_ioctl_arg_t *iap, void *arg)
17067c478bd9Sstevel@tonic-gate {
17077c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_copyout_errs";
17087c478bd9Sstevel@tonic-gate 	sbd_ioctl_arg_t	*uap;
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 	uap = (sbd_ioctl_arg_t *)arg;
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
17137c478bd9Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
17147c478bd9Sstevel@tonic-gate 		sbd_error32_t err32;
17157c478bd9Sstevel@tonic-gate 		sbd_ioctl_arg32_t *uap32;
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate 		uap32 = (sbd_ioctl_arg32_t *)arg;
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 		err32.e_code = iap->ie_code;
17207c478bd9Sstevel@tonic-gate 		(void) strcpy(err32.e_rsc, iap->ie_rsc);
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate 		if (ddi_copyout((void *)&err32, (void *)&uap32->i_err,
1723*d5ebc493SDan Cross 		    sizeof (sbd_error32_t), mode)) {
17247c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1725*d5ebc493SDan Cross 			    "sbd:%s: failed to copyout ioctl32 errs", f);
17267c478bd9Sstevel@tonic-gate 			return (EFAULT);
17277c478bd9Sstevel@tonic-gate 		}
17287c478bd9Sstevel@tonic-gate 	} else
17297c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
17307c478bd9Sstevel@tonic-gate 	if (ddi_copyout((void *)&iap->i_err, (void *)&uap->i_err,
1731*d5ebc493SDan Cross 	    sizeof (sbd_error_t), mode) != 0) {
1732*d5ebc493SDan Cross 		cmn_err(CE_WARN, "sbd:%s: failed to copyout ioctl errs", f);
17337c478bd9Sstevel@tonic-gate 		return (EFAULT);
17347c478bd9Sstevel@tonic-gate 	}
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 	return (0);
17377c478bd9Sstevel@tonic-gate }
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate /*
17407c478bd9Sstevel@tonic-gate  * State transition policy is that if at least one
17417c478bd9Sstevel@tonic-gate  * device cannot make the transition, then none of
17427c478bd9Sstevel@tonic-gate  * the requested devices are allowed to transition.
17437c478bd9Sstevel@tonic-gate  *
17447c478bd9Sstevel@tonic-gate  * Returns the state that is in error, if any.
17457c478bd9Sstevel@tonic-gate  */
17467c478bd9Sstevel@tonic-gate static int
sbd_check_transition(sbd_board_t * sbp,sbd_devset_t * devsetp,struct sbd_state_trans * transp)17477c478bd9Sstevel@tonic-gate sbd_check_transition(sbd_board_t *sbp, sbd_devset_t *devsetp,
1748*d5ebc493SDan Cross     struct sbd_state_trans *transp)
17497c478bd9Sstevel@tonic-gate {
17507c478bd9Sstevel@tonic-gate 	int	s, ut;
17517c478bd9Sstevel@tonic-gate 	int	state_err = 0;
17527c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
17537c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_check_transition";
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	devset = *devsetp;
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	if (!devset) {
17587c478bd9Sstevel@tonic-gate 		/*
17597c478bd9Sstevel@tonic-gate 		 * Transition does not deal with any components.
17607c478bd9Sstevel@tonic-gate 		 * This is the case for addboard/deleteboard.
17617c478bd9Sstevel@tonic-gate 		 */
17627c478bd9Sstevel@tonic-gate 		PR_ALL("%s: no devs: requested devset = 0x%x,"
1763*d5ebc493SDan Cross 		    " final devset = 0x%x\n",
1764*d5ebc493SDan Cross 		    f, (uint_t)*devsetp, (uint_t)devset);
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 		return (0);
17677c478bd9Sstevel@tonic-gate 	}
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) {
17707c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) {
17717c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_MEM, ut) == 0)
17727c478bd9Sstevel@tonic-gate 				continue;
17737c478bd9Sstevel@tonic-gate 			s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_MEM, ut);
17747c478bd9Sstevel@tonic-gate 			if (transp->x_op[s].x_rv) {
17757c478bd9Sstevel@tonic-gate 				if (!state_err)
17767c478bd9Sstevel@tonic-gate 					state_err = s;
17777c478bd9Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_MEM, ut);
17787c478bd9Sstevel@tonic-gate 			}
17797c478bd9Sstevel@tonic-gate 		}
17807c478bd9Sstevel@tonic-gate 	}
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) {
17837c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) {
17847c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_CPU, ut) == 0)
17857c478bd9Sstevel@tonic-gate 				continue;
17867c478bd9Sstevel@tonic-gate 			s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_CPU, ut);
17877c478bd9Sstevel@tonic-gate 			if (transp->x_op[s].x_rv) {
17887c478bd9Sstevel@tonic-gate 				if (!state_err)
17897c478bd9Sstevel@tonic-gate 					state_err = s;
17907c478bd9Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_CPU, ut);
17917c478bd9Sstevel@tonic-gate 			}
17927c478bd9Sstevel@tonic-gate 		}
17937c478bd9Sstevel@tonic-gate 	}
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) {
17967c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) {
17977c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_IO, ut) == 0)
17987c478bd9Sstevel@tonic-gate 				continue;
17997c478bd9Sstevel@tonic-gate 			s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_IO, ut);
18007c478bd9Sstevel@tonic-gate 			if (transp->x_op[s].x_rv) {
18017c478bd9Sstevel@tonic-gate 				if (!state_err)
18027c478bd9Sstevel@tonic-gate 					state_err = s;
18037c478bd9Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_IO, ut);
18047c478bd9Sstevel@tonic-gate 			}
18057c478bd9Sstevel@tonic-gate 		}
18067c478bd9Sstevel@tonic-gate 	}
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	PR_ALL("%s: requested devset = 0x%x, final devset = 0x%x\n",
1809*d5ebc493SDan Cross 	    f, (uint_t)*devsetp, (uint_t)devset);
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 	*devsetp = devset;
18127c478bd9Sstevel@tonic-gate 	/*
18137c478bd9Sstevel@tonic-gate 	 * If there are some remaining components for which
18147c478bd9Sstevel@tonic-gate 	 * this state transition is valid, then allow them
18157c478bd9Sstevel@tonic-gate 	 * through, otherwise if none are left then return
18167c478bd9Sstevel@tonic-gate 	 * the state error.
18177c478bd9Sstevel@tonic-gate 	 */
18187c478bd9Sstevel@tonic-gate 	return (devset ? 0 : state_err);
18197c478bd9Sstevel@tonic-gate }
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate /*
18227c478bd9Sstevel@tonic-gate  * pre-op entry point must SET_ERRNO(), if needed.
18237c478bd9Sstevel@tonic-gate  * Return value of non-zero indicates failure.
18247c478bd9Sstevel@tonic-gate  */
18257c478bd9Sstevel@tonic-gate static int
sbd_pre_op(sbd_handle_t * hp)18267c478bd9Sstevel@tonic-gate sbd_pre_op(sbd_handle_t *hp)
18277c478bd9Sstevel@tonic-gate {
18287c478bd9Sstevel@tonic-gate 	int		rv = 0, t;
18297c478bd9Sstevel@tonic-gate 	int		cmd, serr = 0;
18307c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
18317c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
18327c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp = HD2MACHHD(hp);
18337c478bd9Sstevel@tonic-gate 	sbderror_t	*ep = SBD_HD2ERR(hp);
18347c478bd9Sstevel@tonic-gate 	sbd_cmd_t	*cmdp;
18357c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_pre_op";
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	cmd = hp->h_cmd;
18387c478bd9Sstevel@tonic-gate 	devset = shp->sh_devset;
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate 	switch (cmd) {
18417c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONNECT:
18427c478bd9Sstevel@tonic-gate 		case SBD_CMD_DISCONNECT:
18437c478bd9Sstevel@tonic-gate 		case SBD_CMD_UNCONFIGURE:
18447c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONFIGURE:
18457c478bd9Sstevel@tonic-gate 		case SBD_CMD_ASSIGN:
18467c478bd9Sstevel@tonic-gate 		case SBD_CMD_UNASSIGN:
18477c478bd9Sstevel@tonic-gate 		case SBD_CMD_POWERON:
18487c478bd9Sstevel@tonic-gate 		case SBD_CMD_POWEROFF:
18497c478bd9Sstevel@tonic-gate 		case SBD_CMD_TEST:
18507c478bd9Sstevel@tonic-gate 		/* ioctls allowed if caller has write permission */
18517c478bd9Sstevel@tonic-gate 		if (!(hp->h_mode & FWRITE)) {
18527c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, EPERM);
18537c478bd9Sstevel@tonic-gate 			return (-1);
18547c478bd9Sstevel@tonic-gate 		}
18557c478bd9Sstevel@tonic-gate 
18567c478bd9Sstevel@tonic-gate 		default:
18577c478bd9Sstevel@tonic-gate 		break;
18587c478bd9Sstevel@tonic-gate 	}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	hp->h_iap = GETSTRUCT(sbd_ioctl_arg_t, 1);
18617c478bd9Sstevel@tonic-gate 	rv = sbd_copyin_ioarg(hp, hp->h_mode, cmd,
1862*d5ebc493SDan Cross 	    (sbd_cmd_t *)hp->h_iap, shp->sh_arg);
18637c478bd9Sstevel@tonic-gate 	if (rv) {
18647c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(ep, rv);
18657c478bd9Sstevel@tonic-gate 		FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1);
18667c478bd9Sstevel@tonic-gate 		hp->h_iap = NULL;
18677c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: copyin fail", f);
18687c478bd9Sstevel@tonic-gate 		return (-1);
18697c478bd9Sstevel@tonic-gate 	} else {
18707c478bd9Sstevel@tonic-gate 		cmdp =  (sbd_cmd_t *)hp->h_iap;
18717c478bd9Sstevel@tonic-gate 		if (cmdp->cmd_cm.c_id.c_name[0] != '\0') {
18727c478bd9Sstevel@tonic-gate 
1873*d5ebc493SDan Cross 			cmdp->cmd_cm.c_id.c_type =
1874*d5ebc493SDan Cross 			    SBD_COMP(sbd_name_to_idx(cmdp->cmd_cm.c_id.c_name));
18757c478bd9Sstevel@tonic-gate 			if (cmdp->cmd_cm.c_id.c_type == SBD_COMP_MEM) {
18767c478bd9Sstevel@tonic-gate 				if (cmdp->cmd_cm.c_id.c_unit == -1)
18777c478bd9Sstevel@tonic-gate 					cmdp->cmd_cm.c_id.c_unit = 0;
18787c478bd9Sstevel@tonic-gate 			}
18797c478bd9Sstevel@tonic-gate 		}
18807c478bd9Sstevel@tonic-gate 		devset = shp->sh_orig_devset = shp->sh_devset =
18817c478bd9Sstevel@tonic-gate 		    sbd_dev2devset(&cmdp->cmd_cm.c_id);
18827c478bd9Sstevel@tonic-gate 		if (devset == 0) {
18837c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, EINVAL);
18847c478bd9Sstevel@tonic-gate 			FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1);
18857c478bd9Sstevel@tonic-gate 			hp->h_iap = NULL;
18867c478bd9Sstevel@tonic-gate 			return (-1);
18877c478bd9Sstevel@tonic-gate 		}
18887c478bd9Sstevel@tonic-gate 	}
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate 	/*
18917c478bd9Sstevel@tonic-gate 	 * Always turn on these bits ala Sunfire DR.
18927c478bd9Sstevel@tonic-gate 	 */
18937c478bd9Sstevel@tonic-gate 	hp->h_flags |= SBD_FLAG_DEVI_FORCE;
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	if (cmdp->cmd_cm.c_flags & SBD_FLAG_FORCE)
18967c478bd9Sstevel@tonic-gate 		hp->h_flags |= SBD_IOCTL_FLAG_FORCE;
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	/*
18997c478bd9Sstevel@tonic-gate 	 * Check for valid state transitions.
19007c478bd9Sstevel@tonic-gate 	 */
19017c478bd9Sstevel@tonic-gate 	if (!serr && ((t = CMD2INDEX(cmd)) != -1)) {
19027c478bd9Sstevel@tonic-gate 		struct sbd_state_trans	*transp;
19037c478bd9Sstevel@tonic-gate 		int			state_err;
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 		transp = &sbd_state_transition[t];
19067c478bd9Sstevel@tonic-gate 		ASSERT(transp->x_cmd == cmd);
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 		state_err = sbd_check_transition(sbp, &devset, transp);
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 		if (state_err < 0) {
19117c478bd9Sstevel@tonic-gate 			/*
19127c478bd9Sstevel@tonic-gate 			 * Invalidate device.
19137c478bd9Sstevel@tonic-gate 			 */
19147c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, ENOTTY);
19157c478bd9Sstevel@tonic-gate 			serr = -1;
19167c478bd9Sstevel@tonic-gate 			PR_ALL("%s: invalid devset (0x%x)\n",
1917*d5ebc493SDan Cross 			    f, (uint_t)devset);
19187c478bd9Sstevel@tonic-gate 		} else if (state_err != 0) {
19197c478bd9Sstevel@tonic-gate 			/*
19207c478bd9Sstevel@tonic-gate 			 * State transition is not a valid one.
19217c478bd9Sstevel@tonic-gate 			 */
19227c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, transp->x_op[state_err].x_err);
19237c478bd9Sstevel@tonic-gate 			serr = transp->x_op[state_err].x_rv;
19247c478bd9Sstevel@tonic-gate 			PR_ALL("%s: invalid state %s(%d) for cmd %s(%d)\n",
1925*d5ebc493SDan Cross 			    f, sbd_state_str[state_err], state_err,
1926*d5ebc493SDan Cross 			    SBD_CMD_STR(cmd), cmd);
19277c478bd9Sstevel@tonic-gate 		}
19287c478bd9Sstevel@tonic-gate 		if (serr && SBD_GET_ERRNO(ep) != 0) {
19297c478bd9Sstevel@tonic-gate 			/*
19307c478bd9Sstevel@tonic-gate 			 * A state transition error occurred.
19317c478bd9Sstevel@tonic-gate 			 */
19327c478bd9Sstevel@tonic-gate 			if (serr < 0) {
19337c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(ep, ESBD_INVAL);
19347c478bd9Sstevel@tonic-gate 			} else {
19357c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(ep, ESBD_STATE);
19367c478bd9Sstevel@tonic-gate 			}
19377c478bd9Sstevel@tonic-gate 			PR_ALL("%s: invalid state transition\n", f);
19387c478bd9Sstevel@tonic-gate 		} else {
19397c478bd9Sstevel@tonic-gate 			shp->sh_devset = devset;
19407c478bd9Sstevel@tonic-gate 		}
19417c478bd9Sstevel@tonic-gate 	}
19427c478bd9Sstevel@tonic-gate 
19437c478bd9Sstevel@tonic-gate 	if (serr && !rv && hp->h_iap) {
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 		/*
19467c478bd9Sstevel@tonic-gate 		 * There was a state error.  We successfully copied
19477c478bd9Sstevel@tonic-gate 		 * in the ioctl argument, so let's fill in the
19487c478bd9Sstevel@tonic-gate 		 * error and copy it back out.
19497c478bd9Sstevel@tonic-gate 		 */
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 		if (SBD_GET_ERR(ep) && SBD_GET_ERRNO(ep) == 0)
19527c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, EIO);
19537c478bd9Sstevel@tonic-gate 
1954*d5ebc493SDan Cross 		SBD_SET_IOCTL_ERR(&hp->h_iap->i_err, ep->e_code, ep->e_rsc);
19557c478bd9Sstevel@tonic-gate 		(void) sbd_copyout_errs(hp->h_mode, hp->h_iap, shp->sh_arg);
19567c478bd9Sstevel@tonic-gate 		FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1);
19577c478bd9Sstevel@tonic-gate 		hp->h_iap = NULL;
19587c478bd9Sstevel@tonic-gate 		rv = -1;
19597c478bd9Sstevel@tonic-gate 	}
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 	return (rv);
19627c478bd9Sstevel@tonic-gate }
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate static void
sbd_post_op(sbd_handle_t * hp)19657c478bd9Sstevel@tonic-gate sbd_post_op(sbd_handle_t *hp)
19667c478bd9Sstevel@tonic-gate {
1967*d5ebc493SDan Cross 	int			cmd;
1968*d5ebc493SDan Cross 	sbderror_t		*ep = SBD_HD2ERR(hp);
19697c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp = HD2MACHHD(hp);
1970*d5ebc493SDan Cross 	sbd_board_t		*sbp = SBDH2BD(hp->h_sbd);
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 	cmd = hp->h_cmd;
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 	switch (cmd) {
19757c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONFIGURE:
19767c478bd9Sstevel@tonic-gate 		case SBD_CMD_UNCONFIGURE:
19777c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONNECT:
19787c478bd9Sstevel@tonic-gate 		case SBD_CMD_DISCONNECT:
19797c478bd9Sstevel@tonic-gate 			sbp->sb_time = gethrestime_sec();
19807c478bd9Sstevel@tonic-gate 			break;
19817c478bd9Sstevel@tonic-gate 
19827c478bd9Sstevel@tonic-gate 		default:
19837c478bd9Sstevel@tonic-gate 			break;
19847c478bd9Sstevel@tonic-gate 	}
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERR(ep) && SBD_GET_ERRNO(ep) == 0) {
19877c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(ep, EIO);
19887c478bd9Sstevel@tonic-gate 	}
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate 	if (shp->sh_arg != NULL) {
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 		if (SBD_GET_ERR(ep) != ESBD_NOERROR) {
19937c478bd9Sstevel@tonic-gate 
1994*d5ebc493SDan Cross 			SBD_SET_IOCTL_ERR(&hp->h_iap->i_err, ep->e_code,
1995*d5ebc493SDan Cross 			    ep->e_rsc);
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 			(void) sbd_copyout_errs(hp->h_mode, hp->h_iap,
1998*d5ebc493SDan Cross 			    shp->sh_arg);
19997c478bd9Sstevel@tonic-gate 		}
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 		if (hp->h_iap != NULL) {
20027c478bd9Sstevel@tonic-gate 			FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1);
20037c478bd9Sstevel@tonic-gate 			hp->h_iap = NULL;
20047c478bd9Sstevel@tonic-gate 		}
20057c478bd9Sstevel@tonic-gate 	}
20067c478bd9Sstevel@tonic-gate }
20077c478bd9Sstevel@tonic-gate 
20087c478bd9Sstevel@tonic-gate static int
sbd_probe_board(sbd_handle_t * hp)20097c478bd9Sstevel@tonic-gate sbd_probe_board(sbd_handle_t *hp)
20107c478bd9Sstevel@tonic-gate {
20117c478bd9Sstevel@tonic-gate 	int		rv;
20127c478bd9Sstevel@tonic-gate 	sbd_board_t    *sbp;
20137c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
20147c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_probe_board";
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate 	ASSERT(sbp != NULL);
20197c478bd9Sstevel@tonic-gate 	PR_ALL("%s for board %d", f, sbp->sb_num);
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 	if ((rv = sbdp_connect_board(hdp)) != 0) {
20257c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
20287c478bd9Sstevel@tonic-gate 	}
20297c478bd9Sstevel@tonic-gate 
20307c478bd9Sstevel@tonic-gate 	/*
20317c478bd9Sstevel@tonic-gate 	 * We need to force a recache after the connect.  The cached
20327c478bd9Sstevel@tonic-gate 	 * info may be incorrect
20337c478bd9Sstevel@tonic-gate 	 */
20347c478bd9Sstevel@tonic-gate 	mutex_enter(&sbp->sb_flags_mutex);
20357c478bd9Sstevel@tonic-gate 	sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED;
20367c478bd9Sstevel@tonic-gate 	mutex_exit(&sbp->sb_flags_mutex);
20377c478bd9Sstevel@tonic-gate 
20387c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_PROBE_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2039*d5ebc493SDan Cross 	    ESGT_PROBE, NULL);
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
20427c478bd9Sstevel@tonic-gate 
20437c478bd9Sstevel@tonic-gate 	return (rv);
20447c478bd9Sstevel@tonic-gate }
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate static int
sbd_deprobe_board(sbd_handle_t * hp)20477c478bd9Sstevel@tonic-gate sbd_deprobe_board(sbd_handle_t *hp)
20487c478bd9Sstevel@tonic-gate {
20497c478bd9Sstevel@tonic-gate 	int		rv;
20507c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
20517c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
20527c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_deprobe_board";
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 	if ((rv = sbdp_disconnect_board(hdp)) != 0) {
20617c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
20647c478bd9Sstevel@tonic-gate 	}
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate 	mutex_enter(&sbp->sb_flags_mutex);
20677c478bd9Sstevel@tonic-gate 	sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED;
20687c478bd9Sstevel@tonic-gate 	mutex_exit(&sbp->sb_flags_mutex);
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_DEPROBE_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2071*d5ebc493SDan Cross 	    ESGT_DEPROBE, NULL);
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
20747c478bd9Sstevel@tonic-gate 	return (rv);
20757c478bd9Sstevel@tonic-gate }
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate /*
20787c478bd9Sstevel@tonic-gate  * Check if a CPU node is part of a CMP.
20797c478bd9Sstevel@tonic-gate  */
20807c478bd9Sstevel@tonic-gate int
sbd_is_cmp_child(dev_info_t * dip)20817c478bd9Sstevel@tonic-gate sbd_is_cmp_child(dev_info_t *dip)
20827c478bd9Sstevel@tonic-gate {
20837c478bd9Sstevel@tonic-gate 	dev_info_t *pdip;
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate 	if (strcmp(ddi_node_name(dip), "cpu") != 0) {
20867c478bd9Sstevel@tonic-gate 		return (0);
20877c478bd9Sstevel@tonic-gate 	}
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(dip);
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate 	ASSERT(pdip);
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 	if (strcmp(ddi_node_name(pdip), "cmp") == 0) {
20947c478bd9Sstevel@tonic-gate 		return (1);
20957c478bd9Sstevel@tonic-gate 	}
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate 	return (0);
20987c478bd9Sstevel@tonic-gate }
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate /*
21017c478bd9Sstevel@tonic-gate  * Returns the nodetype if dip is a top dip on the board of
21027c478bd9Sstevel@tonic-gate  * interest or SBD_COMP_UNKNOWN otherwise
21037c478bd9Sstevel@tonic-gate  */
21047c478bd9Sstevel@tonic-gate static sbd_comp_type_t
get_node_type(sbd_board_t * sbp,dev_info_t * dip,int * unitp)21057c478bd9Sstevel@tonic-gate get_node_type(sbd_board_t *sbp, dev_info_t *dip, int *unitp)
21067c478bd9Sstevel@tonic-gate {
21077c478bd9Sstevel@tonic-gate 	int		idx, unit;
21087c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp;
21097c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
21107c478bd9Sstevel@tonic-gate 	char		otype[OBP_MAXDRVNAME];
21117c478bd9Sstevel@tonic-gate 	int		otypelen;
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate 	ASSERT(sbp);
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	if (unitp)
21167c478bd9Sstevel@tonic-gate 		*unitp = -1;
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate 	hp = MACHBD2HD(sbp);
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
21217c478bd9Sstevel@tonic-gate 	if (sbdp_get_board_num(hdp, dip) != sbp->sb_num) {
21227c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
21237c478bd9Sstevel@tonic-gate 		return (SBD_COMP_UNKNOWN);
21247c478bd9Sstevel@tonic-gate 	}
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate 	/*
21277c478bd9Sstevel@tonic-gate 	 * sbdp_get_unit_num will return (-1) for cmp as there
21287c478bd9Sstevel@tonic-gate 	 * is no "device_type" property associated with cmp.
21297c478bd9Sstevel@tonic-gate 	 * Therefore we will just skip getting unit number for
21307c478bd9Sstevel@tonic-gate 	 * cmp.  Callers of this function need to check the
21317c478bd9Sstevel@tonic-gate 	 * value set in unitp before using it to dereference
21327c478bd9Sstevel@tonic-gate 	 * an array.
21337c478bd9Sstevel@tonic-gate 	 */
21347c478bd9Sstevel@tonic-gate 	if (strcmp(ddi_node_name(dip), "cmp") == 0) {
21357c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
21367c478bd9Sstevel@tonic-gate 		return (SBD_COMP_CMP);
21377c478bd9Sstevel@tonic-gate 	}
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate 	otypelen = sizeof (otype);
21407c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
21417c478bd9Sstevel@tonic-gate 	    OBP_DEVICETYPE,  (caddr_t)otype, &otypelen)) {
21427c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
21437c478bd9Sstevel@tonic-gate 		return (SBD_COMP_UNKNOWN);
21447c478bd9Sstevel@tonic-gate 	}
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	idx = sbd_otype_to_idx(otype);
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate 	if (SBD_COMP(idx) == SBD_COMP_UNKNOWN) {
21497c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
21507c478bd9Sstevel@tonic-gate 		return (SBD_COMP_UNKNOWN);
21517c478bd9Sstevel@tonic-gate 	}
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 	unit = sbdp_get_unit_num(hdp, dip);
21547c478bd9Sstevel@tonic-gate 	if (unit == -1) {
21557c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
2156*d5ebc493SDan Cross 		    "get_node_type: %s unit fail %p", otype, (void *)dip);
21577c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
21587c478bd9Sstevel@tonic-gate 		return (SBD_COMP_UNKNOWN);
21597c478bd9Sstevel@tonic-gate 	}
21607c478bd9Sstevel@tonic-gate 
21617c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 	if (unitp)
21647c478bd9Sstevel@tonic-gate 		*unitp = unit;
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate 	return (SBD_COMP(idx));
21677c478bd9Sstevel@tonic-gate }
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate typedef struct {
21707c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
21717c478bd9Sstevel@tonic-gate 	int		nmc;
21727c478bd9Sstevel@tonic-gate 	int		hold;
21737c478bd9Sstevel@tonic-gate } walk_tree_t;
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate static int
sbd_setup_devlists(dev_info_t * dip,void * arg)21767c478bd9Sstevel@tonic-gate sbd_setup_devlists(dev_info_t *dip, void *arg)
21777c478bd9Sstevel@tonic-gate {
21787c478bd9Sstevel@tonic-gate 	walk_tree_t	*wp;
21797c478bd9Sstevel@tonic-gate 	dev_info_t	**devlist = NULL;
21807c478bd9Sstevel@tonic-gate 	char		*pathname = NULL;
21817c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
21827c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_setup_devlists";
21837c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
21847c478bd9Sstevel@tonic-gate 	int		unit;
21857c478bd9Sstevel@tonic-gate 	sbd_comp_type_t nodetype;
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate 	ASSERT(dip);
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate 	wp = (walk_tree_t *)arg;
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 	if (wp == NULL) {
21927c478bd9Sstevel@tonic-gate 		PR_ALL("%s:bad arg\n", f);
21937c478bd9Sstevel@tonic-gate 		return (DDI_WALK_TERMINATE);
21947c478bd9Sstevel@tonic-gate 	}
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 	sbp = wp->sbp;
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate 	nodetype = get_node_type(sbp, dip, &unit);
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 	switch (nodetype) {
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
22037c478bd9Sstevel@tonic-gate 		pathname = sbp->sb_cpupath[unit];
22047c478bd9Sstevel@tonic-gate 		break;
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
22077c478bd9Sstevel@tonic-gate 		pathname = sbp->sb_mempath[unit];
22087c478bd9Sstevel@tonic-gate 		break;
22097c478bd9Sstevel@tonic-gate 
22107c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
22117c478bd9Sstevel@tonic-gate 		pathname = sbp->sb_iopath[unit];
22127c478bd9Sstevel@tonic-gate 		break;
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate 	case SBD_COMP_CMP:
22157c478bd9Sstevel@tonic-gate 	case SBD_COMP_UNKNOWN:
22167c478bd9Sstevel@tonic-gate 		/*
22177c478bd9Sstevel@tonic-gate 		 * This dip is not of interest to us
22187c478bd9Sstevel@tonic-gate 		 */
22197c478bd9Sstevel@tonic-gate 		return (DDI_WALK_CONTINUE);
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 	default:
22227c478bd9Sstevel@tonic-gate 		ASSERT(0);
22237c478bd9Sstevel@tonic-gate 		return (DDI_WALK_CONTINUE);
22247c478bd9Sstevel@tonic-gate 	}
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 	/*
22277c478bd9Sstevel@tonic-gate 	 * dip's parent is being held busy by ddi_walk_devs(),
22287c478bd9Sstevel@tonic-gate 	 * so dip doesn't have to be held while calling ddi_pathname()
22297c478bd9Sstevel@tonic-gate 	 */
22307c478bd9Sstevel@tonic-gate 	if (pathname) {
22317c478bd9Sstevel@tonic-gate 		(void) ddi_pathname(dip, pathname);
22327c478bd9Sstevel@tonic-gate 	}
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 	devlist = sbp->sb_devlist[NIX(nodetype)];
22357c478bd9Sstevel@tonic-gate 
22367c478bd9Sstevel@tonic-gate 	/*
22377c478bd9Sstevel@tonic-gate 	 * The branch rooted at dip should already be held,
22387c478bd9Sstevel@tonic-gate 	 * unless we are dealing with a core of a CMP.
22397c478bd9Sstevel@tonic-gate 	 */
22407c478bd9Sstevel@tonic-gate 	ASSERT(sbd_is_cmp_child(dip) || e_ddi_branch_held(dip));
22417c478bd9Sstevel@tonic-gate 	devlist[unit] = dip;
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate 	/*
22447c478bd9Sstevel@tonic-gate 	 * This test is required if multiple devices are considered
22457c478bd9Sstevel@tonic-gate 	 * as one. This is the case for memory-controller nodes.
22467c478bd9Sstevel@tonic-gate 	 */
22477c478bd9Sstevel@tonic-gate 	if (!SBD_DEV_IS_PRESENT(sbp, nodetype, unit)) {
22487c478bd9Sstevel@tonic-gate 		sbp->sb_ndev++;
22497c478bd9Sstevel@tonic-gate 		SBD_DEV_SET_PRESENT(sbp, nodetype, unit);
22507c478bd9Sstevel@tonic-gate 	}
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 	if (nodetype == SBD_COMP_MEM) {
22537c478bd9Sstevel@tonic-gate 		mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
22547c478bd9Sstevel@tonic-gate 		ASSERT(wp->nmc < SBD_NUM_MC_PER_BOARD);
22557c478bd9Sstevel@tonic-gate 		mp->sbm_dip[wp->nmc++] = dip;
22567c478bd9Sstevel@tonic-gate 	}
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate 	return (DDI_WALK_CONTINUE);
22597c478bd9Sstevel@tonic-gate }
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate /*
22627c478bd9Sstevel@tonic-gate  * This routine is used to construct the memory devlist.
22637c478bd9Sstevel@tonic-gate  * In Starcat and Serengeti platforms, a system board can contain up to
22647c478bd9Sstevel@tonic-gate  * four memory controllers (MC).  The MCs have been programmed by POST for
22657c478bd9Sstevel@tonic-gate  * optimum memory interleaving amongst their peers on the same board.
22667c478bd9Sstevel@tonic-gate  * This DR driver does not support deinterleaving.  Therefore, the smallest
22677c478bd9Sstevel@tonic-gate  * unit of memory that can be manipulated by this driver is all of the
22687c478bd9Sstevel@tonic-gate  * memory on a board.  Because of this restriction, a board's memory devlist
22697c478bd9Sstevel@tonic-gate  * is populated with only one of the four (possible) MC dnodes on that board.
22707c478bd9Sstevel@tonic-gate  * Care must be taken to ensure that the selected MC dnode represents the
22717c478bd9Sstevel@tonic-gate  * lowest physical address to which memory on the board will respond to.
22727c478bd9Sstevel@tonic-gate  * This is required in order to preserve the semantics of
22737c478bd9Sstevel@tonic-gate  * sbdp_get_base_physaddr() when applied to a MC dnode stored in the
22747c478bd9Sstevel@tonic-gate  * memory devlist.
22757c478bd9Sstevel@tonic-gate  */
22767c478bd9Sstevel@tonic-gate static void
sbd_init_mem_devlists(sbd_board_t * sbp)22777c478bd9Sstevel@tonic-gate sbd_init_mem_devlists(sbd_board_t *sbp)
22787c478bd9Sstevel@tonic-gate {
22797c478bd9Sstevel@tonic-gate 	dev_info_t	**devlist;
22807c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
22817c478bd9Sstevel@tonic-gate 	dev_info_t	*mc_dip;
22827c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
22837c478bd9Sstevel@tonic-gate 	uint64_t	mc_pa, lowest_pa;
22847c478bd9Sstevel@tonic-gate 	int		i;
22857c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp = MACHBD2HD(sbp);
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 	devlist = sbp->sb_devlist[NIX(SBD_COMP_MEM)];
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 	mp = SBD_GET_BOARD_MEMUNIT(sbp, 0);
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 	mc_dip = mp->sbm_dip[0];
22927c478bd9Sstevel@tonic-gate 	if (mc_dip == NULL)
22937c478bd9Sstevel@tonic-gate 		return;		/* No MC dips found for this board */
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 	if (sbdphw_get_base_physaddr(hdp, mc_dip, &mc_pa)) {
22987c478bd9Sstevel@tonic-gate 		/* TODO: log complaint about dnode */
22997c478bd9Sstevel@tonic-gate 
23007c478bd9Sstevel@tonic-gate pretend_no_mem:
23017c478bd9Sstevel@tonic-gate 		/*
23027c478bd9Sstevel@tonic-gate 		 * We are here because sbdphw_get_base_physaddr() failed.
23037c478bd9Sstevel@tonic-gate 		 * Although it is very unlikely to happen, it did.  Lucky us.
23047c478bd9Sstevel@tonic-gate 		 * Since we can no longer examine _all_ of the MCs on this
23057c478bd9Sstevel@tonic-gate 		 * board to determine which one is programmed to the lowest
23067c478bd9Sstevel@tonic-gate 		 * physical address, we cannot involve any of the MCs on
23077c478bd9Sstevel@tonic-gate 		 * this board in DR operations.  To ensure this, we pretend
23087c478bd9Sstevel@tonic-gate 		 * that this board does not contain any memory.
23097c478bd9Sstevel@tonic-gate 		 *
23107c478bd9Sstevel@tonic-gate 		 * Paranoia: clear the dev_present mask.
23117c478bd9Sstevel@tonic-gate 		 */
23127c478bd9Sstevel@tonic-gate 		if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, 0)) {
23137c478bd9Sstevel@tonic-gate 			ASSERT(sbp->sb_ndev != 0);
23147c478bd9Sstevel@tonic-gate 			SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, 0);
23157c478bd9Sstevel@tonic-gate 			sbp->sb_ndev--;
23167c478bd9Sstevel@tonic-gate 		}
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 		for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
23197c478bd9Sstevel@tonic-gate 			mp->sbm_dip[i] = NULL;
23207c478bd9Sstevel@tonic-gate 		}
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
23237c478bd9Sstevel@tonic-gate 		return;
23247c478bd9Sstevel@tonic-gate 	}
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 	/* assume this one will win. */
23277c478bd9Sstevel@tonic-gate 	devlist[0] = mc_dip;
23287c478bd9Sstevel@tonic-gate 	mp->sbm_cm.sbdev_dip = mc_dip;
23297c478bd9Sstevel@tonic-gate 	lowest_pa = mc_pa;
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate 	/*
23327c478bd9Sstevel@tonic-gate 	 * We know the base physical address of one of the MC devices.  Now
23337c478bd9Sstevel@tonic-gate 	 * we will enumerate through all of the remaining MC devices on
23347c478bd9Sstevel@tonic-gate 	 * the board to find which of them is programmed to the lowest
23357c478bd9Sstevel@tonic-gate 	 * physical address.
23367c478bd9Sstevel@tonic-gate 	 */
23377c478bd9Sstevel@tonic-gate 	for (i = 1; i < SBD_NUM_MC_PER_BOARD; i++) {
23387c478bd9Sstevel@tonic-gate 		mc_dip = mp->sbm_dip[i];
23397c478bd9Sstevel@tonic-gate 		if (mc_dip == NULL) {
23407c478bd9Sstevel@tonic-gate 			break;
23417c478bd9Sstevel@tonic-gate 		}
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 		if (sbdphw_get_base_physaddr(hdp, mc_dip, &mc_pa)) {
23447c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "No mem on board %d unit %d",
2345*d5ebc493SDan Cross 			    sbp->sb_num, i);
23467c478bd9Sstevel@tonic-gate 			break;
23477c478bd9Sstevel@tonic-gate 		}
23487c478bd9Sstevel@tonic-gate 		if (mc_pa < lowest_pa) {
23497c478bd9Sstevel@tonic-gate 			mp->sbm_cm.sbdev_dip = mc_dip;
23507c478bd9Sstevel@tonic-gate 			devlist[0] = mc_dip;
23517c478bd9Sstevel@tonic-gate 			lowest_pa = mc_pa;
23527c478bd9Sstevel@tonic-gate 		}
23537c478bd9Sstevel@tonic-gate 	}
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
23567c478bd9Sstevel@tonic-gate }
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate static int
sbd_name_to_idx(char * name)23597c478bd9Sstevel@tonic-gate sbd_name_to_idx(char *name)
23607c478bd9Sstevel@tonic-gate {
23617c478bd9Sstevel@tonic-gate 	int idx;
23627c478bd9Sstevel@tonic-gate 
23637c478bd9Sstevel@tonic-gate 	for (idx = 0; SBD_COMP(idx) != SBD_COMP_UNKNOWN; idx++) {
23647c478bd9Sstevel@tonic-gate 		if (strcmp(name, SBD_DEVNAME(idx)) == 0) {
23657c478bd9Sstevel@tonic-gate 			break;
23667c478bd9Sstevel@tonic-gate 		}
23677c478bd9Sstevel@tonic-gate 	}
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 	return (idx);
23707c478bd9Sstevel@tonic-gate }
23717c478bd9Sstevel@tonic-gate 
23727c478bd9Sstevel@tonic-gate static int
sbd_otype_to_idx(char * otype)23737c478bd9Sstevel@tonic-gate sbd_otype_to_idx(char *otype)
23747c478bd9Sstevel@tonic-gate {
23757c478bd9Sstevel@tonic-gate 	int idx;
23767c478bd9Sstevel@tonic-gate 
23777c478bd9Sstevel@tonic-gate 	for (idx = 0; SBD_COMP(idx) != SBD_COMP_UNKNOWN; idx++) {
23787c478bd9Sstevel@tonic-gate 
23797c478bd9Sstevel@tonic-gate 		if (strcmp(otype, SBD_OTYPE(idx)) == 0) {
23807c478bd9Sstevel@tonic-gate 			break;
23817c478bd9Sstevel@tonic-gate 		}
23827c478bd9Sstevel@tonic-gate 	}
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate 	return (idx);
23857c478bd9Sstevel@tonic-gate }
23867c478bd9Sstevel@tonic-gate 
23877c478bd9Sstevel@tonic-gate static int
sbd_init_devlists(sbd_board_t * sbp)23887c478bd9Sstevel@tonic-gate sbd_init_devlists(sbd_board_t *sbp)
23897c478bd9Sstevel@tonic-gate {
23907c478bd9Sstevel@tonic-gate 	int		i;
23917c478bd9Sstevel@tonic-gate 	sbd_dev_unit_t	*dp;
23927c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
23937c478bd9Sstevel@tonic-gate 	walk_tree_t	*wp, walk = {0};
23947c478bd9Sstevel@tonic-gate 	dev_info_t	*pdip;
23957c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_init_devlists";
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 	PR_ALL("%s (board = %d)...\n", f, sbp->sb_num);
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate 	wp = &walk;
24007c478bd9Sstevel@tonic-gate 
24017c478bd9Sstevel@tonic-gate 	SBD_DEVS_DISCONNECT(sbp, (uint_t)-1);
24027c478bd9Sstevel@tonic-gate 
24037c478bd9Sstevel@tonic-gate 	/*
24047c478bd9Sstevel@tonic-gate 	 * Clear out old entries, if any.
24057c478bd9Sstevel@tonic-gate 	 */
24067c478bd9Sstevel@tonic-gate 
24077c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
24087c478bd9Sstevel@tonic-gate 		sbp->sb_devlist[NIX(SBD_COMP_MEM)][i] = NULL;
24097c478bd9Sstevel@tonic-gate 		dp = (sbd_dev_unit_t *)SBD_GET_BOARD_MEMUNIT(sbp, i);
24107c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_sbp = sbp;
24117c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_unum = i;
24127c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_type = SBD_COMP_MEM;
24137c478bd9Sstevel@tonic-gate 	}
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate 	mp = SBD_GET_BOARD_MEMUNIT(sbp, 0);
24167c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
24177c478bd9Sstevel@tonic-gate 	for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
24187c478bd9Sstevel@tonic-gate 		mp->sbm_dip[i] = NULL;
24197c478bd9Sstevel@tonic-gate 	}
24207c478bd9Sstevel@tonic-gate 
24217c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
24227c478bd9Sstevel@tonic-gate 		sbp->sb_devlist[NIX(SBD_COMP_CPU)][i] = NULL;
24237c478bd9Sstevel@tonic-gate 		dp = (sbd_dev_unit_t *)SBD_GET_BOARD_CPUUNIT(sbp, i);
24247c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_sbp = sbp;
24257c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_unum = i;
24267c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_type = SBD_COMP_CPU;
24277c478bd9Sstevel@tonic-gate 	}
24287c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
24297c478bd9Sstevel@tonic-gate 		sbp->sb_devlist[NIX(SBD_COMP_IO)][i] = NULL;
24307c478bd9Sstevel@tonic-gate 		dp = (sbd_dev_unit_t *)SBD_GET_BOARD_IOUNIT(sbp, i);
24317c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_sbp = sbp;
24327c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_unum = i;
24337c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_type = SBD_COMP_IO;
24347c478bd9Sstevel@tonic-gate 	}
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 	wp->sbp = sbp;
24377c478bd9Sstevel@tonic-gate 	wp->nmc = 0;
24387c478bd9Sstevel@tonic-gate 	sbp->sb_ndev = 0;
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate 	/*
24417c478bd9Sstevel@tonic-gate 	 * ddi_walk_devs() requires that topdip's parent be held.
24427c478bd9Sstevel@tonic-gate 	 */
24437c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(sbp->sb_topdip);
24447c478bd9Sstevel@tonic-gate 	if (pdip) {
24457c478bd9Sstevel@tonic-gate 		ndi_hold_devi(pdip);
24463fe80ca4SDan Cross 		ndi_devi_enter(pdip);
24477c478bd9Sstevel@tonic-gate 	}
24487c478bd9Sstevel@tonic-gate 	ddi_walk_devs(sbp->sb_topdip, sbd_setup_devlists, (void *) wp);
24497c478bd9Sstevel@tonic-gate 	if (pdip) {
24503fe80ca4SDan Cross 		ndi_devi_exit(pdip);
24517c478bd9Sstevel@tonic-gate 		ndi_rele_devi(pdip);
24527c478bd9Sstevel@tonic-gate 	}
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 	/*
24557c478bd9Sstevel@tonic-gate 	 * There is no point checking all the components if there
24567c478bd9Sstevel@tonic-gate 	 * are no devices.
24577c478bd9Sstevel@tonic-gate 	 */
24587c478bd9Sstevel@tonic-gate 	if (sbp->sb_ndev == 0) {
24597c478bd9Sstevel@tonic-gate 		sbp->sb_memaccess_ok = 0;
24607c478bd9Sstevel@tonic-gate 		return (sbp->sb_ndev);
24617c478bd9Sstevel@tonic-gate 	}
24627c478bd9Sstevel@tonic-gate 
24637c478bd9Sstevel@tonic-gate 	/*
24647c478bd9Sstevel@tonic-gate 	 * Initialize cpu sections before calling sbd_init_mem_devlists
24657c478bd9Sstevel@tonic-gate 	 * which will access the mmus.
24667c478bd9Sstevel@tonic-gate 	 */
24677c478bd9Sstevel@tonic-gate 	sbp->sb_memaccess_ok = 1;
24687c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
24697c478bd9Sstevel@tonic-gate 		if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i)) {
24707c478bd9Sstevel@tonic-gate 			sbd_init_cpu_unit(sbp, i);
24717c478bd9Sstevel@tonic-gate 			if (sbd_connect_cpu(sbp, i)) {
24727c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(HD2MACHERR(MACHBD2HD(sbp)),
2473*d5ebc493SDan Cross 				    ESBD_CPUSTART);
24747c478bd9Sstevel@tonic-gate 			}
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 		}
24777c478bd9Sstevel@tonic-gate 	}
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	if (sbp->sb_memaccess_ok) {
24807c478bd9Sstevel@tonic-gate 		sbd_init_mem_devlists(sbp);
24817c478bd9Sstevel@tonic-gate 	} else {
24827c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "unable to access memory on board %d",
24837c478bd9Sstevel@tonic-gate 		    sbp->sb_num);
24847c478bd9Sstevel@tonic-gate 	}
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 	return (sbp->sb_ndev);
24877c478bd9Sstevel@tonic-gate }
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate static void
sbd_init_cpu_unit(sbd_board_t * sbp,int unit)24907c478bd9Sstevel@tonic-gate sbd_init_cpu_unit(sbd_board_t *sbp, int unit)
24917c478bd9Sstevel@tonic-gate {
24927c478bd9Sstevel@tonic-gate 	sbd_istate_t	new_state;
24937c478bd9Sstevel@tonic-gate 	sbd_cpu_unit_t	*cp;
24947c478bd9Sstevel@tonic-gate 	int		cpuid;
24957c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
24967c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
24977c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp = MACHBD2HD(sbp);
24987c478bd9Sstevel@tonic-gate 	extern kmutex_t	cpu_lock;
24997c478bd9Sstevel@tonic-gate 
25007c478bd9Sstevel@tonic-gate 	if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_CPU, unit)) {
25017c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_CONFIGURED;
25027c478bd9Sstevel@tonic-gate 	} else if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, unit)) {
25037c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_CONNECTED;
25047c478bd9Sstevel@tonic-gate 	} else {
25057c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_EMPTY;
25067c478bd9Sstevel@tonic-gate 	}
25077c478bd9Sstevel@tonic-gate 
25087c478bd9Sstevel@tonic-gate 	dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][unit];
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 	cp = SBD_GET_BOARD_CPUUNIT(sbp, unit);
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
25137c478bd9Sstevel@tonic-gate 
25147c478bd9Sstevel@tonic-gate 	cpuid = sbdp_get_cpuid(hdp, dip);
25157c478bd9Sstevel@tonic-gate 
25167c478bd9Sstevel@tonic-gate 	cp->sbc_cpu_id = cpuid;
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate 	if (&sbdp_cpu_get_impl)
25197c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_impl = sbdp_cpu_get_impl(hdp, dip);
25207c478bd9Sstevel@tonic-gate 	else
25217c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_impl = -1;
25227c478bd9Sstevel@tonic-gate 
25237c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
25247c478bd9Sstevel@tonic-gate 	if ((cpuid >= 0) && cpu[cpuid])
25257c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_flags = cpu[cpuid]->cpu_flags;
25267c478bd9Sstevel@tonic-gate 	else
25277c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_flags = CPU_OFFLINE | CPU_POWEROFF;
25287c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
25297c478bd9Sstevel@tonic-gate 
25307c478bd9Sstevel@tonic-gate 	sbd_cpu_set_prop(cp, dip);
25317c478bd9Sstevel@tonic-gate 
25327c478bd9Sstevel@tonic-gate 	cp->sbc_cm.sbdev_cond = sbd_get_comp_cond(dip);
25337c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 	/*
25367c478bd9Sstevel@tonic-gate 	 * Any changes to the cpu should be performed above
25377c478bd9Sstevel@tonic-gate 	 * this call to ensure the cpu is fully initialized
25387c478bd9Sstevel@tonic-gate 	 * before transitioning to the new state.
25397c478bd9Sstevel@tonic-gate 	 */
25407c478bd9Sstevel@tonic-gate 	SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, unit, new_state);
25417c478bd9Sstevel@tonic-gate }
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate /*
25447c478bd9Sstevel@tonic-gate  * Only do work if called to operate on an entire board
25457c478bd9Sstevel@tonic-gate  * which doesn't already have components present.
25467c478bd9Sstevel@tonic-gate  */
25477c478bd9Sstevel@tonic-gate static void
sbd_connect(sbd_handle_t * hp)25487c478bd9Sstevel@tonic-gate sbd_connect(sbd_handle_t *hp)
25497c478bd9Sstevel@tonic-gate {
25507c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
25517c478bd9Sstevel@tonic-gate 	sbderror_t	*ep;
25527c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_connect";
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate 	PR_ALL("%s board %d\n", f, sbp->sb_num);
25577c478bd9Sstevel@tonic-gate 
25587c478bd9Sstevel@tonic-gate 	ep = HD2MACHERR(hp);
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate 	if (SBD_DEVS_PRESENT(sbp)) {
25617c478bd9Sstevel@tonic-gate 		/*
25627c478bd9Sstevel@tonic-gate 		 * Board already has devices present.
25637c478bd9Sstevel@tonic-gate 		 */
25647c478bd9Sstevel@tonic-gate 		PR_ALL("%s: devices already present (0x%x)\n",
2565*d5ebc493SDan Cross 		    f, SBD_DEVS_PRESENT(sbp));
25667c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(ep, EINVAL);
25677c478bd9Sstevel@tonic-gate 		return;
25687c478bd9Sstevel@tonic-gate 	}
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	if (sbd_init_devlists(sbp) == 0) {
25717c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: no devices present on board %d",
2572*d5ebc493SDan Cross 		    f, sbp->sb_num);
25737c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_NODEV);
25747c478bd9Sstevel@tonic-gate 		return;
25757c478bd9Sstevel@tonic-gate 	} else {
25767c478bd9Sstevel@tonic-gate 		int	i;
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 		/*
25797c478bd9Sstevel@tonic-gate 		 * Initialize mem-unit section of board structure.
25807c478bd9Sstevel@tonic-gate 		 */
25817c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++)
25827c478bd9Sstevel@tonic-gate 			if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i))
25837c478bd9Sstevel@tonic-gate 				sbd_init_mem_unit(sbp, i, SBD_HD2ERR(hp));
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 		/*
25867c478bd9Sstevel@tonic-gate 		 * Initialize sb_io sections.
25877c478bd9Sstevel@tonic-gate 		 */
25887c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++)
25897c478bd9Sstevel@tonic-gate 			if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_IO, i))
25907c478bd9Sstevel@tonic-gate 				sbd_init_io_unit(sbp, i);
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 		SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONNECTED);
25937c478bd9Sstevel@tonic-gate 		sbp->sb_rstate = SBD_STAT_CONNECTED;
25947c478bd9Sstevel@tonic-gate 		sbp->sb_ostate = SBD_STAT_UNCONFIGURED;
25957c478bd9Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&sbp->sb_time);
25967c478bd9Sstevel@tonic-gate 		SBD_INJECT_ERR(SBD_CONNECT_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2597*d5ebc493SDan Cross 		    ESBD_INTERNAL, NULL);
25987c478bd9Sstevel@tonic-gate 	}
25997c478bd9Sstevel@tonic-gate }
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate static int
sbd_disconnect(sbd_handle_t * hp)26027c478bd9Sstevel@tonic-gate sbd_disconnect(sbd_handle_t *hp)
26037c478bd9Sstevel@tonic-gate {
26047c478bd9Sstevel@tonic-gate 	int		i;
26057c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
26067c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
26077c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_disconnect it";
26087c478bd9Sstevel@tonic-gate 
26097c478bd9Sstevel@tonic-gate 	PR_ALL("%s ...\n", f);
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
26127c478bd9Sstevel@tonic-gate 
26137c478bd9Sstevel@tonic-gate 	/*
26147c478bd9Sstevel@tonic-gate 	 * Only devices which are present, but
26157c478bd9Sstevel@tonic-gate 	 * unattached can be disconnected.
26167c478bd9Sstevel@tonic-gate 	 */
26177c478bd9Sstevel@tonic-gate 	devset = HD2MACHHD(hp)->sh_devset & SBD_DEVS_PRESENT(sbp) &
2618*d5ebc493SDan Cross 	    SBD_DEVS_UNATTACHED(sbp);
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate 	ASSERT((SBD_DEVS_ATTACHED(sbp) & devset) == 0);
26217c478bd9Sstevel@tonic-gate 
26227c478bd9Sstevel@tonic-gate 	/*
26237c478bd9Sstevel@tonic-gate 	 * Update per-device state transitions.
26247c478bd9Sstevel@tonic-gate 	 */
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++)
26277c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) {
26287c478bd9Sstevel@tonic-gate 			if (sbd_disconnect_mem(hp, i) == 0) {
26297c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i,
2630*d5ebc493SDan Cross 				    SBD_STATE_EMPTY);
26317c478bd9Sstevel@tonic-gate 				SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, i);
26327c478bd9Sstevel@tonic-gate 			}
26337c478bd9Sstevel@tonic-gate 		}
26347c478bd9Sstevel@tonic-gate 
26357c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++)
26367c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_CPU, i)) {
26377c478bd9Sstevel@tonic-gate 			if (sbd_disconnect_cpu(hp, i) == 0) {
26387c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i,
2639*d5ebc493SDan Cross 				    SBD_STATE_EMPTY);
26407c478bd9Sstevel@tonic-gate 				SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_CPU, i);
26417c478bd9Sstevel@tonic-gate 			}
26427c478bd9Sstevel@tonic-gate 		}
26437c478bd9Sstevel@tonic-gate 
26447c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++)
26457c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_IO, i)) {
26467c478bd9Sstevel@tonic-gate 			if (sbd_disconnect_io(hp, i) == 0) {
26477c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, i,
2648*d5ebc493SDan Cross 				    SBD_STATE_EMPTY);
26497c478bd9Sstevel@tonic-gate 				SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_IO, i);
26507c478bd9Sstevel@tonic-gate 			}
26517c478bd9Sstevel@tonic-gate 		}
26527c478bd9Sstevel@tonic-gate 
26537c478bd9Sstevel@tonic-gate 	/*
26547c478bd9Sstevel@tonic-gate 	 * Once all the components on a board have been disconnect
26557c478bd9Sstevel@tonic-gate 	 * the board's state can transition to disconnected and
26567c478bd9Sstevel@tonic-gate 	 * we can allow the deprobe to take place.
26577c478bd9Sstevel@tonic-gate 	 */
26587c478bd9Sstevel@tonic-gate 	if (SBD_DEVS_PRESENT(sbp) == 0) {
26597c478bd9Sstevel@tonic-gate 		SBD_BOARD_TRANSITION(sbp, SBD_STATE_OCCUPIED);
26607c478bd9Sstevel@tonic-gate 		sbp->sb_rstate = SBD_STAT_DISCONNECTED;
26617c478bd9Sstevel@tonic-gate 		sbp->sb_ostate = SBD_STAT_UNCONFIGURED;
26627c478bd9Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&sbp->sb_time);
26637c478bd9Sstevel@tonic-gate 		SBD_INJECT_ERR(SBD_DISCONNECT_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2664*d5ebc493SDan Cross 		    ESBD_INTERNAL, NULL);
26657c478bd9Sstevel@tonic-gate 		return (0);
26667c478bd9Sstevel@tonic-gate 	} else {
26677c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: could not disconnect devices on board %d",
2668*d5ebc493SDan Cross 		    f, sbp->sb_num);
26697c478bd9Sstevel@tonic-gate 		return (-1);
26707c478bd9Sstevel@tonic-gate 	}
26717c478bd9Sstevel@tonic-gate }
26727c478bd9Sstevel@tonic-gate 
26737c478bd9Sstevel@tonic-gate static void
sbd_test_board(sbd_handle_t * hp)26747c478bd9Sstevel@tonic-gate sbd_test_board(sbd_handle_t *hp)
26757c478bd9Sstevel@tonic-gate {
26767c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
26777c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
26787c478bd9Sstevel@tonic-gate 
26797c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate 	PR_ALL("sbd_test_board: board %d\n", sbp->sb_num);
26827c478bd9Sstevel@tonic-gate 
26837c478bd9Sstevel@tonic-gate 
26847c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
26857c478bd9Sstevel@tonic-gate 
26867c478bd9Sstevel@tonic-gate 	if (sbdp_test_board(hdp, &hp->h_opts) != 0) {
26877c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
26887c478bd9Sstevel@tonic-gate 
26897c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
26907c478bd9Sstevel@tonic-gate 	}
26917c478bd9Sstevel@tonic-gate 
26927c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_TEST_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2693*d5ebc493SDan Cross 	    ESBD_INTERNAL, NULL);
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
26967c478bd9Sstevel@tonic-gate }
26977c478bd9Sstevel@tonic-gate 
26987c478bd9Sstevel@tonic-gate static void
sbd_assign_board(sbd_handle_t * hp)26997c478bd9Sstevel@tonic-gate sbd_assign_board(sbd_handle_t *hp)
27007c478bd9Sstevel@tonic-gate {
27017c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
27027c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
27037c478bd9Sstevel@tonic-gate 
27047c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
27057c478bd9Sstevel@tonic-gate 
27067c478bd9Sstevel@tonic-gate 	PR_ALL("sbd_assign_board: board %d\n", sbp->sb_num);
27077c478bd9Sstevel@tonic-gate 
27087c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
27097c478bd9Sstevel@tonic-gate 
27107c478bd9Sstevel@tonic-gate 	if (sbdp_assign_board(hdp) != 0) {
27117c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
27127c478bd9Sstevel@tonic-gate 
27137c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
27147c478bd9Sstevel@tonic-gate 	}
27157c478bd9Sstevel@tonic-gate 
27167c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_ASSIGN_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2717*d5ebc493SDan Cross 	    ESBD_INTERNAL, NULL);
27187c478bd9Sstevel@tonic-gate 
27197c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
27207c478bd9Sstevel@tonic-gate }
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate static void
sbd_unassign_board(sbd_handle_t * hp)27237c478bd9Sstevel@tonic-gate sbd_unassign_board(sbd_handle_t *hp)
27247c478bd9Sstevel@tonic-gate {
27257c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
27267c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
27277c478bd9Sstevel@tonic-gate 
27287c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate 	PR_ALL("sbd_unassign_board: board %d\n", sbp->sb_num);
27317c478bd9Sstevel@tonic-gate 
27327c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate 	if (sbdp_unassign_board(hdp) != 0) {
27357c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
27387c478bd9Sstevel@tonic-gate 	}
27397c478bd9Sstevel@tonic-gate 
27407c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_ASSIGN_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2741*d5ebc493SDan Cross 	    ESBD_INTERNAL, NULL);
27427c478bd9Sstevel@tonic-gate 
27437c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
27447c478bd9Sstevel@tonic-gate }
27457c478bd9Sstevel@tonic-gate 
27467c478bd9Sstevel@tonic-gate static void
sbd_poweron_board(sbd_handle_t * hp)27477c478bd9Sstevel@tonic-gate sbd_poweron_board(sbd_handle_t *hp)
27487c478bd9Sstevel@tonic-gate {
27497c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
27507c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
27517c478bd9Sstevel@tonic-gate 
27527c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
27537c478bd9Sstevel@tonic-gate 
27547c478bd9Sstevel@tonic-gate 	PR_ALL("sbd_poweron_board: %d\n", sbp->sb_num);
27557c478bd9Sstevel@tonic-gate 
27567c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
27577c478bd9Sstevel@tonic-gate 
27587c478bd9Sstevel@tonic-gate 	if (sbdp_poweron_board(hdp) != 0) {
27597c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
27627c478bd9Sstevel@tonic-gate 	}
27637c478bd9Sstevel@tonic-gate 
27647c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_POWERON_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2765*d5ebc493SDan Cross 	    ESBD_INTERNAL, NULL);
27667c478bd9Sstevel@tonic-gate 
27677c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
27687c478bd9Sstevel@tonic-gate }
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate static void
sbd_poweroff_board(sbd_handle_t * hp)27717c478bd9Sstevel@tonic-gate sbd_poweroff_board(sbd_handle_t *hp)
27727c478bd9Sstevel@tonic-gate {
27737c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
27747c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
27757c478bd9Sstevel@tonic-gate 
27767c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
27777c478bd9Sstevel@tonic-gate 
27787c478bd9Sstevel@tonic-gate 	PR_ALL("sbd_poweroff_board: %d\n", sbp->sb_num);
27797c478bd9Sstevel@tonic-gate 
27807c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
27817c478bd9Sstevel@tonic-gate 
27827c478bd9Sstevel@tonic-gate 	if (sbdp_poweroff_board(hdp) != 0) {
27837c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
27847c478bd9Sstevel@tonic-gate 
27857c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
27867c478bd9Sstevel@tonic-gate 	}
27877c478bd9Sstevel@tonic-gate 
27887c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_POWEROFF_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2789*d5ebc493SDan Cross 	    ESBD_INTERNAL, NULL);
27907c478bd9Sstevel@tonic-gate 
27917c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
27927c478bd9Sstevel@tonic-gate }
27937c478bd9Sstevel@tonic-gate 
27947c478bd9Sstevel@tonic-gate 
27957c478bd9Sstevel@tonic-gate /*
27967c478bd9Sstevel@tonic-gate  * Return a list of the dip's of devices that are
27977c478bd9Sstevel@tonic-gate  * either present and attached, or present only but
27987c478bd9Sstevel@tonic-gate  * not yet attached for the given board.
27997c478bd9Sstevel@tonic-gate  */
28007c478bd9Sstevel@tonic-gate sbd_devlist_t *
sbd_get_devlist(sbd_handle_t * hp,sbd_board_t * sbp,sbd_comp_type_t nodetype,int max_units,uint_t uset,int * count,int present_only)28017c478bd9Sstevel@tonic-gate sbd_get_devlist(sbd_handle_t *hp, sbd_board_t *sbp, sbd_comp_type_t nodetype,
2802*d5ebc493SDan Cross     int max_units, uint_t uset, int *count, int present_only)
28037c478bd9Sstevel@tonic-gate {
28047c478bd9Sstevel@tonic-gate 	int		i, ix;
28057c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*ret_devlist;
28067c478bd9Sstevel@tonic-gate 	dev_info_t	**devlist;
28077c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
28087c478bd9Sstevel@tonic-gate 
28097c478bd9Sstevel@tonic-gate 	*count = 0;
28107c478bd9Sstevel@tonic-gate 	ret_devlist = GETSTRUCT(sbd_devlist_t, max_units);
28117c478bd9Sstevel@tonic-gate 	devlist = sbp->sb_devlist[NIX(nodetype)];
28127c478bd9Sstevel@tonic-gate 	/*
28137c478bd9Sstevel@tonic-gate 	 * Turn into binary value since we're going
28147c478bd9Sstevel@tonic-gate 	 * to be using XOR for a comparison.
28157c478bd9Sstevel@tonic-gate 	 * if (present_only) then
28167c478bd9Sstevel@tonic-gate 	 *	dev must be PRESENT, but NOT ATTACHED.
28177c478bd9Sstevel@tonic-gate 	 * else
28187c478bd9Sstevel@tonic-gate 	 *	dev must be PRESENT AND ATTACHED.
28197c478bd9Sstevel@tonic-gate 	 * endif
28207c478bd9Sstevel@tonic-gate 	 */
28217c478bd9Sstevel@tonic-gate 	if (present_only)
28227c478bd9Sstevel@tonic-gate 		present_only = 1;
28237c478bd9Sstevel@tonic-gate 
28247c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate 	for (i = ix = 0; (i < max_units) && uset; i++) {
28277c478bd9Sstevel@tonic-gate 		int	ut, is_present, is_attached;
28287c478bd9Sstevel@tonic-gate 		dev_info_t *dip;
28297c478bd9Sstevel@tonic-gate 		sbderror_t *ep = SBD_HD2ERR(hp);
28307c478bd9Sstevel@tonic-gate 		int	nunits, distance, j;
28317c478bd9Sstevel@tonic-gate 
28327c478bd9Sstevel@tonic-gate 		/*
28337c478bd9Sstevel@tonic-gate 		 * For CMPs, we would like to perform DR operation on
28347c478bd9Sstevel@tonic-gate 		 * all the cores before moving onto the next chip.
28357c478bd9Sstevel@tonic-gate 		 * Therefore, when constructing the devlist, we process
28367c478bd9Sstevel@tonic-gate 		 * all the cores together.
28377c478bd9Sstevel@tonic-gate 		 */
28387c478bd9Sstevel@tonic-gate 		if (nodetype == SBD_COMP_CPU) {
28397c478bd9Sstevel@tonic-gate 			/*
28407c478bd9Sstevel@tonic-gate 			 * Number of units to process in the inner loop
28417c478bd9Sstevel@tonic-gate 			 */
28427c478bd9Sstevel@tonic-gate 			nunits = MAX_CORES_PER_CMP;
28437c478bd9Sstevel@tonic-gate 			/*
28447c478bd9Sstevel@tonic-gate 			 * The distance between the units in the
28457c478bd9Sstevel@tonic-gate 			 * board's sb_devlist structure.
28467c478bd9Sstevel@tonic-gate 			 */
28477c478bd9Sstevel@tonic-gate 			distance = MAX_CMP_UNITS_PER_BOARD;
28487c478bd9Sstevel@tonic-gate 		} else {
28497c478bd9Sstevel@tonic-gate 			nunits = 1;
28507c478bd9Sstevel@tonic-gate 			distance = 0;
28517c478bd9Sstevel@tonic-gate 		}
28527c478bd9Sstevel@tonic-gate 
28537c478bd9Sstevel@tonic-gate 		for (j = 0; j < nunits; j++) {
28547c478bd9Sstevel@tonic-gate 			if ((dip = devlist[i + j * distance]) == NULL)
28557c478bd9Sstevel@tonic-gate 				continue;
28567c478bd9Sstevel@tonic-gate 
28577c478bd9Sstevel@tonic-gate 			ut = sbdp_get_unit_num(hdp, dip);
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate 			if (ut == -1) {
28607c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, ep);
28617c478bd9Sstevel@tonic-gate 				PR_ALL("sbd_get_devlist bad unit %d"
28627c478bd9Sstevel@tonic-gate 				    " code %d errno %d",
28637c478bd9Sstevel@tonic-gate 				    i, ep->e_code, ep->e_errno);
28647c478bd9Sstevel@tonic-gate 			}
28657c478bd9Sstevel@tonic-gate 
28667c478bd9Sstevel@tonic-gate 			if ((uset & (1 << ut)) == 0)
28677c478bd9Sstevel@tonic-gate 				continue;
28687c478bd9Sstevel@tonic-gate 			uset &= ~(1 << ut);
2869*d5ebc493SDan Cross 			is_present =
2870*d5ebc493SDan Cross 			    SBD_DEV_IS_PRESENT(sbp, nodetype, ut) ? 1 : 0;
2871*d5ebc493SDan Cross 			is_attached =
2872*d5ebc493SDan Cross 			    SBD_DEV_IS_ATTACHED(sbp, nodetype, ut) ? 1 : 0;
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate 			if (is_present && (present_only ^ is_attached)) {
28757c478bd9Sstevel@tonic-gate 				ret_devlist[ix].dv_dip = dip;
28767c478bd9Sstevel@tonic-gate 				sbd_init_err(&ret_devlist[ix].dv_error);
28777c478bd9Sstevel@tonic-gate 				ix++;
28787c478bd9Sstevel@tonic-gate 			}
28797c478bd9Sstevel@tonic-gate 		}
28807c478bd9Sstevel@tonic-gate 	}
28817c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
28827c478bd9Sstevel@tonic-gate 
28837c478bd9Sstevel@tonic-gate 	if ((*count = ix) == 0) {
28847c478bd9Sstevel@tonic-gate 		FREESTRUCT(ret_devlist, sbd_devlist_t, max_units);
28857c478bd9Sstevel@tonic-gate 		ret_devlist = NULL;
28867c478bd9Sstevel@tonic-gate 	}
28877c478bd9Sstevel@tonic-gate 
28887c478bd9Sstevel@tonic-gate 	return (ret_devlist);
28897c478bd9Sstevel@tonic-gate }
28907c478bd9Sstevel@tonic-gate 
28917c478bd9Sstevel@tonic-gate static sbd_devlist_t *
sbd_get_attach_devlist(sbd_handle_t * hp,int32_t * devnump,int32_t pass)28927c478bd9Sstevel@tonic-gate sbd_get_attach_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass)
28937c478bd9Sstevel@tonic-gate {
28947c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
28957c478bd9Sstevel@tonic-gate 	uint_t		uset;
28967c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
28977c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*attach_devlist;
28987c478bd9Sstevel@tonic-gate 	static int	next_pass = 1;
28997c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_get_attach_devlist";
29007c478bd9Sstevel@tonic-gate 
29017c478bd9Sstevel@tonic-gate 	PR_ALL("%s (pass = %d)...\n", f, pass);
29027c478bd9Sstevel@tonic-gate 
29037c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
29047c478bd9Sstevel@tonic-gate 	devset = HD2MACHHD(hp)->sh_devset;
29057c478bd9Sstevel@tonic-gate 
29067c478bd9Sstevel@tonic-gate 	*devnump = 0;
29077c478bd9Sstevel@tonic-gate 	attach_devlist = NULL;
29087c478bd9Sstevel@tonic-gate 
29097c478bd9Sstevel@tonic-gate 	/*
29107c478bd9Sstevel@tonic-gate 	 * We switch on next_pass for the cases where a board
29117c478bd9Sstevel@tonic-gate 	 * does not contain a particular type of component.
29127c478bd9Sstevel@tonic-gate 	 * In these situations we don't want to return NULL
29137c478bd9Sstevel@tonic-gate 	 * prematurely.  We need to check other devices and
29147c478bd9Sstevel@tonic-gate 	 * we don't want to check the same type multiple times.
29157c478bd9Sstevel@tonic-gate 	 * For example, if there were no cpus, then on pass 1
29167c478bd9Sstevel@tonic-gate 	 * we would drop through and return the memory nodes.
29177c478bd9Sstevel@tonic-gate 	 * However, on pass 2 we would switch back to the memory
29187c478bd9Sstevel@tonic-gate 	 * nodes thereby returning them twice!  Using next_pass
29197c478bd9Sstevel@tonic-gate 	 * forces us down to the end (or next item).
29207c478bd9Sstevel@tonic-gate 	 */
29217c478bd9Sstevel@tonic-gate 	if (pass == 1)
29227c478bd9Sstevel@tonic-gate 		next_pass = 1;
29237c478bd9Sstevel@tonic-gate 
29247c478bd9Sstevel@tonic-gate 	switch (next_pass) {
29257c478bd9Sstevel@tonic-gate 	case 1:
29267c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) {
29277c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU);
29287c478bd9Sstevel@tonic-gate 
29297c478bd9Sstevel@tonic-gate 			attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_CPU,
2930*d5ebc493SDan Cross 			    MAX_CPU_UNITS_PER_BOARD, uset, devnump, 1);
29317c478bd9Sstevel@tonic-gate 
29327c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT);
29337c478bd9Sstevel@tonic-gate 			if (!devset || attach_devlist) {
29347c478bd9Sstevel@tonic-gate 				next_pass = 2;
29357c478bd9Sstevel@tonic-gate 				return (attach_devlist);
29367c478bd9Sstevel@tonic-gate 			}
29377c478bd9Sstevel@tonic-gate 			/*
29387c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
29397c478bd9Sstevel@tonic-gate 			 * board, but there aren't any cpus, then just
29407c478bd9Sstevel@tonic-gate 			 * fall through to check for the next component.
29417c478bd9Sstevel@tonic-gate 			 */
29427c478bd9Sstevel@tonic-gate 		}
29437c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
29447c478bd9Sstevel@tonic-gate 
29457c478bd9Sstevel@tonic-gate 	case 2:
29467c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) {
29477c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM);
29487c478bd9Sstevel@tonic-gate 
29497c478bd9Sstevel@tonic-gate 			attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_MEM,
2950*d5ebc493SDan Cross 			    MAX_MEM_UNITS_PER_BOARD, uset, devnump, 1);
29517c478bd9Sstevel@tonic-gate 
29527c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT);
29537c478bd9Sstevel@tonic-gate 			if (!devset || attach_devlist) {
29547c478bd9Sstevel@tonic-gate 				next_pass = 3;
29557c478bd9Sstevel@tonic-gate 				return (attach_devlist);
29567c478bd9Sstevel@tonic-gate 			}
29577c478bd9Sstevel@tonic-gate 			/*
29587c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
29597c478bd9Sstevel@tonic-gate 			 * board, but there isn't any memory, then
29607c478bd9Sstevel@tonic-gate 			 * just fall through to next component.
29617c478bd9Sstevel@tonic-gate 			 */
29627c478bd9Sstevel@tonic-gate 		}
29637c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
29647c478bd9Sstevel@tonic-gate 
29657c478bd9Sstevel@tonic-gate 
29667c478bd9Sstevel@tonic-gate 	case 3:
29677c478bd9Sstevel@tonic-gate 		next_pass = -1;
29687c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) {
29697c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO);
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate 			attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_IO,
2972*d5ebc493SDan Cross 			    MAX_IO_UNITS_PER_BOARD, uset, devnump, 1);
29737c478bd9Sstevel@tonic-gate 
29747c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT);
29757c478bd9Sstevel@tonic-gate 			if (!devset || attach_devlist) {
29767c478bd9Sstevel@tonic-gate 				next_pass = 4;
29777c478bd9Sstevel@tonic-gate 				return (attach_devlist);
29787c478bd9Sstevel@tonic-gate 			}
29797c478bd9Sstevel@tonic-gate 		}
29807c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate 	default:
29837c478bd9Sstevel@tonic-gate 		*devnump = 0;
29847c478bd9Sstevel@tonic-gate 		return (NULL);
29857c478bd9Sstevel@tonic-gate 	}
29867c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
29877c478bd9Sstevel@tonic-gate }
29887c478bd9Sstevel@tonic-gate 
29897c478bd9Sstevel@tonic-gate static int
sbd_pre_attach_devlist(sbd_handle_t * hp,sbd_devlist_t * devlist,int32_t devnum)2990*d5ebc493SDan Cross sbd_pre_attach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, int32_t devnum)
29917c478bd9Sstevel@tonic-gate {
29927c478bd9Sstevel@tonic-gate 	int		max_units = 0, rv = 0;
29937c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
29947c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_pre_attach_devlist";
29957c478bd9Sstevel@tonic-gate 
29967c478bd9Sstevel@tonic-gate 	/*
29977c478bd9Sstevel@tonic-gate 	 * In this driver, all entries in a devlist[] are
29987c478bd9Sstevel@tonic-gate 	 * of the same nodetype.
29997c478bd9Sstevel@tonic-gate 	 */
30007c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
30017c478bd9Sstevel@tonic-gate 
30027c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3003*d5ebc493SDan Cross 	    f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
30047c478bd9Sstevel@tonic-gate 
30057c478bd9Sstevel@tonic-gate 	switch (nodetype) {
30067c478bd9Sstevel@tonic-gate 
30077c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
30087c478bd9Sstevel@tonic-gate 		max_units = MAX_MEM_UNITS_PER_BOARD;
30097c478bd9Sstevel@tonic-gate 		rv = sbd_pre_attach_mem(hp, devlist, devnum);
30107c478bd9Sstevel@tonic-gate 		break;
30117c478bd9Sstevel@tonic-gate 
30127c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
30137c478bd9Sstevel@tonic-gate 		max_units = MAX_CPU_UNITS_PER_BOARD;
30147c478bd9Sstevel@tonic-gate 		rv = sbd_pre_attach_cpu(hp, devlist, devnum);
30157c478bd9Sstevel@tonic-gate 		break;
30167c478bd9Sstevel@tonic-gate 
30177c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
30187c478bd9Sstevel@tonic-gate 		max_units = MAX_IO_UNITS_PER_BOARD;
30197c478bd9Sstevel@tonic-gate 		break;
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate 	default:
30227c478bd9Sstevel@tonic-gate 		rv = -1;
30237c478bd9Sstevel@tonic-gate 		break;
30247c478bd9Sstevel@tonic-gate 	}
30257c478bd9Sstevel@tonic-gate 
30267c478bd9Sstevel@tonic-gate 	if (rv && max_units) {
30277c478bd9Sstevel@tonic-gate 		int	i;
30287c478bd9Sstevel@tonic-gate 		/*
30297c478bd9Sstevel@tonic-gate 		 * Need to clean up devlist
30307c478bd9Sstevel@tonic-gate 		 * if pre-op is going to fail.
30317c478bd9Sstevel@tonic-gate 		 */
30327c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_units; i++) {
30337c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERRSTR(&devlist[i].dv_error)) {
30347c478bd9Sstevel@tonic-gate 				SBD_FREE_ERR(&devlist[i].dv_error);
30357c478bd9Sstevel@tonic-gate 			} else {
30367c478bd9Sstevel@tonic-gate 				break;
30377c478bd9Sstevel@tonic-gate 			}
30387c478bd9Sstevel@tonic-gate 		}
30397c478bd9Sstevel@tonic-gate 		FREESTRUCT(devlist, sbd_devlist_t, max_units);
30407c478bd9Sstevel@tonic-gate 	}
30417c478bd9Sstevel@tonic-gate 
30427c478bd9Sstevel@tonic-gate 	/*
30437c478bd9Sstevel@tonic-gate 	 * If an error occurred, return "continue"
30447c478bd9Sstevel@tonic-gate 	 * indication so that we can continue attaching
30457c478bd9Sstevel@tonic-gate 	 * as much as possible.
30467c478bd9Sstevel@tonic-gate 	 */
30477c478bd9Sstevel@tonic-gate 	return (rv ? -1 : 0);
30487c478bd9Sstevel@tonic-gate }
30497c478bd9Sstevel@tonic-gate 
30507c478bd9Sstevel@tonic-gate static int
sbd_post_attach_devlist(sbd_handle_t * hp,sbd_devlist_t * devlist,int32_t devnum)30517c478bd9Sstevel@tonic-gate sbd_post_attach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist,
3052*d5ebc493SDan Cross     int32_t devnum)
30537c478bd9Sstevel@tonic-gate {
30547c478bd9Sstevel@tonic-gate 	int		i, max_units = 0, rv = 0;
30557c478bd9Sstevel@tonic-gate 	sbd_devset_t	devs_unattached, devs_present;
30567c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
3057*d5ebc493SDan Cross 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
30587c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
30597c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_post_attach_devlist";
30607c478bd9Sstevel@tonic-gate 
30617c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
30627c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
30637c478bd9Sstevel@tonic-gate 
30647c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3065*d5ebc493SDan Cross 	    f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
30667c478bd9Sstevel@tonic-gate 
30677c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
30687c478bd9Sstevel@tonic-gate 
30697c478bd9Sstevel@tonic-gate 	/*
30707c478bd9Sstevel@tonic-gate 	 * Need to free up devlist[] created earlier in
30717c478bd9Sstevel@tonic-gate 	 * sbd_get_attach_devlist().
30727c478bd9Sstevel@tonic-gate 	 */
30737c478bd9Sstevel@tonic-gate 	switch (nodetype) {
30747c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
30757c478bd9Sstevel@tonic-gate 		max_units = MAX_CPU_UNITS_PER_BOARD;
30767c478bd9Sstevel@tonic-gate 		rv = sbd_post_attach_cpu(hp, devlist, devnum);
30777c478bd9Sstevel@tonic-gate 		break;
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
30817c478bd9Sstevel@tonic-gate 		max_units = MAX_MEM_UNITS_PER_BOARD;
30827c478bd9Sstevel@tonic-gate 
30837c478bd9Sstevel@tonic-gate 		rv = sbd_post_attach_mem(hp, devlist, devnum);
30847c478bd9Sstevel@tonic-gate 		break;
30857c478bd9Sstevel@tonic-gate 
30867c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
30877c478bd9Sstevel@tonic-gate 		max_units = MAX_IO_UNITS_PER_BOARD;
30887c478bd9Sstevel@tonic-gate 		break;
30897c478bd9Sstevel@tonic-gate 
30907c478bd9Sstevel@tonic-gate 	default:
30917c478bd9Sstevel@tonic-gate 		rv = -1;
30927c478bd9Sstevel@tonic-gate 		break;
30937c478bd9Sstevel@tonic-gate 	}
30947c478bd9Sstevel@tonic-gate 
30957c478bd9Sstevel@tonic-gate 
30967c478bd9Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
30977c478bd9Sstevel@tonic-gate 		int		unit;
30987c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
30997c478bd9Sstevel@tonic-gate 		sbderror_t	*ep;
31007c478bd9Sstevel@tonic-gate 
31017c478bd9Sstevel@tonic-gate 		ep = &devlist[i].dv_error;
31027c478bd9Sstevel@tonic-gate 
31037c478bd9Sstevel@tonic-gate 		if (sbd_set_err_in_hdl(hp, ep) == 0)
31047c478bd9Sstevel@tonic-gate 			continue;
31057c478bd9Sstevel@tonic-gate 
31067c478bd9Sstevel@tonic-gate 		dip = devlist[i].dv_dip;
31077c478bd9Sstevel@tonic-gate 		nodetype = sbd_get_devtype(hp, dip);
31087c478bd9Sstevel@tonic-gate 		unit = sbdp_get_unit_num(hdp, dip);
31097c478bd9Sstevel@tonic-gate 
31107c478bd9Sstevel@tonic-gate 		if (unit == -1) {
31117c478bd9Sstevel@tonic-gate 			SBD_GET_PERR(hdp->h_err, ep);
31127c478bd9Sstevel@tonic-gate 			continue;
31137c478bd9Sstevel@tonic-gate 		}
31147c478bd9Sstevel@tonic-gate 
31157c478bd9Sstevel@tonic-gate 		unit = sbd_check_unit_attached(sbp, dip, unit, nodetype, ep);
31167c478bd9Sstevel@tonic-gate 
31177c478bd9Sstevel@tonic-gate 		if (unit == -1) {
31187c478bd9Sstevel@tonic-gate 			PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not attached\n",
3119*d5ebc493SDan Cross 			    f, sbd_ct_str[(int)nodetype], sbp->sb_num, i);
31207c478bd9Sstevel@tonic-gate 			continue;
31217c478bd9Sstevel@tonic-gate 		}
31227c478bd9Sstevel@tonic-gate 
31237c478bd9Sstevel@tonic-gate 		SBD_DEV_SET_ATTACHED(sbp, nodetype, unit);
31247c478bd9Sstevel@tonic-gate 		SBD_DEVICE_TRANSITION(sbp, nodetype, unit,
3125*d5ebc493SDan Cross 		    SBD_STATE_CONFIGURED);
31267c478bd9Sstevel@tonic-gate 	}
31277c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
31287c478bd9Sstevel@tonic-gate 
31297c478bd9Sstevel@tonic-gate 	if (rv) {
31307c478bd9Sstevel@tonic-gate 		PR_ALL("%s: errno %d, ecode %d during attach\n",
3131*d5ebc493SDan Cross 		    f, SBD_GET_ERRNO(SBD_HD2ERR(hp)),
3132*d5ebc493SDan Cross 		    SBD_GET_ERR(HD2MACHERR(hp)));
31337c478bd9Sstevel@tonic-gate 	}
31347c478bd9Sstevel@tonic-gate 
31357c478bd9Sstevel@tonic-gate 	devs_present = SBD_DEVS_PRESENT(sbp);
31367c478bd9Sstevel@tonic-gate 	devs_unattached = SBD_DEVS_UNATTACHED(sbp);
31377c478bd9Sstevel@tonic-gate 
31387c478bd9Sstevel@tonic-gate 	switch (SBD_BOARD_STATE(sbp)) {
31397c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONNECTED:
31407c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNCONFIGURED:
31417c478bd9Sstevel@tonic-gate 		ASSERT(devs_present);
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate 		if (devs_unattached == 0) {
31447c478bd9Sstevel@tonic-gate 			/*
31457c478bd9Sstevel@tonic-gate 			 * All devices finally attached.
31467c478bd9Sstevel@tonic-gate 			 */
31477c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED);
31487c478bd9Sstevel@tonic-gate 			sbp->sb_rstate = SBD_STAT_CONNECTED;
31497c478bd9Sstevel@tonic-gate 			sbp->sb_ostate = SBD_STAT_CONFIGURED;
31507c478bd9Sstevel@tonic-gate 		} else if (devs_present != devs_unattached) {
31517c478bd9Sstevel@tonic-gate 			/*
31527c478bd9Sstevel@tonic-gate 			 * Only some devices are fully attached.
31537c478bd9Sstevel@tonic-gate 			 */
31547c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL);
31557c478bd9Sstevel@tonic-gate 			sbp->sb_rstate = SBD_STAT_CONNECTED;
31567c478bd9Sstevel@tonic-gate 			sbp->sb_ostate = SBD_STAT_UNCONFIGURED;
31577c478bd9Sstevel@tonic-gate 		}
31587c478bd9Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&sbp->sb_time);
31597c478bd9Sstevel@tonic-gate 		break;
31607c478bd9Sstevel@tonic-gate 
31617c478bd9Sstevel@tonic-gate 	case SBD_STATE_PARTIAL:
31627c478bd9Sstevel@tonic-gate 		ASSERT(devs_present);
31637c478bd9Sstevel@tonic-gate 		/*
31647c478bd9Sstevel@tonic-gate 		 * All devices finally attached.
31657c478bd9Sstevel@tonic-gate 		 */
31667c478bd9Sstevel@tonic-gate 		if (devs_unattached == 0) {
31677c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED);
31687c478bd9Sstevel@tonic-gate 			sbp->sb_rstate = SBD_STAT_CONNECTED;
31697c478bd9Sstevel@tonic-gate 			sbp->sb_ostate = SBD_STAT_CONFIGURED;
31707c478bd9Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&sbp->sb_time);
31717c478bd9Sstevel@tonic-gate 		}
31727c478bd9Sstevel@tonic-gate 		break;
31737c478bd9Sstevel@tonic-gate 
31747c478bd9Sstevel@tonic-gate 	default:
31757c478bd9Sstevel@tonic-gate 		break;
31767c478bd9Sstevel@tonic-gate 	}
31777c478bd9Sstevel@tonic-gate 
31787c478bd9Sstevel@tonic-gate 	if (max_units && devlist) {
31797c478bd9Sstevel@tonic-gate 		int	i;
31807c478bd9Sstevel@tonic-gate 
31817c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_units; i++) {
31827c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERRSTR(&devlist[i].dv_error)) {
31837c478bd9Sstevel@tonic-gate 				SBD_FREE_ERR(&devlist[i].dv_error);
31847c478bd9Sstevel@tonic-gate 			} else {
31857c478bd9Sstevel@tonic-gate 				break;
31867c478bd9Sstevel@tonic-gate 			}
31877c478bd9Sstevel@tonic-gate 		}
31887c478bd9Sstevel@tonic-gate 		FREESTRUCT(devlist, sbd_devlist_t, max_units);
31897c478bd9Sstevel@tonic-gate 	}
31907c478bd9Sstevel@tonic-gate 
31917c478bd9Sstevel@tonic-gate 	/*
31927c478bd9Sstevel@tonic-gate 	 * Our policy is to attach all components that are
31937c478bd9Sstevel@tonic-gate 	 * possible, thus we always return "success" on the
31947c478bd9Sstevel@tonic-gate 	 * pre and post operations.
31957c478bd9Sstevel@tonic-gate 	 */
31967c478bd9Sstevel@tonic-gate 	return (0);
31977c478bd9Sstevel@tonic-gate }
31987c478bd9Sstevel@tonic-gate 
31997c478bd9Sstevel@tonic-gate /*
32007c478bd9Sstevel@tonic-gate  * We only need to "release" cpu and memory devices.
32017c478bd9Sstevel@tonic-gate  */
32027c478bd9Sstevel@tonic-gate static sbd_devlist_t *
sbd_get_release_devlist(sbd_handle_t * hp,int32_t * devnump,int32_t pass)32037c478bd9Sstevel@tonic-gate sbd_get_release_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass)
32047c478bd9Sstevel@tonic-gate {
32057c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
32067c478bd9Sstevel@tonic-gate 	uint_t		uset;
32077c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
32087c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*release_devlist;
32097c478bd9Sstevel@tonic-gate 	static int	next_pass = 1;
32107c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_get_release_devlist";
32117c478bd9Sstevel@tonic-gate 
32127c478bd9Sstevel@tonic-gate 	PR_ALL("%s (pass = %d)...\n", f, pass);
32137c478bd9Sstevel@tonic-gate 
32147c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
32157c478bd9Sstevel@tonic-gate 	devset = HD2MACHHD(hp)->sh_devset;
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate 	*devnump = 0;
32187c478bd9Sstevel@tonic-gate 	release_devlist = NULL;
32197c478bd9Sstevel@tonic-gate 
32207c478bd9Sstevel@tonic-gate 	/*
32217c478bd9Sstevel@tonic-gate 	 * We switch on next_pass for the cases where a board
32227c478bd9Sstevel@tonic-gate 	 * does not contain a particular type of component.
32237c478bd9Sstevel@tonic-gate 	 * In these situations we don't want to return NULL
32247c478bd9Sstevel@tonic-gate 	 * prematurely.  We need to check other devices and
32257c478bd9Sstevel@tonic-gate 	 * we don't want to check the same type multiple times.
32267c478bd9Sstevel@tonic-gate 	 * For example, if there were no cpus, then on pass 1
32277c478bd9Sstevel@tonic-gate 	 * we would drop through and return the memory nodes.
32287c478bd9Sstevel@tonic-gate 	 * However, on pass 2 we would switch back to the memory
32297c478bd9Sstevel@tonic-gate 	 * nodes thereby returning them twice!  Using next_pass
32307c478bd9Sstevel@tonic-gate 	 * forces us down to the end (or next item).
32317c478bd9Sstevel@tonic-gate 	 */
32327c478bd9Sstevel@tonic-gate 	if (pass == 1)
32337c478bd9Sstevel@tonic-gate 		next_pass = 1;
32347c478bd9Sstevel@tonic-gate 
32357c478bd9Sstevel@tonic-gate 	switch (next_pass) {
32367c478bd9Sstevel@tonic-gate 	case 1:
32377c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) {
32387c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM);
32397c478bd9Sstevel@tonic-gate 
32407c478bd9Sstevel@tonic-gate 			release_devlist = sbd_get_devlist(hp, sbp,
3241*d5ebc493SDan Cross 			    SBD_COMP_MEM,
3242*d5ebc493SDan Cross 			    MAX_MEM_UNITS_PER_BOARD,
3243*d5ebc493SDan Cross 			    uset, devnump, 0);
32447c478bd9Sstevel@tonic-gate 
32457c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT);
32467c478bd9Sstevel@tonic-gate 			if (!devset || release_devlist) {
32477c478bd9Sstevel@tonic-gate 				next_pass = 2;
32487c478bd9Sstevel@tonic-gate 				return (release_devlist);
32497c478bd9Sstevel@tonic-gate 			}
32507c478bd9Sstevel@tonic-gate 			/*
32517c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
32527c478bd9Sstevel@tonic-gate 			 * board, but there isn't any memory, then
32537c478bd9Sstevel@tonic-gate 			 * just fall through to next component.
32547c478bd9Sstevel@tonic-gate 			 */
32557c478bd9Sstevel@tonic-gate 		}
32567c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
32577c478bd9Sstevel@tonic-gate 
32587c478bd9Sstevel@tonic-gate 
32597c478bd9Sstevel@tonic-gate 	case 2:
32607c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) {
32617c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU);
32627c478bd9Sstevel@tonic-gate 
32637c478bd9Sstevel@tonic-gate 			release_devlist = sbd_get_devlist(hp, sbp,
3264*d5ebc493SDan Cross 			    SBD_COMP_CPU,
3265*d5ebc493SDan Cross 			    MAX_CPU_UNITS_PER_BOARD,
3266*d5ebc493SDan Cross 			    uset, devnump, 0);
32677c478bd9Sstevel@tonic-gate 
32687c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT);
32697c478bd9Sstevel@tonic-gate 			if (!devset || release_devlist) {
32707c478bd9Sstevel@tonic-gate 				next_pass = 3;
32717c478bd9Sstevel@tonic-gate 				return (release_devlist);
32727c478bd9Sstevel@tonic-gate 			}
32737c478bd9Sstevel@tonic-gate 			/*
32747c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
32757c478bd9Sstevel@tonic-gate 			 * board, but there aren't any cpus, then just
32767c478bd9Sstevel@tonic-gate 			 * fall through to check for the next component.
32777c478bd9Sstevel@tonic-gate 			 */
32787c478bd9Sstevel@tonic-gate 		}
32797c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
32807c478bd9Sstevel@tonic-gate 
32817c478bd9Sstevel@tonic-gate 
32827c478bd9Sstevel@tonic-gate 	case 3:
32837c478bd9Sstevel@tonic-gate 		next_pass = -1;
32847c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) {
32857c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO);
32867c478bd9Sstevel@tonic-gate 
32877c478bd9Sstevel@tonic-gate 			release_devlist = sbd_get_devlist(hp, sbp,
3288*d5ebc493SDan Cross 			    SBD_COMP_IO,
3289*d5ebc493SDan Cross 			    MAX_IO_UNITS_PER_BOARD,
3290*d5ebc493SDan Cross 			    uset, devnump, 0);
32917c478bd9Sstevel@tonic-gate 
32927c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT);
32937c478bd9Sstevel@tonic-gate 			if (!devset || release_devlist) {
32947c478bd9Sstevel@tonic-gate 				next_pass = 4;
32957c478bd9Sstevel@tonic-gate 				return (release_devlist);
32967c478bd9Sstevel@tonic-gate 			}
32977c478bd9Sstevel@tonic-gate 		}
32987c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
32997c478bd9Sstevel@tonic-gate 
33007c478bd9Sstevel@tonic-gate 	default:
33017c478bd9Sstevel@tonic-gate 		*devnump = 0;
33027c478bd9Sstevel@tonic-gate 		return (NULL);
33037c478bd9Sstevel@tonic-gate 	}
33047c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
33057c478bd9Sstevel@tonic-gate }
33067c478bd9Sstevel@tonic-gate 
33077c478bd9Sstevel@tonic-gate static int
sbd_pre_release_devlist(sbd_handle_t * hp,sbd_devlist_t * devlist,int32_t devnum)33087c478bd9Sstevel@tonic-gate sbd_pre_release_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist,
3309*d5ebc493SDan Cross     int32_t devnum)
33107c478bd9Sstevel@tonic-gate {
33117c478bd9Sstevel@tonic-gate 	int		max_units = 0, rv = 0;
33127c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
33137c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_pre_release_devlist";
33147c478bd9Sstevel@tonic-gate 
33157c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
33167c478bd9Sstevel@tonic-gate 
33177c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3318*d5ebc493SDan Cross 	    f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
33197c478bd9Sstevel@tonic-gate 
33207c478bd9Sstevel@tonic-gate 	switch (nodetype) {
33217c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU: {
33227c478bd9Sstevel@tonic-gate 		int			i, mem_present = 0;
33237c478bd9Sstevel@tonic-gate 		sbd_board_t		*sbp = SBDH2BD(hp->h_sbd);
33247c478bd9Sstevel@tonic-gate 		sbd_devset_t		devset;
33257c478bd9Sstevel@tonic-gate 		sbd_priv_handle_t	*shp = HD2MACHHD(hp);
33267c478bd9Sstevel@tonic-gate 
33277c478bd9Sstevel@tonic-gate 		max_units = MAX_CPU_UNITS_PER_BOARD;
33287c478bd9Sstevel@tonic-gate 
33297c478bd9Sstevel@tonic-gate 		devset = shp->sh_orig_devset;
33307c478bd9Sstevel@tonic-gate 
33317c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
33327c478bd9Sstevel@tonic-gate 			/*
33337c478bd9Sstevel@tonic-gate 			 * if client also requested to unconfigure memory
33347c478bd9Sstevel@tonic-gate 			 * the we allow the operation. Therefore
33357c478bd9Sstevel@tonic-gate 			 * we need to warranty that memory gets unconfig
33367c478bd9Sstevel@tonic-gate 			 * before cpus
33377c478bd9Sstevel@tonic-gate 			 */
33387c478bd9Sstevel@tonic-gate 
33397c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) {
33407c478bd9Sstevel@tonic-gate 				continue;
33417c478bd9Sstevel@tonic-gate 			}
33427c478bd9Sstevel@tonic-gate 			if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_MEM, i)) {
33437c478bd9Sstevel@tonic-gate 				mem_present = 1;
33447c478bd9Sstevel@tonic-gate 				break;
33457c478bd9Sstevel@tonic-gate 			}
33467c478bd9Sstevel@tonic-gate 		}
33477c478bd9Sstevel@tonic-gate 		if (mem_present) {
33487c478bd9Sstevel@tonic-gate 			sbderror_t	*ep = SBD_HD2ERR(hp);
33497c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(ep, ESBD_MEMONLINE);
33507c478bd9Sstevel@tonic-gate 			SBD_SET_ERRSTR(ep, sbp->sb_mempath[i]);
33517c478bd9Sstevel@tonic-gate 			rv = -1;
33527c478bd9Sstevel@tonic-gate 		} else {
33537c478bd9Sstevel@tonic-gate 			rv = sbd_pre_release_cpu(hp, devlist, devnum);
33547c478bd9Sstevel@tonic-gate 		}
33557c478bd9Sstevel@tonic-gate 
33567c478bd9Sstevel@tonic-gate 		break;
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate 	}
33597c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
33607c478bd9Sstevel@tonic-gate 		max_units = MAX_MEM_UNITS_PER_BOARD;
33617c478bd9Sstevel@tonic-gate 		rv = sbd_pre_release_mem(hp, devlist, devnum);
33627c478bd9Sstevel@tonic-gate 		break;
33637c478bd9Sstevel@tonic-gate 
33647c478bd9Sstevel@tonic-gate 
33657c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
33667c478bd9Sstevel@tonic-gate 		max_units = MAX_IO_UNITS_PER_BOARD;
33677c478bd9Sstevel@tonic-gate 		rv = sbd_pre_release_io(hp, devlist, devnum);
33687c478bd9Sstevel@tonic-gate 		break;
33697c478bd9Sstevel@tonic-gate 
33707c478bd9Sstevel@tonic-gate 	default:
33717c478bd9Sstevel@tonic-gate 		rv = -1;
33727c478bd9Sstevel@tonic-gate 		break;
33737c478bd9Sstevel@tonic-gate 	}
33747c478bd9Sstevel@tonic-gate 
33757c478bd9Sstevel@tonic-gate 	if (rv && max_units) {
33767c478bd9Sstevel@tonic-gate 		int	i;
33777c478bd9Sstevel@tonic-gate 
33787c478bd9Sstevel@tonic-gate 		/*
33797c478bd9Sstevel@tonic-gate 		 * the individual pre_release component routines should
33807c478bd9Sstevel@tonic-gate 		 * have set the error in the handle.  No need to set it
33817c478bd9Sstevel@tonic-gate 		 * here
33827c478bd9Sstevel@tonic-gate 		 *
33837c478bd9Sstevel@tonic-gate 		 * Need to clean up dynamically allocated devlist
33847c478bd9Sstevel@tonic-gate 		 * if pre-op is going to fail.
33857c478bd9Sstevel@tonic-gate 		 */
33867c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_units; i++) {
33877c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERRSTR(&devlist[i].dv_error)) {
33887c478bd9Sstevel@tonic-gate 				SBD_FREE_ERR(&devlist[i].dv_error);
33897c478bd9Sstevel@tonic-gate 			} else {
33907c478bd9Sstevel@tonic-gate 				break;
33917c478bd9Sstevel@tonic-gate 			}
33927c478bd9Sstevel@tonic-gate 		}
33937c478bd9Sstevel@tonic-gate 		FREESTRUCT(devlist, sbd_devlist_t, max_units);
33947c478bd9Sstevel@tonic-gate 	}
33957c478bd9Sstevel@tonic-gate 
33967c478bd9Sstevel@tonic-gate 	return (rv ? -1 : 0);
33977c478bd9Sstevel@tonic-gate }
33987c478bd9Sstevel@tonic-gate 
33997c478bd9Sstevel@tonic-gate static int
sbd_post_release_devlist(sbd_handle_t * hp,sbd_devlist_t * devlist,int32_t devnum)34007c478bd9Sstevel@tonic-gate sbd_post_release_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist,
3401*d5ebc493SDan Cross     int32_t devnum)
34027c478bd9Sstevel@tonic-gate {
34037c478bd9Sstevel@tonic-gate 	int		i, max_units = 0;
34047c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
34057c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
34067c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
34077c478bd9Sstevel@tonic-gate 	sbd_error_t	*spe;
34087c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_post_release_devlist";
34097c478bd9Sstevel@tonic-gate 
34107c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
34117c478bd9Sstevel@tonic-gate 	ASSERT(nodetype >= SBD_COMP_CPU && nodetype <= SBD_COMP_IO);
34127c478bd9Sstevel@tonic-gate 
34137c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3414*d5ebc493SDan Cross 	    f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
34157c478bd9Sstevel@tonic-gate 
34167c478bd9Sstevel@tonic-gate 	/*
34177c478bd9Sstevel@tonic-gate 	 * Need to free up devlist[] created earlier in
34187c478bd9Sstevel@tonic-gate 	 * sbd_get_release_devlist().
34197c478bd9Sstevel@tonic-gate 	 */
34207c478bd9Sstevel@tonic-gate 	switch (nodetype) {
34217c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
34227c478bd9Sstevel@tonic-gate 		max_units = MAX_CPU_UNITS_PER_BOARD;
34237c478bd9Sstevel@tonic-gate 		break;
34247c478bd9Sstevel@tonic-gate 
34257c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
34267c478bd9Sstevel@tonic-gate 		max_units = MAX_MEM_UNITS_PER_BOARD;
34277c478bd9Sstevel@tonic-gate 		break;
34287c478bd9Sstevel@tonic-gate 
34297c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
34307c478bd9Sstevel@tonic-gate 		/*
34317c478bd9Sstevel@tonic-gate 		 *  Need to check if specific I/O is referenced and
34327c478bd9Sstevel@tonic-gate 		 *  fail post-op.
34337c478bd9Sstevel@tonic-gate 		 */
34347c478bd9Sstevel@tonic-gate 
34357c478bd9Sstevel@tonic-gate 		if (sbd_check_io_refs(hp, devlist, devnum) > 0) {
34367c478bd9Sstevel@tonic-gate 				PR_IO("%s: error - I/O devices ref'd\n", f);
34377c478bd9Sstevel@tonic-gate 		}
34387c478bd9Sstevel@tonic-gate 
34397c478bd9Sstevel@tonic-gate 		max_units = MAX_IO_UNITS_PER_BOARD;
34407c478bd9Sstevel@tonic-gate 		break;
34417c478bd9Sstevel@tonic-gate 
34427c478bd9Sstevel@tonic-gate 	default:
34437c478bd9Sstevel@tonic-gate 		{
34447c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: invalid nodetype (%d)",
3445*d5ebc493SDan Cross 			    f, (int)nodetype);
34467c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(HD2MACHERR(hp), ESBD_INVAL);
34477c478bd9Sstevel@tonic-gate 		}
34487c478bd9Sstevel@tonic-gate 		break;
34497c478bd9Sstevel@tonic-gate 	}
34507c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
34517c478bd9Sstevel@tonic-gate 	spe = hdp->h_err;
34527c478bd9Sstevel@tonic-gate 
34537c478bd9Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
34547c478bd9Sstevel@tonic-gate 		int		unit;
34557c478bd9Sstevel@tonic-gate 		sbderror_t	*ep;
34567c478bd9Sstevel@tonic-gate 
34577c478bd9Sstevel@tonic-gate 		ep = &devlist[i].dv_error;
34587c478bd9Sstevel@tonic-gate 
34597c478bd9Sstevel@tonic-gate 		if (sbd_set_err_in_hdl(hp, ep) == 0) {
34607c478bd9Sstevel@tonic-gate 			continue;
34617c478bd9Sstevel@tonic-gate 		}
34627c478bd9Sstevel@tonic-gate 
34637c478bd9Sstevel@tonic-gate 		unit = sbdp_get_unit_num(hdp, devlist[i].dv_dip);
34647c478bd9Sstevel@tonic-gate 		if (unit == -1) {
34657c478bd9Sstevel@tonic-gate 			SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
34667c478bd9Sstevel@tonic-gate 			PR_ALL("%s bad unit num: %d code %d",
34677c478bd9Sstevel@tonic-gate 			    f, unit, spe->e_code);
34687c478bd9Sstevel@tonic-gate 			continue;
34697c478bd9Sstevel@tonic-gate 		}
34707c478bd9Sstevel@tonic-gate 	}
34717c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
34727c478bd9Sstevel@tonic-gate 
34737c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERRNO(SBD_HD2ERR(hp))) {
34747c478bd9Sstevel@tonic-gate 		PR_ALL("%s: errno %d, ecode %d during release\n",
3475*d5ebc493SDan Cross 		    f, SBD_GET_ERRNO(SBD_HD2ERR(hp)),
3476*d5ebc493SDan Cross 		    SBD_GET_ERR(SBD_HD2ERR(hp)));
34777c478bd9Sstevel@tonic-gate 	}
34787c478bd9Sstevel@tonic-gate 
34797c478bd9Sstevel@tonic-gate 	if (max_units && devlist) {
34807c478bd9Sstevel@tonic-gate 		int	i;
34817c478bd9Sstevel@tonic-gate 
34827c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_units; i++) {
34837c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERRSTR(&devlist[i].dv_error)) {
34847c478bd9Sstevel@tonic-gate 				SBD_FREE_ERR(&devlist[i].dv_error);
34857c478bd9Sstevel@tonic-gate 			} else {
34867c478bd9Sstevel@tonic-gate 				break;
34877c478bd9Sstevel@tonic-gate 			}
34887c478bd9Sstevel@tonic-gate 		}
34897c478bd9Sstevel@tonic-gate 		FREESTRUCT(devlist, sbd_devlist_t, max_units);
34907c478bd9Sstevel@tonic-gate 	}
34917c478bd9Sstevel@tonic-gate 
34927c478bd9Sstevel@tonic-gate 	return (SBD_GET_ERRNO(SBD_HD2ERR(hp)) ? -1 : 0);
34937c478bd9Sstevel@tonic-gate }
34947c478bd9Sstevel@tonic-gate 
34957c478bd9Sstevel@tonic-gate static void
sbd_release_dev_done(sbd_board_t * sbp,sbd_comp_type_t nodetype,int unit)34967c478bd9Sstevel@tonic-gate sbd_release_dev_done(sbd_board_t *sbp, sbd_comp_type_t nodetype, int unit)
34977c478bd9Sstevel@tonic-gate {
34987c478bd9Sstevel@tonic-gate 	SBD_DEV_SET_UNREFERENCED(sbp, nodetype, unit);
34997c478bd9Sstevel@tonic-gate 	SBD_DEVICE_TRANSITION(sbp, nodetype, unit, SBD_STATE_UNREFERENCED);
35007c478bd9Sstevel@tonic-gate }
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate static void
sbd_release_done(sbd_handle_t * hp,sbd_comp_type_t nodetype,dev_info_t * dip)35037c478bd9Sstevel@tonic-gate sbd_release_done(sbd_handle_t *hp, sbd_comp_type_t nodetype, dev_info_t *dip)
35047c478bd9Sstevel@tonic-gate {
35057c478bd9Sstevel@tonic-gate 	int		unit;
35067c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
35077c478bd9Sstevel@tonic-gate 	sbderror_t	*ep;
35087c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_release_done";
35097c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
35107c478bd9Sstevel@tonic-gate 
35117c478bd9Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
35127c478bd9Sstevel@tonic-gate 
35137c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
35147c478bd9Sstevel@tonic-gate 	ep = SBD_HD2ERR(hp);
35157c478bd9Sstevel@tonic-gate 
35167c478bd9Sstevel@tonic-gate 	if ((unit = sbdp_get_unit_num(hdp, dip)) < 0) {
35177c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
3518*d5ebc493SDan Cross 		    "sbd:%s: unable to get unit for dip (0x%p)",
3519*d5ebc493SDan Cross 		    f, (void *)dip);
35207c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
35217c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
35227c478bd9Sstevel@tonic-gate 		return;
35237c478bd9Sstevel@tonic-gate 	}
35247c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
35257c478bd9Sstevel@tonic-gate 
35267c478bd9Sstevel@tonic-gate 	/*
35277c478bd9Sstevel@tonic-gate 	 * Transfer the device which just completed its release
35287c478bd9Sstevel@tonic-gate 	 * to the UNREFERENCED state.
35297c478bd9Sstevel@tonic-gate 	 */
35307c478bd9Sstevel@tonic-gate 	switch (nodetype) {
35317c478bd9Sstevel@tonic-gate 
35327c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
35337c478bd9Sstevel@tonic-gate 		sbd_release_mem_done((void *)hp, unit);
35347c478bd9Sstevel@tonic-gate 		break;
35357c478bd9Sstevel@tonic-gate 
35367c478bd9Sstevel@tonic-gate 	default:
35377c478bd9Sstevel@tonic-gate 		sbd_release_dev_done(sbp, nodetype, unit);
35387c478bd9Sstevel@tonic-gate 		break;
35397c478bd9Sstevel@tonic-gate 	}
35407c478bd9Sstevel@tonic-gate 
35417c478bd9Sstevel@tonic-gate 	/*
35427c478bd9Sstevel@tonic-gate 	 * If the entire board was released and all components
35437c478bd9Sstevel@tonic-gate 	 * unreferenced then transfer it to the UNREFERENCED state.
35447c478bd9Sstevel@tonic-gate 	 */
35457c478bd9Sstevel@tonic-gate 	if (SBD_DEVS_RELEASED(sbp) == SBD_DEVS_UNREFERENCED(sbp)) {
35467c478bd9Sstevel@tonic-gate 		SBD_BOARD_TRANSITION(sbp, SBD_STATE_UNREFERENCED);
35477c478bd9Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&sbp->sb_time);
35487c478bd9Sstevel@tonic-gate 	}
35497c478bd9Sstevel@tonic-gate }
35507c478bd9Sstevel@tonic-gate 
35517c478bd9Sstevel@tonic-gate static sbd_devlist_t *
sbd_get_detach_devlist(sbd_handle_t * hp,int32_t * devnump,int32_t pass)35527c478bd9Sstevel@tonic-gate sbd_get_detach_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass)
35537c478bd9Sstevel@tonic-gate {
35547c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
35557c478bd9Sstevel@tonic-gate 	uint_t		uset;
35567c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
35577c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*detach_devlist;
35587c478bd9Sstevel@tonic-gate 	static int	next_pass = 1;
35597c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_get_detach_devlist";
35607c478bd9Sstevel@tonic-gate 
35617c478bd9Sstevel@tonic-gate 	PR_ALL("%s (pass = %d)...\n", f, pass);
35627c478bd9Sstevel@tonic-gate 
35637c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
35647c478bd9Sstevel@tonic-gate 	devset = HD2MACHHD(hp)->sh_devset;
35657c478bd9Sstevel@tonic-gate 
35667c478bd9Sstevel@tonic-gate 	*devnump = 0;
35677c478bd9Sstevel@tonic-gate 	detach_devlist = NULL;
35687c478bd9Sstevel@tonic-gate 
35697c478bd9Sstevel@tonic-gate 	/*
35707c478bd9Sstevel@tonic-gate 	 * We switch on next_pass for the cases where a board
35717c478bd9Sstevel@tonic-gate 	 * does not contain a particular type of component.
35727c478bd9Sstevel@tonic-gate 	 * In these situations we don't want to return NULL
35737c478bd9Sstevel@tonic-gate 	 * prematurely.  We need to check other devices and
35747c478bd9Sstevel@tonic-gate 	 * we don't want to check the same type multiple times.
35757c478bd9Sstevel@tonic-gate 	 * For example, if there were no cpus, then on pass 1
35767c478bd9Sstevel@tonic-gate 	 * we would drop through and return the memory nodes.
35777c478bd9Sstevel@tonic-gate 	 * However, on pass 2 we would switch back to the memory
35787c478bd9Sstevel@tonic-gate 	 * nodes thereby returning them twice!  Using next_pass
35797c478bd9Sstevel@tonic-gate 	 * forces us down to the end (or next item).
35807c478bd9Sstevel@tonic-gate 	 */
35817c478bd9Sstevel@tonic-gate 	if (pass == 1)
35827c478bd9Sstevel@tonic-gate 		next_pass = 1;
35837c478bd9Sstevel@tonic-gate 
35847c478bd9Sstevel@tonic-gate 	switch (next_pass) {
35857c478bd9Sstevel@tonic-gate 	case 1:
35867c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) {
35877c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM);
35887c478bd9Sstevel@tonic-gate 
35897c478bd9Sstevel@tonic-gate 			detach_devlist = sbd_get_devlist(hp, sbp,
3590*d5ebc493SDan Cross 			    SBD_COMP_MEM,
3591*d5ebc493SDan Cross 			    MAX_MEM_UNITS_PER_BOARD,
3592*d5ebc493SDan Cross 			    uset, devnump, 0);
35937c478bd9Sstevel@tonic-gate 
35947c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT);
35957c478bd9Sstevel@tonic-gate 			if (!devset || detach_devlist) {
35967c478bd9Sstevel@tonic-gate 				next_pass = 2;
35977c478bd9Sstevel@tonic-gate 				return (detach_devlist);
35987c478bd9Sstevel@tonic-gate 			}
35997c478bd9Sstevel@tonic-gate 			/*
36007c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
36017c478bd9Sstevel@tonic-gate 			 * board, but there isn't any memory, then
36027c478bd9Sstevel@tonic-gate 			 * just fall through to next component.
36037c478bd9Sstevel@tonic-gate 			 */
36047c478bd9Sstevel@tonic-gate 		}
36057c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
36067c478bd9Sstevel@tonic-gate 
36077c478bd9Sstevel@tonic-gate 	case 2:
36087c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) {
36097c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU);
36107c478bd9Sstevel@tonic-gate 
36117c478bd9Sstevel@tonic-gate 			detach_devlist = sbd_get_devlist(hp, sbp,
3612*d5ebc493SDan Cross 			    SBD_COMP_CPU,
3613*d5ebc493SDan Cross 			    MAX_CPU_UNITS_PER_BOARD,
3614*d5ebc493SDan Cross 			    uset, devnump, 0);
36157c478bd9Sstevel@tonic-gate 
36167c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT);
36177c478bd9Sstevel@tonic-gate 			if (!devset || detach_devlist) {
36187c478bd9Sstevel@tonic-gate 				next_pass = 2;
36197c478bd9Sstevel@tonic-gate 				return (detach_devlist);
36207c478bd9Sstevel@tonic-gate 			}
36217c478bd9Sstevel@tonic-gate 			/*
36227c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
36237c478bd9Sstevel@tonic-gate 			 * board, but there aren't any cpus, then just
36247c478bd9Sstevel@tonic-gate 			 * fall through to check for the next component.
36257c478bd9Sstevel@tonic-gate 			 */
36267c478bd9Sstevel@tonic-gate 		}
36277c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
36287c478bd9Sstevel@tonic-gate 
36297c478bd9Sstevel@tonic-gate 	case 3:
36307c478bd9Sstevel@tonic-gate 		next_pass = -1;
36317c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) {
36327c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO);
36337c478bd9Sstevel@tonic-gate 
36347c478bd9Sstevel@tonic-gate 			detach_devlist = sbd_get_devlist(hp, sbp,
3635*d5ebc493SDan Cross 			    SBD_COMP_IO,
3636*d5ebc493SDan Cross 			    MAX_IO_UNITS_PER_BOARD,
3637*d5ebc493SDan Cross 			    uset, devnump, 0);
36387c478bd9Sstevel@tonic-gate 
36397c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT);
36407c478bd9Sstevel@tonic-gate 			if (!devset || detach_devlist) {
36417c478bd9Sstevel@tonic-gate 				next_pass = 4;
36427c478bd9Sstevel@tonic-gate 				return (detach_devlist);
36437c478bd9Sstevel@tonic-gate 			}
36447c478bd9Sstevel@tonic-gate 		}
36457c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
36467c478bd9Sstevel@tonic-gate 
36477c478bd9Sstevel@tonic-gate 	default:
36487c478bd9Sstevel@tonic-gate 		*devnump = 0;
36497c478bd9Sstevel@tonic-gate 		return (NULL);
36507c478bd9Sstevel@tonic-gate 	}
36517c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
36527c478bd9Sstevel@tonic-gate }
36537c478bd9Sstevel@tonic-gate 
36547c478bd9Sstevel@tonic-gate static int
sbd_pre_detach_devlist(sbd_handle_t * hp,sbd_devlist_t * devlist,int32_t devnum)3655*d5ebc493SDan Cross sbd_pre_detach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, int32_t devnum)
36567c478bd9Sstevel@tonic-gate {
36577c478bd9Sstevel@tonic-gate 	int		rv = 0;
36587c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
36597c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_pre_detach_devlist";
36607c478bd9Sstevel@tonic-gate 
36617c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
36627c478bd9Sstevel@tonic-gate 
36637c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3664*d5ebc493SDan Cross 	    f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
36657c478bd9Sstevel@tonic-gate 
36667c478bd9Sstevel@tonic-gate 	switch (nodetype) {
36677c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
36687c478bd9Sstevel@tonic-gate 		rv = sbd_pre_detach_cpu(hp, devlist, devnum);
36697c478bd9Sstevel@tonic-gate 		break;
36707c478bd9Sstevel@tonic-gate 
36717c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
36727c478bd9Sstevel@tonic-gate 		rv = sbd_pre_detach_mem(hp, devlist, devnum);
36737c478bd9Sstevel@tonic-gate 		break;
36747c478bd9Sstevel@tonic-gate 
36757c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
36767c478bd9Sstevel@tonic-gate 		rv = sbd_pre_detach_io(hp, devlist, devnum);
36777c478bd9Sstevel@tonic-gate 		break;
36787c478bd9Sstevel@tonic-gate 
36797c478bd9Sstevel@tonic-gate 	default:
36807c478bd9Sstevel@tonic-gate 		rv = -1;
36817c478bd9Sstevel@tonic-gate 		break;
36827c478bd9Sstevel@tonic-gate 	}
36837c478bd9Sstevel@tonic-gate 
36847c478bd9Sstevel@tonic-gate 	/*
36857c478bd9Sstevel@tonic-gate 	 * We want to continue attempting to detach
36867c478bd9Sstevel@tonic-gate 	 * other components.
36877c478bd9Sstevel@tonic-gate 	 */
36887c478bd9Sstevel@tonic-gate 	return (rv);
36897c478bd9Sstevel@tonic-gate }
36907c478bd9Sstevel@tonic-gate 
36917c478bd9Sstevel@tonic-gate static int
sbd_post_detach_devlist(sbd_handle_t * hp,sbd_devlist_t * devlist,int32_t devnum)36927c478bd9Sstevel@tonic-gate sbd_post_detach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist,
3693*d5ebc493SDan Cross     int32_t devnum)
36947c478bd9Sstevel@tonic-gate {
36957c478bd9Sstevel@tonic-gate 	int		i, max_units = 0, rv = 0;
36967c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
36977c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
36987c478bd9Sstevel@tonic-gate 	sbd_istate_t	bstate;
36997c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_post_detach_devlist";
37007c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
37017c478bd9Sstevel@tonic-gate 
37027c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
37037c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
37047c478bd9Sstevel@tonic-gate 
37057c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
37067c478bd9Sstevel@tonic-gate 
37077c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3708*d5ebc493SDan Cross 	    f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
37097c478bd9Sstevel@tonic-gate 
37107c478bd9Sstevel@tonic-gate 	/*
37117c478bd9Sstevel@tonic-gate 	 * Need to free up devlist[] created earlier in
37127c478bd9Sstevel@tonic-gate 	 * sbd_get_detach_devlist().
37137c478bd9Sstevel@tonic-gate 	 */
37147c478bd9Sstevel@tonic-gate 	switch (nodetype) {
37157c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
37167c478bd9Sstevel@tonic-gate 		max_units = MAX_CPU_UNITS_PER_BOARD;
37177c478bd9Sstevel@tonic-gate 		rv = sbd_post_detach_cpu(hp, devlist, devnum);
37187c478bd9Sstevel@tonic-gate 		break;
37197c478bd9Sstevel@tonic-gate 
37207c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
37217c478bd9Sstevel@tonic-gate 		max_units = MAX_MEM_UNITS_PER_BOARD;
37227c478bd9Sstevel@tonic-gate 		rv = sbd_post_detach_mem(hp, devlist, devnum);
37237c478bd9Sstevel@tonic-gate 		break;
37247c478bd9Sstevel@tonic-gate 
37257c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
37267c478bd9Sstevel@tonic-gate 		max_units = MAX_IO_UNITS_PER_BOARD;
37277c478bd9Sstevel@tonic-gate 		rv = sbd_post_detach_io(hp, devlist, devnum);
37287c478bd9Sstevel@tonic-gate 		break;
37297c478bd9Sstevel@tonic-gate 
37307c478bd9Sstevel@tonic-gate 	default:
37317c478bd9Sstevel@tonic-gate 		rv = -1;
37327c478bd9Sstevel@tonic-gate 		break;
37337c478bd9Sstevel@tonic-gate 	}
37347c478bd9Sstevel@tonic-gate 
37357c478bd9Sstevel@tonic-gate 
37367c478bd9Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
37377c478bd9Sstevel@tonic-gate 		int		unit;
37387c478bd9Sstevel@tonic-gate 		sbderror_t	*ep;
37397c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
37407c478bd9Sstevel@tonic-gate 
37417c478bd9Sstevel@tonic-gate 		ep = &devlist[i].dv_error;
37427c478bd9Sstevel@tonic-gate 
37437c478bd9Sstevel@tonic-gate 		if (sbd_set_err_in_hdl(hp, ep) == 0)
37447c478bd9Sstevel@tonic-gate 			continue;
37457c478bd9Sstevel@tonic-gate 
37467c478bd9Sstevel@tonic-gate 		dip = devlist[i].dv_dip;
37477c478bd9Sstevel@tonic-gate 		unit = sbdp_get_unit_num(hdp, dip);
37487c478bd9Sstevel@tonic-gate 		if (unit == -1) {
37497c478bd9Sstevel@tonic-gate 			if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
37507c478bd9Sstevel@tonic-gate 				continue;
37517c478bd9Sstevel@tonic-gate 			else {
37527c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, ep);
37537c478bd9Sstevel@tonic-gate 				break;
37547c478bd9Sstevel@tonic-gate 			}
37557c478bd9Sstevel@tonic-gate 		}
37567c478bd9Sstevel@tonic-gate 		nodetype = sbd_get_devtype(hp, dip);
37577c478bd9Sstevel@tonic-gate 
37587c478bd9Sstevel@tonic-gate 		if (sbd_check_unit_attached(sbp, dip, unit, nodetype,
37597c478bd9Sstevel@tonic-gate 		    ep) >= 0) {
37607c478bd9Sstevel@tonic-gate 			/*
37617c478bd9Sstevel@tonic-gate 			 * Device is still attached probably due
37627c478bd9Sstevel@tonic-gate 			 * to an error.  Need to keep track of it.
37637c478bd9Sstevel@tonic-gate 			 */
37647c478bd9Sstevel@tonic-gate 			PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not detached\n",
3765*d5ebc493SDan Cross 			    f, sbd_ct_str[(int)nodetype], sbp->sb_num,
3766*d5ebc493SDan Cross 			    unit);
37677c478bd9Sstevel@tonic-gate 			continue;
37687c478bd9Sstevel@tonic-gate 		}
37697c478bd9Sstevel@tonic-gate 
37707c478bd9Sstevel@tonic-gate 		SBD_DEV_CLR_ATTACHED(sbp, nodetype, unit);
37717c478bd9Sstevel@tonic-gate 		SBD_DEV_CLR_RELEASED(sbp, nodetype, unit);
37727c478bd9Sstevel@tonic-gate 		SBD_DEV_CLR_UNREFERENCED(sbp, nodetype, unit);
37737c478bd9Sstevel@tonic-gate 		SBD_DEVICE_TRANSITION(sbp, nodetype, unit,
3774*d5ebc493SDan Cross 		    SBD_STATE_UNCONFIGURED);
37757c478bd9Sstevel@tonic-gate 	}
37767c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
37777c478bd9Sstevel@tonic-gate 
37787c478bd9Sstevel@tonic-gate 	bstate = SBD_BOARD_STATE(sbp);
37797c478bd9Sstevel@tonic-gate 	if (bstate != SBD_STATE_UNCONFIGURED) {
37807c478bd9Sstevel@tonic-gate 		if (SBD_DEVS_PRESENT(sbp) == SBD_DEVS_UNATTACHED(sbp)) {
37817c478bd9Sstevel@tonic-gate 			/*
37827c478bd9Sstevel@tonic-gate 			 * All devices are finally detached.
37837c478bd9Sstevel@tonic-gate 			 */
37847c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_UNCONFIGURED);
37857c478bd9Sstevel@tonic-gate 		} else if ((SBD_BOARD_STATE(sbp) != SBD_STATE_PARTIAL) &&
3786*d5ebc493SDan Cross 		    SBD_DEVS_ATTACHED(sbp)) {
37877c478bd9Sstevel@tonic-gate 			/*
37887c478bd9Sstevel@tonic-gate 			 * Some devices remain attached.
37897c478bd9Sstevel@tonic-gate 			 */
37907c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL);
37917c478bd9Sstevel@tonic-gate 		}
37927c478bd9Sstevel@tonic-gate 	}
37937c478bd9Sstevel@tonic-gate 
37947c478bd9Sstevel@tonic-gate 	if (rv) {
37957c478bd9Sstevel@tonic-gate 		PR_ALL("%s: errno %d, ecode %d during detach\n",
3796*d5ebc493SDan Cross 		    f, SBD_GET_ERRNO(SBD_HD2ERR(hp)),
3797*d5ebc493SDan Cross 		    SBD_GET_ERR(HD2MACHERR(hp)));
37987c478bd9Sstevel@tonic-gate 	}
37997c478bd9Sstevel@tonic-gate 
38007c478bd9Sstevel@tonic-gate 	if (max_units && devlist) {
38017c478bd9Sstevel@tonic-gate 		int	i;
38027c478bd9Sstevel@tonic-gate 
38037c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_units; i++) {
38047c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERRSTR(&devlist[i].dv_error)) {
38057c478bd9Sstevel@tonic-gate 				SBD_FREE_ERR(&devlist[i].dv_error);
38067c478bd9Sstevel@tonic-gate 			} else {
38077c478bd9Sstevel@tonic-gate 				break;
38087c478bd9Sstevel@tonic-gate 			}
38097c478bd9Sstevel@tonic-gate 		}
38107c478bd9Sstevel@tonic-gate 		FREESTRUCT(devlist, sbd_devlist_t, max_units);
38117c478bd9Sstevel@tonic-gate 	}
38127c478bd9Sstevel@tonic-gate 
38137c478bd9Sstevel@tonic-gate 	return (SBD_GET_ERRNO(SBD_HD2ERR(hp)) ? -1 : 0);
38147c478bd9Sstevel@tonic-gate }
38157c478bd9Sstevel@tonic-gate 
38167c478bd9Sstevel@tonic-gate /*
38177c478bd9Sstevel@tonic-gate  * Return the unit number of the respective dip if
38187c478bd9Sstevel@tonic-gate  * it's found to be attached.
38197c478bd9Sstevel@tonic-gate  */
38207c478bd9Sstevel@tonic-gate static int
sbd_check_unit_attached(sbd_board_t * sbp,dev_info_t * dip,int unit,sbd_comp_type_t nodetype,sbderror_t * ep)38217c478bd9Sstevel@tonic-gate sbd_check_unit_attached(sbd_board_t *sbp, dev_info_t *dip, int unit,
3822*d5ebc493SDan Cross     sbd_comp_type_t nodetype, sbderror_t *ep)
38237c478bd9Sstevel@tonic-gate {
38247c478bd9Sstevel@tonic-gate 	int		rv = -1;
38257c478bd9Sstevel@tonic-gate 	processorid_t	cpuid;
38267c478bd9Sstevel@tonic-gate 	uint64_t	basepa, endpa;
38277c478bd9Sstevel@tonic-gate 	struct memlist	*ml;
38287c478bd9Sstevel@tonic-gate 	extern struct memlist	*phys_install;
38297c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
38307c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp = MACHBD2HD(sbp);
38317c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_check_unit_attached";
38327c478bd9Sstevel@tonic-gate 
38337c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
38347c478bd9Sstevel@tonic-gate 
38357c478bd9Sstevel@tonic-gate 	switch (nodetype) {
38367c478bd9Sstevel@tonic-gate 
38377c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
38387c478bd9Sstevel@tonic-gate 		cpuid = sbdp_get_cpuid(hdp, dip);
38397c478bd9Sstevel@tonic-gate 		if (cpuid < 0) {
38407c478bd9Sstevel@tonic-gate 			break;
38417c478bd9Sstevel@tonic-gate 		}
38427c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
38437c478bd9Sstevel@tonic-gate 		if (cpu_get(cpuid) != NULL)
38447c478bd9Sstevel@tonic-gate 			rv = unit;
38457c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
38467c478bd9Sstevel@tonic-gate 		break;
38477c478bd9Sstevel@tonic-gate 
38487c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
38497c478bd9Sstevel@tonic-gate 		if (sbdphw_get_base_physaddr(hdp, dip, &basepa)) {
38507c478bd9Sstevel@tonic-gate 			break;
38517c478bd9Sstevel@tonic-gate 		}
38527c478bd9Sstevel@tonic-gate 		if (sbdp_get_mem_alignment(hdp, dip, &endpa)) {
38537c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s sbdp_get_mem_alignment fail", f);
38547c478bd9Sstevel@tonic-gate 			break;
38557c478bd9Sstevel@tonic-gate 		}
38567c478bd9Sstevel@tonic-gate 
38577c478bd9Sstevel@tonic-gate 		basepa &= ~(endpa - 1);
38587c478bd9Sstevel@tonic-gate 		endpa += basepa;
38597c478bd9Sstevel@tonic-gate 		/*
38607c478bd9Sstevel@tonic-gate 		 * Check if base address is in phys_install.
38617c478bd9Sstevel@tonic-gate 		 */
38627c478bd9Sstevel@tonic-gate 		memlist_read_lock();
386356f33205SJonathan Adams 		for (ml = phys_install; ml; ml = ml->ml_next)
386456f33205SJonathan Adams 			if ((endpa <= ml->ml_address) ||
386556f33205SJonathan Adams 			    (basepa >= (ml->ml_address + ml->ml_size)))
38667c478bd9Sstevel@tonic-gate 				continue;
38677c478bd9Sstevel@tonic-gate 			else
38687c478bd9Sstevel@tonic-gate 				break;
38697c478bd9Sstevel@tonic-gate 		memlist_read_unlock();
38707c478bd9Sstevel@tonic-gate 		if (ml != NULL)
38717c478bd9Sstevel@tonic-gate 			rv = unit;
38727c478bd9Sstevel@tonic-gate 		break;
38737c478bd9Sstevel@tonic-gate 
38747c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
38757c478bd9Sstevel@tonic-gate 	{
38767c478bd9Sstevel@tonic-gate 		dev_info_t	*tdip, *pdip;
38777c478bd9Sstevel@tonic-gate 
38787c478bd9Sstevel@tonic-gate 		tdip = dip;
38797c478bd9Sstevel@tonic-gate 
38807c478bd9Sstevel@tonic-gate 		/*
38817c478bd9Sstevel@tonic-gate 		 * ddi_walk_devs() requires that topdip's parent be held.
38827c478bd9Sstevel@tonic-gate 		 */
38837c478bd9Sstevel@tonic-gate 		pdip = ddi_get_parent(sbp->sb_topdip);
38847c478bd9Sstevel@tonic-gate 		if (pdip) {
38857c478bd9Sstevel@tonic-gate 			ndi_hold_devi(pdip);
38863fe80ca4SDan Cross 			ndi_devi_enter(pdip);
38877c478bd9Sstevel@tonic-gate 		}
38887c478bd9Sstevel@tonic-gate 		ddi_walk_devs(sbp->sb_topdip, sbd_check_io_attached,
3889*d5ebc493SDan Cross 		    (void *)&tdip);
38907c478bd9Sstevel@tonic-gate 		if (pdip) {
38913fe80ca4SDan Cross 			ndi_devi_exit(pdip);
38927c478bd9Sstevel@tonic-gate 			ndi_rele_devi(pdip);
38937c478bd9Sstevel@tonic-gate 		}
38947c478bd9Sstevel@tonic-gate 
38957c478bd9Sstevel@tonic-gate 		if (tdip == NULL)
38967c478bd9Sstevel@tonic-gate 			rv = unit;
38977c478bd9Sstevel@tonic-gate 		else
38987c478bd9Sstevel@tonic-gate 			rv = -1;
38997c478bd9Sstevel@tonic-gate 		break;
39007c478bd9Sstevel@tonic-gate 	}
39017c478bd9Sstevel@tonic-gate 
39027c478bd9Sstevel@tonic-gate 	default:
39037c478bd9Sstevel@tonic-gate 		PR_ALL("%s: unexpected nodetype(%d) for dip 0x%p\n",
3904*d5ebc493SDan Cross 		    f, nodetype, (void *)dip);
39057c478bd9Sstevel@tonic-gate 		rv = -1;
39067c478bd9Sstevel@tonic-gate 		break;
39077c478bd9Sstevel@tonic-gate 	}
39087c478bd9Sstevel@tonic-gate 
39097c478bd9Sstevel@tonic-gate 	/*
39107c478bd9Sstevel@tonic-gate 	 * Save the error that sbdp sent us and report it
39117c478bd9Sstevel@tonic-gate 	 */
39127c478bd9Sstevel@tonic-gate 	if (rv == -1)
39137c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
39147c478bd9Sstevel@tonic-gate 
39157c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
39167c478bd9Sstevel@tonic-gate 
39177c478bd9Sstevel@tonic-gate 	return (rv);
39187c478bd9Sstevel@tonic-gate }
39197c478bd9Sstevel@tonic-gate 
39207c478bd9Sstevel@tonic-gate /*
39217c478bd9Sstevel@tonic-gate  * Return memhandle, if in fact, this memunit is the owner of
39227c478bd9Sstevel@tonic-gate  * a scheduled memory delete.
39237c478bd9Sstevel@tonic-gate  */
39247c478bd9Sstevel@tonic-gate int
sbd_get_memhandle(sbd_handle_t * hp,dev_info_t * dip,memhandle_t * mhp)39257c478bd9Sstevel@tonic-gate sbd_get_memhandle(sbd_handle_t *hp, dev_info_t *dip, memhandle_t *mhp)
39267c478bd9Sstevel@tonic-gate {
39277c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
39287c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
39297c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
39307c478bd9Sstevel@tonic-gate 	int		unit;
39317c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_get_memhandle";
39327c478bd9Sstevel@tonic-gate 
39337c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
39347c478bd9Sstevel@tonic-gate 
39357c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
39367c478bd9Sstevel@tonic-gate 
39377c478bd9Sstevel@tonic-gate 	unit = sbdp_get_unit_num(hdp, dip);
39387c478bd9Sstevel@tonic-gate 	if (unit == -1) {
39397c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
39407c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
39417c478bd9Sstevel@tonic-gate 		return (-1);
39427c478bd9Sstevel@tonic-gate 	}
39437c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
39447c478bd9Sstevel@tonic-gate 
39457c478bd9Sstevel@tonic-gate 	mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
39467c478bd9Sstevel@tonic-gate 
39477c478bd9Sstevel@tonic-gate 	if (mp->sbm_flags & SBD_MFLAG_RELOWNER) {
39487c478bd9Sstevel@tonic-gate 		*mhp = mp->sbm_memhandle;
39497c478bd9Sstevel@tonic-gate 		return (0);
39507c478bd9Sstevel@tonic-gate 	} else {
39517c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(SBD_HD2ERR(hp), ESBD_INTERNAL);
39527c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(SBD_HD2ERR(hp), sbp->sb_mempath[unit]);
39537c478bd9Sstevel@tonic-gate 		return (-1);
39547c478bd9Sstevel@tonic-gate 	}
39557c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
39567c478bd9Sstevel@tonic-gate }
39577c478bd9Sstevel@tonic-gate 
39587c478bd9Sstevel@tonic-gate 
39597c478bd9Sstevel@tonic-gate static int
sbd_cpu_cnt(sbd_handle_t * hp,sbd_devset_t devset)39607c478bd9Sstevel@tonic-gate sbd_cpu_cnt(sbd_handle_t *hp, sbd_devset_t devset)
39617c478bd9Sstevel@tonic-gate {
39627c478bd9Sstevel@tonic-gate 	int		c, cix;
39637c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
39647c478bd9Sstevel@tonic-gate 
39657c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
39667c478bd9Sstevel@tonic-gate 
39677c478bd9Sstevel@tonic-gate 	/*
39687c478bd9Sstevel@tonic-gate 	 * Only look for requested devices that are actually present.
39697c478bd9Sstevel@tonic-gate 	 */
39707c478bd9Sstevel@tonic-gate 	devset &= SBD_DEVS_PRESENT(sbp);
39717c478bd9Sstevel@tonic-gate 
39727c478bd9Sstevel@tonic-gate 	for (c = cix = 0; c < MAX_CMP_UNITS_PER_BOARD; c++) {
39737c478bd9Sstevel@tonic-gate 		/*
39747c478bd9Sstevel@tonic-gate 		 * Index for core 1 , if exists.
39757c478bd9Sstevel@tonic-gate 		 * With the current implementation it is
39767c478bd9Sstevel@tonic-gate 		 * MAX_CMP_UNITS_PER_BOARD off from core 0.
39777c478bd9Sstevel@tonic-gate 		 * The calculation will need to change if
39787c478bd9Sstevel@tonic-gate 		 * the assumption is no longer true.
39797c478bd9Sstevel@tonic-gate 		 */
39807c478bd9Sstevel@tonic-gate 		int		c1 = c + MAX_CMP_UNITS_PER_BOARD;
39817c478bd9Sstevel@tonic-gate 
39827c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_CMP, c) == 0) {
39837c478bd9Sstevel@tonic-gate 			continue;
39847c478bd9Sstevel@tonic-gate 		}
39857c478bd9Sstevel@tonic-gate 
39867c478bd9Sstevel@tonic-gate 		/*
39877c478bd9Sstevel@tonic-gate 		 * Check to see if the dip(s) exist for this chip
39887c478bd9Sstevel@tonic-gate 		 */
39897c478bd9Sstevel@tonic-gate 		if ((sbp->sb_devlist[NIX(SBD_COMP_CMP)][c] == NULL) &&
39907c478bd9Sstevel@tonic-gate 		    (sbp->sb_devlist[NIX(SBD_COMP_CMP)][c1] == NULL))
39917c478bd9Sstevel@tonic-gate 			continue;
39927c478bd9Sstevel@tonic-gate 
39937c478bd9Sstevel@tonic-gate 		cix++;
39947c478bd9Sstevel@tonic-gate 	}
39957c478bd9Sstevel@tonic-gate 
39967c478bd9Sstevel@tonic-gate 	return (cix);
39977c478bd9Sstevel@tonic-gate }
39987c478bd9Sstevel@tonic-gate 
39997c478bd9Sstevel@tonic-gate static int
sbd_mem_cnt(sbd_handle_t * hp,sbd_devset_t devset)40007c478bd9Sstevel@tonic-gate sbd_mem_cnt(sbd_handle_t *hp, sbd_devset_t devset)
40017c478bd9Sstevel@tonic-gate {
40027c478bd9Sstevel@tonic-gate 	int		i, ix;
40037c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
40047c478bd9Sstevel@tonic-gate 
40057c478bd9Sstevel@tonic-gate 	/*
40067c478bd9Sstevel@tonic-gate 	 * Only look for requested devices that are actually present.
40077c478bd9Sstevel@tonic-gate 	 */
40087c478bd9Sstevel@tonic-gate 	devset &= SBD_DEVS_PRESENT(sbp);
40097c478bd9Sstevel@tonic-gate 
40107c478bd9Sstevel@tonic-gate 	for (i = ix = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
40117c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
40127c478bd9Sstevel@tonic-gate 
40137c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i) == 0) {
40147c478bd9Sstevel@tonic-gate 			continue;
40157c478bd9Sstevel@tonic-gate 		}
40167c478bd9Sstevel@tonic-gate 
40177c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][i];
40187c478bd9Sstevel@tonic-gate 		if (dip == NULL)
40197c478bd9Sstevel@tonic-gate 			continue;
40207c478bd9Sstevel@tonic-gate 
40217c478bd9Sstevel@tonic-gate 		ix++;
40227c478bd9Sstevel@tonic-gate 	}
40237c478bd9Sstevel@tonic-gate 
40247c478bd9Sstevel@tonic-gate 	return (ix);
40257c478bd9Sstevel@tonic-gate }
40267c478bd9Sstevel@tonic-gate 
40277c478bd9Sstevel@tonic-gate /*
40287c478bd9Sstevel@tonic-gate  * NOTE: This routine is only partially smart about multiple
40297c478bd9Sstevel@tonic-gate  *	 mem-units.  Need to make mem-status structure smart
40307c478bd9Sstevel@tonic-gate  *	 about them also.
40317c478bd9Sstevel@tonic-gate  */
40327c478bd9Sstevel@tonic-gate static int
sbd_mem_status(sbd_handle_t * hp,sbd_devset_t devset,sbd_dev_stat_t * dsp)40337c478bd9Sstevel@tonic-gate sbd_mem_status(sbd_handle_t *hp, sbd_devset_t devset, sbd_dev_stat_t *dsp)
40347c478bd9Sstevel@tonic-gate {
40357c478bd9Sstevel@tonic-gate 	int		m, mix, rv;
40367c478bd9Sstevel@tonic-gate 	memdelstat_t	mdst;
40377c478bd9Sstevel@tonic-gate 	memquery_t	mq;
40387c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
40397c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
40407c478bd9Sstevel@tonic-gate 	sbd_mem_stat_t	*msp;
40417c478bd9Sstevel@tonic-gate 	extern int	kcage_on;
40427c478bd9Sstevel@tonic-gate 	int		i;
40437c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_mem_status";
40447c478bd9Sstevel@tonic-gate 
40457c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
40467c478bd9Sstevel@tonic-gate 
40477c478bd9Sstevel@tonic-gate 	/*
40487c478bd9Sstevel@tonic-gate 	 * Check the present devset and access the dip with
40497c478bd9Sstevel@tonic-gate 	 * status lock held to protect agains a concurrent
40507c478bd9Sstevel@tonic-gate 	 * unconfigure or disconnect thread.
40517c478bd9Sstevel@tonic-gate 	 */
40527c478bd9Sstevel@tonic-gate 	mutex_enter(&sbp->sb_slock);
40537c478bd9Sstevel@tonic-gate 
40547c478bd9Sstevel@tonic-gate 	/*
40557c478bd9Sstevel@tonic-gate 	 * Only look for requested devices that are actually present.
40567c478bd9Sstevel@tonic-gate 	 */
40577c478bd9Sstevel@tonic-gate 	devset &= SBD_DEVS_PRESENT(sbp);
40587c478bd9Sstevel@tonic-gate 
40597c478bd9Sstevel@tonic-gate 	for (m = mix = 0; m < MAX_MEM_UNITS_PER_BOARD; m++) {
40607c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
40617c478bd9Sstevel@tonic-gate 
40627c478bd9Sstevel@tonic-gate 
40637c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, m) == 0)
40647c478bd9Sstevel@tonic-gate 			continue;
40657c478bd9Sstevel@tonic-gate 
40667c478bd9Sstevel@tonic-gate 		/*
40677c478bd9Sstevel@tonic-gate 		 * Check to make sure the memory unit is in a state
40687c478bd9Sstevel@tonic-gate 		 * where its fully initialized.
40697c478bd9Sstevel@tonic-gate 		 */
40707c478bd9Sstevel@tonic-gate 		if (SBD_DEVICE_STATE(sbp, SBD_COMP_MEM, m) == SBD_STATE_EMPTY)
40717c478bd9Sstevel@tonic-gate 			continue;
40727c478bd9Sstevel@tonic-gate 
40737c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][m];
40747c478bd9Sstevel@tonic-gate 		if (dip == NULL)
40757c478bd9Sstevel@tonic-gate 			continue;
40767c478bd9Sstevel@tonic-gate 
40777c478bd9Sstevel@tonic-gate 		mp = SBD_GET_BOARD_MEMUNIT(sbp, m);
40787c478bd9Sstevel@tonic-gate 
40797c478bd9Sstevel@tonic-gate 		msp = &dsp->d_mem;
40807c478bd9Sstevel@tonic-gate 
40817c478bd9Sstevel@tonic-gate 		bzero((caddr_t)msp, sizeof (*msp));
40827c478bd9Sstevel@tonic-gate 		msp->ms_type = SBD_COMP_MEM;
40837c478bd9Sstevel@tonic-gate 
40847c478bd9Sstevel@tonic-gate 		/*
40857c478bd9Sstevel@tonic-gate 		 * The plugin expects -1 for the mem unit
40867c478bd9Sstevel@tonic-gate 		 */
40877c478bd9Sstevel@tonic-gate 		msp->ms_cm.c_id.c_unit = -1;
40887c478bd9Sstevel@tonic-gate 
40897c478bd9Sstevel@tonic-gate 		/*
40907c478bd9Sstevel@tonic-gate 		 * Get the memory name from what sbdp gave us
40917c478bd9Sstevel@tonic-gate 		 */
40927c478bd9Sstevel@tonic-gate 		for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) {
40937c478bd9Sstevel@tonic-gate 			if (SBD_COMP(i) == SBD_COMP_MEM) {
40947c478bd9Sstevel@tonic-gate 				(void) strcpy(msp->ms_name, SBD_DEVNAME(i));
40957c478bd9Sstevel@tonic-gate 			}
40967c478bd9Sstevel@tonic-gate 		}
40977c478bd9Sstevel@tonic-gate 		msp->ms_cm.c_cond = mp->sbm_cm.sbdev_cond;
40987c478bd9Sstevel@tonic-gate 		msp->ms_cm.c_busy = mp->sbm_cm.sbdev_busy;
40997c478bd9Sstevel@tonic-gate 		msp->ms_cm.c_time = mp->sbm_cm.sbdev_time;
41007c478bd9Sstevel@tonic-gate 
41017c478bd9Sstevel@tonic-gate 		/* XXX revisit this after memory conversion */
41027c478bd9Sstevel@tonic-gate 		msp->ms_ostate = ostate_cvt(SBD_DEVICE_STATE(
4103*d5ebc493SDan Cross 		    sbp, SBD_COMP_MEM, m));
41047c478bd9Sstevel@tonic-gate 
41057c478bd9Sstevel@tonic-gate 		msp->ms_basepfn = mp->sbm_basepfn;
41067c478bd9Sstevel@tonic-gate 		msp->ms_pageslost = mp->sbm_pageslost;
41077c478bd9Sstevel@tonic-gate 		msp->ms_cage_enabled = kcage_on;
41087c478bd9Sstevel@tonic-gate 		msp->ms_interleave = mp->sbm_interleave;
41097c478bd9Sstevel@tonic-gate 
41107c478bd9Sstevel@tonic-gate 		if (mp->sbm_flags & SBD_MFLAG_RELOWNER)
41117c478bd9Sstevel@tonic-gate 			rv = kphysm_del_status(mp->sbm_memhandle, &mdst);
41127c478bd9Sstevel@tonic-gate 		else
41137c478bd9Sstevel@tonic-gate 			rv = KPHYSM_EHANDLE;	/* force 'if' to fail */
41147c478bd9Sstevel@tonic-gate 
41157c478bd9Sstevel@tonic-gate 		if (rv == KPHYSM_OK) {
41167c478bd9Sstevel@tonic-gate 			msp->ms_totpages += mdst.phys_pages;
41177c478bd9Sstevel@tonic-gate 
41187c478bd9Sstevel@tonic-gate 			/*
41197c478bd9Sstevel@tonic-gate 			 * Any pages above managed is "free",
41207c478bd9Sstevel@tonic-gate 			 * i.e. it's collected.
41217c478bd9Sstevel@tonic-gate 			 */
41227c478bd9Sstevel@tonic-gate 			msp->ms_detpages += (uint_t)(mdst.collected +
4123*d5ebc493SDan Cross 			    mdst.phys_pages - mdst.managed);
41247c478bd9Sstevel@tonic-gate 		} else {
41257c478bd9Sstevel@tonic-gate 			msp->ms_totpages += (uint_t)mp->sbm_npages;
41267c478bd9Sstevel@tonic-gate 
41277c478bd9Sstevel@tonic-gate 			/*
41287c478bd9Sstevel@tonic-gate 			 * If we're UNREFERENCED or UNCONFIGURED,
41297c478bd9Sstevel@tonic-gate 			 * then the number of detached pages is
41307c478bd9Sstevel@tonic-gate 			 * however many pages are on the board.
41317c478bd9Sstevel@tonic-gate 			 * I.e. detached = not in use by OS.
41327c478bd9Sstevel@tonic-gate 			 */
41337c478bd9Sstevel@tonic-gate 			switch (msp->ms_cm.c_ostate) {
41347c478bd9Sstevel@tonic-gate 			/*
41357c478bd9Sstevel@tonic-gate 			 * changed to use cfgadm states
41367c478bd9Sstevel@tonic-gate 			 *
41377c478bd9Sstevel@tonic-gate 			 * was:
41387c478bd9Sstevel@tonic-gate 			 *	case SFDR_STATE_UNREFERENCED:
41397c478bd9Sstevel@tonic-gate 			 *	case SFDR_STATE_UNCONFIGURED:
41407c478bd9Sstevel@tonic-gate 			 */
41417c478bd9Sstevel@tonic-gate 			case SBD_STAT_UNCONFIGURED:
41427c478bd9Sstevel@tonic-gate 				msp->ms_detpages = msp->ms_totpages;
41437c478bd9Sstevel@tonic-gate 				break;
41447c478bd9Sstevel@tonic-gate 
41457c478bd9Sstevel@tonic-gate 			default:
41467c478bd9Sstevel@tonic-gate 				break;
41477c478bd9Sstevel@tonic-gate 			}
41487c478bd9Sstevel@tonic-gate 		}
41497c478bd9Sstevel@tonic-gate 
41507c478bd9Sstevel@tonic-gate 		rv = kphysm_del_span_query(mp->sbm_basepfn,
4151*d5ebc493SDan Cross 		    mp->sbm_npages, &mq);
41527c478bd9Sstevel@tonic-gate 		if (rv == KPHYSM_OK) {
41537c478bd9Sstevel@tonic-gate 			msp->ms_managed_pages = mq.managed;
41547c478bd9Sstevel@tonic-gate 			msp->ms_noreloc_pages = mq.nonrelocatable;
41557c478bd9Sstevel@tonic-gate 			msp->ms_noreloc_first = mq.first_nonrelocatable;
41567c478bd9Sstevel@tonic-gate 			msp->ms_noreloc_last = mq.last_nonrelocatable;
41577c478bd9Sstevel@tonic-gate 			msp->ms_cm.c_sflags = 0;
41587c478bd9Sstevel@tonic-gate 			if (mq.nonrelocatable) {
41597c478bd9Sstevel@tonic-gate 				SBD_SET_SUSPEND(SBD_CMD_UNCONFIGURE,
41607c478bd9Sstevel@tonic-gate 				    dsp->ds_suspend);
41617c478bd9Sstevel@tonic-gate 			}
41627c478bd9Sstevel@tonic-gate 		} else {
41637c478bd9Sstevel@tonic-gate 			PR_MEM("%s: kphysm_del_span_query() = %d\n", f, rv);
41647c478bd9Sstevel@tonic-gate 		}
41657c478bd9Sstevel@tonic-gate 
41667c478bd9Sstevel@tonic-gate 		mix++;
41677c478bd9Sstevel@tonic-gate 		dsp++;
41687c478bd9Sstevel@tonic-gate 	}
41697c478bd9Sstevel@tonic-gate 
41707c478bd9Sstevel@tonic-gate 	mutex_exit(&sbp->sb_slock);
41717c478bd9Sstevel@tonic-gate 
41727c478bd9Sstevel@tonic-gate 	return (mix);
41737c478bd9Sstevel@tonic-gate }
41747c478bd9Sstevel@tonic-gate 
41757c478bd9Sstevel@tonic-gate static void
sbd_cancel(sbd_handle_t * hp)41767c478bd9Sstevel@tonic-gate sbd_cancel(sbd_handle_t *hp)
41777c478bd9Sstevel@tonic-gate {
41787c478bd9Sstevel@tonic-gate 	int		i;
41797c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
41807c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
41817c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_cancel";
41827c478bd9Sstevel@tonic-gate 	int		rv;
41837c478bd9Sstevel@tonic-gate 
41847c478bd9Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
41857c478bd9Sstevel@tonic-gate 
41867c478bd9Sstevel@tonic-gate 	/*
41877c478bd9Sstevel@tonic-gate 	 * Only devices which have been "released" are
41887c478bd9Sstevel@tonic-gate 	 * subject to cancellation.
41897c478bd9Sstevel@tonic-gate 	 */
41907c478bd9Sstevel@tonic-gate 	devset = HD2MACHHD(hp)->sh_devset & SBD_DEVS_UNREFERENCED(sbp);
41917c478bd9Sstevel@tonic-gate 
41927c478bd9Sstevel@tonic-gate 	/*
41937c478bd9Sstevel@tonic-gate 	 * Nothing to do for CPUs or IO other than change back
41947c478bd9Sstevel@tonic-gate 	 * their state.
41957c478bd9Sstevel@tonic-gate 	 */
41967c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
41977c478bd9Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_CPU, i))
41987c478bd9Sstevel@tonic-gate 			continue;
41997c478bd9Sstevel@tonic-gate 		if (sbd_cancel_cpu(hp, i) != SBD_CPUERR_FATAL) {
42007c478bd9Sstevel@tonic-gate 			SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i,
4201*d5ebc493SDan Cross 			    SBD_STATE_CONFIGURED);
42027c478bd9Sstevel@tonic-gate 		} else {
42037c478bd9Sstevel@tonic-gate 			SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i,
4204*d5ebc493SDan Cross 			    SBD_STATE_FATAL);
42057c478bd9Sstevel@tonic-gate 		}
42067c478bd9Sstevel@tonic-gate 	}
42077c478bd9Sstevel@tonic-gate 
42087c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
42097c478bd9Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_IO, i))
42107c478bd9Sstevel@tonic-gate 			continue;
42117c478bd9Sstevel@tonic-gate 		SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, i,
4212*d5ebc493SDan Cross 		    SBD_STATE_CONFIGURED);
42137c478bd9Sstevel@tonic-gate 	}
42147c478bd9Sstevel@tonic-gate 
42157c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
42167c478bd9Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_MEM, i))
42177c478bd9Sstevel@tonic-gate 			continue;
42187c478bd9Sstevel@tonic-gate 		if ((rv = sbd_cancel_mem(hp, i)) == 0) {
42197c478bd9Sstevel@tonic-gate 			SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i,
4220*d5ebc493SDan Cross 			    SBD_STATE_CONFIGURED);
42217c478bd9Sstevel@tonic-gate 		} else if (rv == -1) {
42227c478bd9Sstevel@tonic-gate 			SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i,
4223*d5ebc493SDan Cross 			    SBD_STATE_FATAL);
42247c478bd9Sstevel@tonic-gate 		}
42257c478bd9Sstevel@tonic-gate 	}
42267c478bd9Sstevel@tonic-gate 
42277c478bd9Sstevel@tonic-gate 	PR_ALL("%s: unreleasing devset (0x%x)\n", f, (uint_t)devset);
42287c478bd9Sstevel@tonic-gate 
42297c478bd9Sstevel@tonic-gate 	SBD_DEVS_CANCEL(sbp, devset);
42307c478bd9Sstevel@tonic-gate 
42317c478bd9Sstevel@tonic-gate 	if (SBD_DEVS_UNREFERENCED(sbp) == 0) {
42327c478bd9Sstevel@tonic-gate 		sbd_istate_t	new_state;
42337c478bd9Sstevel@tonic-gate 		/*
42347c478bd9Sstevel@tonic-gate 		 * If the board no longer has any released devices
42357c478bd9Sstevel@tonic-gate 		 * than transfer it back to the CONFIG/PARTIAL state.
42367c478bd9Sstevel@tonic-gate 		 */
42377c478bd9Sstevel@tonic-gate 		if (SBD_DEVS_ATTACHED(sbp) == SBD_DEVS_PRESENT(sbp))
42387c478bd9Sstevel@tonic-gate 			new_state = SBD_STATE_CONFIGURED;
42397c478bd9Sstevel@tonic-gate 		else
42407c478bd9Sstevel@tonic-gate 			new_state = SBD_STATE_PARTIAL;
42417c478bd9Sstevel@tonic-gate 		if (SBD_BOARD_STATE(sbp) != new_state) {
42427c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, new_state);
42437c478bd9Sstevel@tonic-gate 		}
42447c478bd9Sstevel@tonic-gate 		sbp->sb_ostate = SBD_STAT_CONFIGURED;
42457c478bd9Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&sbp->sb_time);
42467c478bd9Sstevel@tonic-gate 	}
42477c478bd9Sstevel@tonic-gate }
42487c478bd9Sstevel@tonic-gate 
42497c478bd9Sstevel@tonic-gate static void
sbd_get_ncm(sbd_handle_t * hp)42507c478bd9Sstevel@tonic-gate sbd_get_ncm(sbd_handle_t *hp)
42517c478bd9Sstevel@tonic-gate {
42527c478bd9Sstevel@tonic-gate 	sbd_devset_t devset;
42537c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp = HD2MACHHD(hp);
42547c478bd9Sstevel@tonic-gate 	sbd_cmd_t		*cmdp =  (sbd_cmd_t *)hp->h_iap;
42557c478bd9Sstevel@tonic-gate 	int			error;
42567c478bd9Sstevel@tonic-gate 
42577c478bd9Sstevel@tonic-gate 	/* pre_op restricted the devices to those selected by the ioctl */
42587c478bd9Sstevel@tonic-gate 	devset = shp->sh_devset;
42597c478bd9Sstevel@tonic-gate 
4260*d5ebc493SDan Cross 	cmdp->cmd_getncm.g_ncm = sbd_cpu_cnt(hp, devset) +
4261*d5ebc493SDan Cross 	    sbd_io_cnt(hp, devset) + sbd_mem_cnt(hp, devset);
42627c478bd9Sstevel@tonic-gate 
42637c478bd9Sstevel@tonic-gate 	error = sbd_copyout_ioarg(hp->h_mode, hp->h_cmd, cmdp,
4264*d5ebc493SDan Cross 	    (sbd_ioctl_arg_t *)shp->sh_arg);
42657c478bd9Sstevel@tonic-gate 
42667c478bd9Sstevel@tonic-gate 	if (error != 0)
42677c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(SBD_HD2ERR(hp), error);
42687c478bd9Sstevel@tonic-gate }
42697c478bd9Sstevel@tonic-gate 
42707c478bd9Sstevel@tonic-gate static void
sbd_status(sbd_handle_t * hp)42717c478bd9Sstevel@tonic-gate sbd_status(sbd_handle_t *hp)
42727c478bd9Sstevel@tonic-gate {
42737c478bd9Sstevel@tonic-gate 	int			nstat, mode, ncm, sz, cksz;
42747c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp = HD2MACHHD(hp);
42757c478bd9Sstevel@tonic-gate 	sbd_devset_t		devset;
42767c478bd9Sstevel@tonic-gate 	sbd_board_t		*sbp = SBDH2BD(hp->h_sbd);
42777c478bd9Sstevel@tonic-gate 	sbd_stat_t		*dstatp;
42787c478bd9Sstevel@tonic-gate 	sbd_cmd_t		*cmdp =  (sbd_cmd_t *)hp->h_iap;
42797c478bd9Sstevel@tonic-gate 	sbdp_handle_t		*hdp;
42807c478bd9Sstevel@tonic-gate 	sbd_dev_stat_t		*devstatp;
42817c478bd9Sstevel@tonic-gate 
42827c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
42837c478bd9Sstevel@tonic-gate 	int			sz32;
42847c478bd9Sstevel@tonic-gate 	sbd_stat32_t		*dstat32p;
42857c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
42867c478bd9Sstevel@tonic-gate 
42877c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_status";
42887c478bd9Sstevel@tonic-gate 
42897c478bd9Sstevel@tonic-gate 	mode = hp->h_mode;
42907c478bd9Sstevel@tonic-gate 	devset = shp->sh_devset;
42917c478bd9Sstevel@tonic-gate 
42927c478bd9Sstevel@tonic-gate 	devset &= SBD_DEVS_PRESENT(sbp);
42937c478bd9Sstevel@tonic-gate 
42947c478bd9Sstevel@tonic-gate 	if (cmdp->cmd_cm.c_id.c_type == SBD_COMP_NONE) {
42957c478bd9Sstevel@tonic-gate 		if (cmdp->cmd_cm.c_flags & SBD_FLAG_ALLCMP) {
42967c478bd9Sstevel@tonic-gate 			/*
42977c478bd9Sstevel@tonic-gate 			 * Get the number of components "ncm" on the board.
42987c478bd9Sstevel@tonic-gate 			 * Calculate size of buffer required to store one
42997c478bd9Sstevel@tonic-gate 			 * sbd_stat_t structure plus ncm-1 sbd_dev_stat_t
43007c478bd9Sstevel@tonic-gate 			 * structures. Note that sbd_stat_t already contains
43017c478bd9Sstevel@tonic-gate 			 * one sbd_dev_stat_t, so only an additional ncm-1
43027c478bd9Sstevel@tonic-gate 			 * sbd_dev_stat_t structures need to be accounted for
43037c478bd9Sstevel@tonic-gate 			 * in the calculation when more than one component
43047c478bd9Sstevel@tonic-gate 			 * is present.
43057c478bd9Sstevel@tonic-gate 			 */
43067c478bd9Sstevel@tonic-gate 			ncm = sbd_cpu_cnt(hp, devset) + sbd_io_cnt(hp, devset) +
43077c478bd9Sstevel@tonic-gate 			    sbd_mem_cnt(hp, devset);
43087c478bd9Sstevel@tonic-gate 
43097c478bd9Sstevel@tonic-gate 		} else {
43107c478bd9Sstevel@tonic-gate 			/*
43117c478bd9Sstevel@tonic-gate 			 * In the case of c_type == SBD_COMP_NONE, and
43127c478bd9Sstevel@tonic-gate 			 * SBD_FLAG_ALLCMP not specified, only the board
43137c478bd9Sstevel@tonic-gate 			 * info is to be returned, no components.
43147c478bd9Sstevel@tonic-gate 			 */
43157c478bd9Sstevel@tonic-gate 			ncm = 0;
43167c478bd9Sstevel@tonic-gate 			devset = 0;
43177c478bd9Sstevel@tonic-gate 		}
43187c478bd9Sstevel@tonic-gate 	} else {
43197c478bd9Sstevel@tonic-gate 		/* Confirm that only one component is selected. */
43207c478bd9Sstevel@tonic-gate 		ncm = sbd_cpu_cnt(hp, devset) + sbd_io_cnt(hp, devset) +
43217c478bd9Sstevel@tonic-gate 		    sbd_mem_cnt(hp, devset);
43227c478bd9Sstevel@tonic-gate 		if (ncm != 1) {
43237c478bd9Sstevel@tonic-gate 			PR_ALL("%s: expected ncm of 1, got %d, devset 0x%x\n",
43247c478bd9Sstevel@tonic-gate 			    f, ncm, devset);
43257c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL);
43267c478bd9Sstevel@tonic-gate 			return;
43277c478bd9Sstevel@tonic-gate 		}
43287c478bd9Sstevel@tonic-gate 	}
43297c478bd9Sstevel@tonic-gate 
43307c478bd9Sstevel@tonic-gate 	sz = sizeof (sbd_stat_t);
43317c478bd9Sstevel@tonic-gate 	if (ncm > 1)
43327c478bd9Sstevel@tonic-gate 		sz += sizeof (sbd_dev_stat_t) * (ncm - 1);
43337c478bd9Sstevel@tonic-gate 
43347c478bd9Sstevel@tonic-gate 	cksz = sz;
43357c478bd9Sstevel@tonic-gate 
43367c478bd9Sstevel@tonic-gate 	/*
43377c478bd9Sstevel@tonic-gate 	 * s_nbytes describes the size of the preallocated user
43387c478bd9Sstevel@tonic-gate 	 * buffer into which the application is executing to
43397c478bd9Sstevel@tonic-gate 	 * receive the sbd_stat_t and sbd_dev_stat_t structures.
43407c478bd9Sstevel@tonic-gate 	 * This buffer must be at least the required (sz) size.
43417c478bd9Sstevel@tonic-gate 	 */
43427c478bd9Sstevel@tonic-gate 
43437c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
43447c478bd9Sstevel@tonic-gate 
43457c478bd9Sstevel@tonic-gate 	/*
43467c478bd9Sstevel@tonic-gate 	 * More buffer space is required for the 64bit to 32bit
43477c478bd9Sstevel@tonic-gate 	 * conversion of data structures.
43487c478bd9Sstevel@tonic-gate 	 */
43497c478bd9Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
43507c478bd9Sstevel@tonic-gate 		sz32 = sizeof (sbd_stat32_t);
43517c478bd9Sstevel@tonic-gate 		if (ncm > 1)
43527c478bd9Sstevel@tonic-gate 			sz32  += sizeof (sbd_dev_stat32_t) * (ncm - 1);
43537c478bd9Sstevel@tonic-gate 		cksz = sz32;
43547c478bd9Sstevel@tonic-gate 	} else
43557c478bd9Sstevel@tonic-gate 		sz32 = 0;
43567c478bd9Sstevel@tonic-gate #endif
43577c478bd9Sstevel@tonic-gate 
43587c478bd9Sstevel@tonic-gate 	if ((int)cmdp->cmd_stat.s_nbytes < cksz) {
43597c478bd9Sstevel@tonic-gate 		PR_ALL("%s: ncm=%d s_nbytes = 0x%x\n", f, ncm,
43607c478bd9Sstevel@tonic-gate 		    cmdp->cmd_stat.s_nbytes);
43617c478bd9Sstevel@tonic-gate 		PR_ALL("%s: expected size of 0x%x\n", f, cksz);
43627c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL);
43637c478bd9Sstevel@tonic-gate 		return;
43647c478bd9Sstevel@tonic-gate 	}
43657c478bd9Sstevel@tonic-gate 
43667c478bd9Sstevel@tonic-gate 	dstatp = kmem_zalloc(sz, KM_SLEEP);
43677c478bd9Sstevel@tonic-gate 	devstatp = &dstatp->s_stat[0];
43687c478bd9Sstevel@tonic-gate 
43697c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
43707c478bd9Sstevel@tonic-gate 	if (sz32 != 0)
43717c478bd9Sstevel@tonic-gate 		dstat32p = kmem_zalloc(sz32, KM_SLEEP);
43727c478bd9Sstevel@tonic-gate #endif
43737c478bd9Sstevel@tonic-gate 
43747c478bd9Sstevel@tonic-gate 	/*
43757c478bd9Sstevel@tonic-gate 	 * if connected or better, provide cached status if available,
43767c478bd9Sstevel@tonic-gate 	 * otherwise call sbdp for status
43777c478bd9Sstevel@tonic-gate 	 */
43787c478bd9Sstevel@tonic-gate 	mutex_enter(&sbp->sb_flags_mutex);
43797c478bd9Sstevel@tonic-gate 	switch (sbp->sb_state) {
43807c478bd9Sstevel@tonic-gate 
43817c478bd9Sstevel@tonic-gate 	case	SBD_STATE_CONNECTED:
43827c478bd9Sstevel@tonic-gate 	case	SBD_STATE_PARTIAL:
43837c478bd9Sstevel@tonic-gate 	case	SBD_STATE_CONFIGURED:
43847c478bd9Sstevel@tonic-gate 		if (sbp->sb_flags & SBD_BOARD_STATUS_CACHED) {
43857c478bd9Sstevel@tonic-gate 			bcopy(&sbp->sb_stat, dstatp, sizeof (sbd_stat_t));
43867c478bd9Sstevel@tonic-gate 			dstatp->s_rstate = rstate_cvt(sbp->sb_state);
43877c478bd9Sstevel@tonic-gate 			dstatp->s_ostate = ostate_cvt(sbp->sb_state);
43887c478bd9Sstevel@tonic-gate 			dstatp->s_busy = sbp->sb_busy;
43897c478bd9Sstevel@tonic-gate 			dstatp->s_time = sbp->sb_time;
43907c478bd9Sstevel@tonic-gate 			dstatp->s_cond = sbp->sb_cond;
43917c478bd9Sstevel@tonic-gate 			break;
43927c478bd9Sstevel@tonic-gate 		}
43937c478bd9Sstevel@tonic-gate 	/*FALLTHROUGH*/
43947c478bd9Sstevel@tonic-gate 
43957c478bd9Sstevel@tonic-gate 	default:
43967c478bd9Sstevel@tonic-gate 		sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED;
43977c478bd9Sstevel@tonic-gate 		dstatp->s_board = sbp->sb_num;
43987c478bd9Sstevel@tonic-gate 		dstatp->s_ostate = ostate_cvt(sbp->sb_state);
43997c478bd9Sstevel@tonic-gate 		dstatp->s_time = sbp->sb_time;
44007c478bd9Sstevel@tonic-gate 
44017c478bd9Sstevel@tonic-gate 		hdp = sbd_get_sbdp_handle(sbp, hp);
44027c478bd9Sstevel@tonic-gate 
44037c478bd9Sstevel@tonic-gate 		if (sbdp_get_board_status(hdp, dstatp) != 0) {
44047c478bd9Sstevel@tonic-gate 			SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
44057c478bd9Sstevel@tonic-gate 			sbd_release_sbdp_handle(hdp);
44067c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
44077c478bd9Sstevel@tonic-gate 			if (sz32 != 0)
44087c478bd9Sstevel@tonic-gate 				kmem_free(dstat32p, sz32);
44097c478bd9Sstevel@tonic-gate #endif
44107c478bd9Sstevel@tonic-gate 			kmem_free(dstatp, sz);
44117c478bd9Sstevel@tonic-gate 			mutex_exit(&sbp->sb_flags_mutex);
44127c478bd9Sstevel@tonic-gate 			return;
44137c478bd9Sstevel@tonic-gate 		}
44147c478bd9Sstevel@tonic-gate 		/*
44157c478bd9Sstevel@tonic-gate 		 * Do not cache status if the busy flag has
44167c478bd9Sstevel@tonic-gate 		 * been set by the call to sbdp_get_board_status().
44177c478bd9Sstevel@tonic-gate 		 */
44187c478bd9Sstevel@tonic-gate 		if (!dstatp->s_busy) {
44197c478bd9Sstevel@tonic-gate 			/* Can get board busy flag now */
44207c478bd9Sstevel@tonic-gate 			dstatp->s_busy = sbp->sb_busy;
44217c478bd9Sstevel@tonic-gate 			sbp->sb_cond = (sbd_cond_t)dstatp->s_cond;
4422*d5ebc493SDan Cross 			bcopy(dstatp, &sbp->sb_stat, sizeof (sbd_stat_t));
44237c478bd9Sstevel@tonic-gate 			sbp->sb_flags |= SBD_BOARD_STATUS_CACHED;
44247c478bd9Sstevel@tonic-gate 		}
44257c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
44267c478bd9Sstevel@tonic-gate 		break;
44277c478bd9Sstevel@tonic-gate 	}
44287c478bd9Sstevel@tonic-gate 	mutex_exit(&sbp->sb_flags_mutex);
44297c478bd9Sstevel@tonic-gate 
44307c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT))
44317c478bd9Sstevel@tonic-gate 		if ((nstat = sbd_cpu_flags(hp, devset, devstatp)) > 0) {
44327c478bd9Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
44337c478bd9Sstevel@tonic-gate 			devstatp += nstat;
44347c478bd9Sstevel@tonic-gate 		}
44357c478bd9Sstevel@tonic-gate 
44367c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT))
44377c478bd9Sstevel@tonic-gate 		if ((nstat = sbd_mem_status(hp, devset, devstatp)) > 0) {
44387c478bd9Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
44397c478bd9Sstevel@tonic-gate 			devstatp += nstat;
44407c478bd9Sstevel@tonic-gate 		}
44417c478bd9Sstevel@tonic-gate 
44427c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT))
44437c478bd9Sstevel@tonic-gate 		if ((nstat = sbd_io_status(hp, devset, devstatp)) > 0) {
44447c478bd9Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
44457c478bd9Sstevel@tonic-gate 			devstatp += nstat;
44467c478bd9Sstevel@tonic-gate 		}
44477c478bd9Sstevel@tonic-gate 
44487c478bd9Sstevel@tonic-gate 	/* paranoia: detect buffer overrun */
44497c478bd9Sstevel@tonic-gate 	if ((caddr_t)devstatp > ((caddr_t)dstatp) + sz) {
44507c478bd9Sstevel@tonic-gate 		PR_ALL("%s: buffer overrun\n", f);
44517c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
44527c478bd9Sstevel@tonic-gate 		if (sz32 != 0)
44537c478bd9Sstevel@tonic-gate 			kmem_free(dstat32p, sz32);
44547c478bd9Sstevel@tonic-gate #endif
44557c478bd9Sstevel@tonic-gate 		kmem_free(dstatp, sz);
44567c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL);
44577c478bd9Sstevel@tonic-gate 		return;
44587c478bd9Sstevel@tonic-gate 	}
44597c478bd9Sstevel@tonic-gate 
44607c478bd9Sstevel@tonic-gate /* if necessary, move data into intermediate device status buffer */
44617c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
44627c478bd9Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
44637c478bd9Sstevel@tonic-gate 		int		i, j;
44647c478bd9Sstevel@tonic-gate 
44657c478bd9Sstevel@tonic-gate 		ASSERT(sz32 != 0);
44667c478bd9Sstevel@tonic-gate 		/* paranoia: detect buffer overrun */
44677c478bd9Sstevel@tonic-gate 		if ((caddr_t)&dstat32p->s_stat[dstatp->s_nstat] >
44687c478bd9Sstevel@tonic-gate 		    ((caddr_t)dstat32p) + sz32) {
4469*d5ebc493SDan Cross 			cmn_err(CE_WARN, "sbd:%s: buffer32 overrun", f);
44707c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
44717c478bd9Sstevel@tonic-gate 			if (sz32 != 0)
44727c478bd9Sstevel@tonic-gate 				kmem_free(dstat32p, sz32);
44737c478bd9Sstevel@tonic-gate #endif
44747c478bd9Sstevel@tonic-gate 			kmem_free(dstatp, sz);
44757c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL);
44767c478bd9Sstevel@tonic-gate 			return;
44777c478bd9Sstevel@tonic-gate 		}
44787c478bd9Sstevel@tonic-gate 
44797c478bd9Sstevel@tonic-gate 		/*
44807c478bd9Sstevel@tonic-gate 		 * initialize 32 bit sbd board status structure
44817c478bd9Sstevel@tonic-gate 		 */
44827c478bd9Sstevel@tonic-gate 		dstat32p->s_board = (int32_t)dstatp->s_board;
44837c478bd9Sstevel@tonic-gate 		dstat32p->s_nstat = (int32_t)dstatp->s_nstat;
44847c478bd9Sstevel@tonic-gate 		dstat32p->s_rstate = dstatp->s_rstate;
44857c478bd9Sstevel@tonic-gate 		dstat32p->s_ostate = dstatp->s_ostate;
44867c478bd9Sstevel@tonic-gate 		dstat32p->s_cond = dstatp->s_cond;
44877c478bd9Sstevel@tonic-gate 		dstat32p->s_busy = dstatp->s_busy;
44887c478bd9Sstevel@tonic-gate 		dstat32p->s_time = dstatp->s_time;
44897c478bd9Sstevel@tonic-gate 		dstat32p->s_assigned = dstatp->s_assigned;
44907c478bd9Sstevel@tonic-gate 		dstat32p->s_power = dstatp->s_power;
44917c478bd9Sstevel@tonic-gate 		dstat32p->s_platopts = (int32_t)dstatp->s_platopts;
44927c478bd9Sstevel@tonic-gate 		(void) strcpy(dstat32p->s_type, dstatp->s_type);
44937c478bd9Sstevel@tonic-gate 
44947c478bd9Sstevel@tonic-gate 		for (i = 0; i < dstatp->s_nstat; i++) {
44957c478bd9Sstevel@tonic-gate 			sbd_dev_stat_t	*dsp = &dstatp->s_stat[i];
44967c478bd9Sstevel@tonic-gate 			sbd_dev_stat32_t	*ds32p = &dstat32p->s_stat[i];
44977c478bd9Sstevel@tonic-gate 
44987c478bd9Sstevel@tonic-gate 			/*
44997c478bd9Sstevel@tonic-gate 			 * copy common data for the device
45007c478bd9Sstevel@tonic-gate 			 */
45017c478bd9Sstevel@tonic-gate 			ds32p->d_cm.ci_type = (int32_t)dsp->d_cm.ci_type;
45027c478bd9Sstevel@tonic-gate 			ds32p->d_cm.ci_unit = (int32_t)dsp->d_cm.ci_unit;
45037c478bd9Sstevel@tonic-gate 			ds32p->d_cm.c_ostate = (int32_t)dsp->d_cm.c_ostate;
45047c478bd9Sstevel@tonic-gate 			ds32p->d_cm.c_cond = (int32_t)dsp->d_cm.c_cond;
45057c478bd9Sstevel@tonic-gate 			ds32p->d_cm.c_busy = (int32_t)dsp->d_cm.c_busy;
45067c478bd9Sstevel@tonic-gate 			ds32p->d_cm.c_time = (time32_t)dsp->d_cm.c_time;
45077c478bd9Sstevel@tonic-gate 			ds32p->d_cm.c_sflags = (int32_t)dsp->d_cm.c_sflags;
45087c478bd9Sstevel@tonic-gate 			(void) strcpy(ds32p->d_cm.ci_name, dsp->d_cm.ci_name);
45097c478bd9Sstevel@tonic-gate 
45107c478bd9Sstevel@tonic-gate 			/* copy type specific data for the device */
45117c478bd9Sstevel@tonic-gate 			switch (dsp->d_cm.ci_type) {
45127c478bd9Sstevel@tonic-gate 
45137c478bd9Sstevel@tonic-gate 			case SBD_COMP_CPU:
45147c478bd9Sstevel@tonic-gate 				ds32p->d_cpu.cs_isbootproc =
4515*d5ebc493SDan Cross 				    (int32_t)dsp->d_cpu.cs_isbootproc;
45167c478bd9Sstevel@tonic-gate 				ds32p->d_cpu.cs_cpuid =
4517*d5ebc493SDan Cross 				    (int32_t)dsp->d_cpu.cs_cpuid;
45187c478bd9Sstevel@tonic-gate 				ds32p->d_cpu.cs_speed =
4519*d5ebc493SDan Cross 				    (int32_t)dsp->d_cpu.cs_speed;
45207c478bd9Sstevel@tonic-gate 				ds32p->d_cpu.cs_ecache =
4521*d5ebc493SDan Cross 				    (int32_t)dsp->d_cpu.cs_ecache;
45227c478bd9Sstevel@tonic-gate 				break;
45237c478bd9Sstevel@tonic-gate 
45247c478bd9Sstevel@tonic-gate 			case SBD_COMP_MEM:
45257c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_type =
4526*d5ebc493SDan Cross 				    (int32_t)dsp->d_mem.ms_type;
45277c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_ostate =
4528*d5ebc493SDan Cross 				    (int32_t)dsp->d_mem.ms_ostate;
45297c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_cond =
4530*d5ebc493SDan Cross 				    (int32_t)dsp->d_mem.ms_cond;
45317c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_interleave =
4532*d5ebc493SDan Cross 				    (uint32_t)dsp->d_mem.ms_interleave;
45337c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_basepfn =
4534*d5ebc493SDan Cross 				    (uint32_t)dsp->d_mem.ms_basepfn;
45357c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_totpages =
4536*d5ebc493SDan Cross 				    (uint32_t)dsp->d_mem.ms_totpages;
45377c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_detpages =
4538*d5ebc493SDan Cross 				    (uint32_t)dsp->d_mem.ms_detpages;
45397c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_pageslost =
4540*d5ebc493SDan Cross 				    (int32_t)dsp->d_mem.ms_pageslost;
45417c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_managed_pages =
4542*d5ebc493SDan Cross 				    (int32_t)dsp->d_mem.ms_managed_pages;
45437c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_noreloc_pages =
4544*d5ebc493SDan Cross 				    (int32_t)dsp->d_mem.ms_noreloc_pages;
45457c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_noreloc_first =
4546*d5ebc493SDan Cross 				    (int32_t)dsp->d_mem.ms_noreloc_first;
45477c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_noreloc_last =
4548*d5ebc493SDan Cross 				    (int32_t)dsp->d_mem.ms_noreloc_last;
45497c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_cage_enabled =
4550*d5ebc493SDan Cross 				    (int32_t)dsp->d_mem.ms_cage_enabled;
45517c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_peer_is_target =
4552*d5ebc493SDan Cross 				    (int32_t)dsp->d_mem.ms_peer_is_target;
45537c478bd9Sstevel@tonic-gate 				(void) strcpy(ds32p->d_mem.ms_peer_ap_id,
4554*d5ebc493SDan Cross 				    dsp->d_mem.ms_peer_ap_id);
45557c478bd9Sstevel@tonic-gate 				break;
45567c478bd9Sstevel@tonic-gate 
45577c478bd9Sstevel@tonic-gate 
45587c478bd9Sstevel@tonic-gate 			case SBD_COMP_IO:
45597c478bd9Sstevel@tonic-gate 
45607c478bd9Sstevel@tonic-gate 				ds32p->d_io.is_type =
4561*d5ebc493SDan Cross 				    (int32_t)dsp->d_io.is_type;
45627c478bd9Sstevel@tonic-gate 				ds32p->d_io.is_unsafe_count =
4563*d5ebc493SDan Cross 				    (int32_t)dsp->d_io.is_unsafe_count;
45647c478bd9Sstevel@tonic-gate 				ds32p->d_io.is_referenced =
4565*d5ebc493SDan Cross 				    (int32_t)dsp->d_io.is_referenced;
45667c478bd9Sstevel@tonic-gate 				for (j = 0; j < SBD_MAX_UNSAFE; j++)
45677c478bd9Sstevel@tonic-gate 					ds32p->d_io.is_unsafe_list[j] =
45687c478bd9Sstevel@tonic-gate 					    (int32_t)
45697c478bd9Sstevel@tonic-gate 					    ds32p->d_io.is_unsafe_list[j];
45707c478bd9Sstevel@tonic-gate 				bcopy(dsp->d_io.is_pathname,
45717c478bd9Sstevel@tonic-gate 				    ds32p->d_io.is_pathname, MAXPATHLEN);
45727c478bd9Sstevel@tonic-gate 				break;
45737c478bd9Sstevel@tonic-gate 
45747c478bd9Sstevel@tonic-gate 			case SBD_COMP_CMP:
45757c478bd9Sstevel@tonic-gate 				/* copy sbd_cmp_stat_t structure members */
45767c478bd9Sstevel@tonic-gate 				bcopy(&dsp->d_cmp.ps_cpuid[0],
4577*d5ebc493SDan Cross 				    &ds32p->d_cmp.ps_cpuid[0],
4578*d5ebc493SDan Cross 				    sizeof (ds32p->d_cmp.ps_cpuid));
45797c478bd9Sstevel@tonic-gate 				ds32p->d_cmp.ps_ncores =
4580*d5ebc493SDan Cross 				    (int32_t)dsp->d_cmp.ps_ncores;
45817c478bd9Sstevel@tonic-gate 				ds32p->d_cmp.ps_speed =
4582*d5ebc493SDan Cross 				    (int32_t)dsp->d_cmp.ps_speed;
45837c478bd9Sstevel@tonic-gate 				ds32p->d_cmp.ps_ecache =
4584*d5ebc493SDan Cross 				    (int32_t)dsp->d_cmp.ps_ecache;
45857c478bd9Sstevel@tonic-gate 				break;
45867c478bd9Sstevel@tonic-gate 
45877c478bd9Sstevel@tonic-gate 			default:
45887c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
45897c478bd9Sstevel@tonic-gate 				    "sbd:%s: unknown dev type (%d)", f,
45907c478bd9Sstevel@tonic-gate 				    (int)dsp->d_cm.c_id.c_type);
45917c478bd9Sstevel@tonic-gate 				break;
45927c478bd9Sstevel@tonic-gate 			}
45937c478bd9Sstevel@tonic-gate 		}
45947c478bd9Sstevel@tonic-gate 
45957c478bd9Sstevel@tonic-gate 		if (ddi_copyout((void *)dstat32p,
45967c478bd9Sstevel@tonic-gate 		    cmdp->cmd_stat.s_statp, sz32, mode) != 0) {
45977c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
4598*d5ebc493SDan Cross 			    "sbd:%s: failed to copyout status for board %d",
4599*d5ebc493SDan Cross 			    f, sbp->sb_num);
46007c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(SBD_HD2ERR(hp), EFAULT);
46017c478bd9Sstevel@tonic-gate 		}
46027c478bd9Sstevel@tonic-gate 	} else
46037c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
46047c478bd9Sstevel@tonic-gate 	if (ddi_copyout((void *)dstatp, cmdp->cmd_stat.s_statp,
46057c478bd9Sstevel@tonic-gate 	    sz, mode) != 0) {
46067c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
4607*d5ebc493SDan Cross 		    "sbd:%s: failed to copyout status for board %d",
4608*d5ebc493SDan Cross 		    f, sbp->sb_num);
46097c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(SBD_HD2ERR(hp), EFAULT);
46107c478bd9Sstevel@tonic-gate 	}
46117c478bd9Sstevel@tonic-gate 
46127c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
46137c478bd9Sstevel@tonic-gate 	if (sz32 != 0)
46147c478bd9Sstevel@tonic-gate 		kmem_free(dstat32p, sz32);
46157c478bd9Sstevel@tonic-gate #endif
46167c478bd9Sstevel@tonic-gate 	kmem_free(dstatp, sz);
46177c478bd9Sstevel@tonic-gate }
46187c478bd9Sstevel@tonic-gate 
46197c478bd9Sstevel@tonic-gate /*
46207c478bd9Sstevel@tonic-gate  * Called at driver load time to determine the state and condition
46217c478bd9Sstevel@tonic-gate  * of an existing board in the system.
46227c478bd9Sstevel@tonic-gate  */
46237c478bd9Sstevel@tonic-gate static void
sbd_board_discovery(sbd_board_t * sbp)46247c478bd9Sstevel@tonic-gate sbd_board_discovery(sbd_board_t *sbp)
46257c478bd9Sstevel@tonic-gate {
46267c478bd9Sstevel@tonic-gate 	int		i;
46277c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
46287c478bd9Sstevel@tonic-gate 	sbd_devset_t	devs_lost, devs_attached = 0;
46297c478bd9Sstevel@tonic-gate 	extern kmutex_t	cpu_lock;
46307c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
46317c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_board_discovery";
46327c478bd9Sstevel@tonic-gate 	sbderror_t	error, *ep;
46337c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp = MACHBD2HD(sbp);
46347c478bd9Sstevel@tonic-gate 
46357c478bd9Sstevel@tonic-gate 	if (SBD_DEVS_PRESENT(sbp) == 0) {
46367c478bd9Sstevel@tonic-gate 		PR_ALL("%s: board %d has no devices present\n",
4637*d5ebc493SDan Cross 		    f, sbp->sb_num);
46387c478bd9Sstevel@tonic-gate 		return;
46397c478bd9Sstevel@tonic-gate 	}
46407c478bd9Sstevel@tonic-gate 
46417c478bd9Sstevel@tonic-gate 	ep = &error;
46427c478bd9Sstevel@tonic-gate 	bzero(ep, sizeof (sbderror_t));
46437c478bd9Sstevel@tonic-gate 
46447c478bd9Sstevel@tonic-gate 	/*
46457c478bd9Sstevel@tonic-gate 	 * Check for existence of cpus.
46467c478bd9Sstevel@tonic-gate 	 */
46477c478bd9Sstevel@tonic-gate 
46487c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
46497c478bd9Sstevel@tonic-gate 
46507c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
46517c478bd9Sstevel@tonic-gate 		processorid_t	cpuid;
46527c478bd9Sstevel@tonic-gate 
46537c478bd9Sstevel@tonic-gate 		if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i))
46547c478bd9Sstevel@tonic-gate 			continue;
46557c478bd9Sstevel@tonic-gate 
46567c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][i];
46577c478bd9Sstevel@tonic-gate 
46587c478bd9Sstevel@tonic-gate 		if (dip != NULL) {
46597c478bd9Sstevel@tonic-gate 			cpuid = sbdp_get_cpuid(hdp, dip);
46607c478bd9Sstevel@tonic-gate 
46617c478bd9Sstevel@tonic-gate 			if (cpuid < 0) {
4662*d5ebc493SDan Cross 				SBD_GET_PERR(hdp->h_err, ep);
46637c478bd9Sstevel@tonic-gate 				continue;
46647c478bd9Sstevel@tonic-gate 			}
46657c478bd9Sstevel@tonic-gate 
46667c478bd9Sstevel@tonic-gate 			mutex_enter(&cpu_lock);	/* needed to call cpu_get() */
46677c478bd9Sstevel@tonic-gate 			if (cpu_get(cpuid)) {
46687c478bd9Sstevel@tonic-gate 				SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_CPU, i);
46697c478bd9Sstevel@tonic-gate 				DEVSET_ADD(devs_attached, SBD_COMP_CPU, i);
46707c478bd9Sstevel@tonic-gate 				PR_ALL("%s: board %d, cpuid %d - attached\n",
4671*d5ebc493SDan Cross 				    f, sbp->sb_num, cpuid);
46727c478bd9Sstevel@tonic-gate 			}
46737c478bd9Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
46747c478bd9Sstevel@tonic-gate 			sbd_init_cpu_unit(sbp, i);
46757c478bd9Sstevel@tonic-gate 		}
46767c478bd9Sstevel@tonic-gate 	}
46777c478bd9Sstevel@tonic-gate 
46787c478bd9Sstevel@tonic-gate 	/*
46797c478bd9Sstevel@tonic-gate 	 * Check for existence of memory.
46807c478bd9Sstevel@tonic-gate 	 */
46817c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
46827c478bd9Sstevel@tonic-gate 		uint64_t	basepa, endpa;
46837c478bd9Sstevel@tonic-gate 		struct memlist	*ml;
46847c478bd9Sstevel@tonic-gate 		extern struct memlist	*phys_install;
46857c478bd9Sstevel@tonic-gate 
46867c478bd9Sstevel@tonic-gate 		if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i))
46877c478bd9Sstevel@tonic-gate 			continue;
46887c478bd9Sstevel@tonic-gate 
46897c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][i];
46907c478bd9Sstevel@tonic-gate 		if (dip == NULL)
46917c478bd9Sstevel@tonic-gate 			continue;
46927c478bd9Sstevel@tonic-gate 
46937c478bd9Sstevel@tonic-gate 		if (sbdphw_get_base_physaddr(hdp, dip, &basepa)) {
46947c478bd9Sstevel@tonic-gate 			/* omit phantom memory controllers on I/O boards */
46957c478bd9Sstevel@tonic-gate 			if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i)) {
46967c478bd9Sstevel@tonic-gate 				ASSERT(sbp->sb_ndev != 0);
46977c478bd9Sstevel@tonic-gate 				SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, i);
46987c478bd9Sstevel@tonic-gate 				sbp->sb_ndev--;
46997c478bd9Sstevel@tonic-gate 			}
47007c478bd9Sstevel@tonic-gate 			sbp->sb_devlist[NIX(SBD_COMP_MEM)][i] = NULL;
47017c478bd9Sstevel@tonic-gate 			continue;
47027c478bd9Sstevel@tonic-gate 		}
47037c478bd9Sstevel@tonic-gate 
47047c478bd9Sstevel@tonic-gate 		/*
47057c478bd9Sstevel@tonic-gate 		 * basepa may not be on a alignment boundary, make it so.
47067c478bd9Sstevel@tonic-gate 		 */
47077c478bd9Sstevel@tonic-gate 		if (sbdp_get_mem_alignment(hdp, dip, &endpa)) {
47087c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s sbdp_get_mem_alignment fail", f);
47097c478bd9Sstevel@tonic-gate 			continue;
47107c478bd9Sstevel@tonic-gate 		}
47117c478bd9Sstevel@tonic-gate 
47127c478bd9Sstevel@tonic-gate 		basepa &= ~(endpa - 1);
47137c478bd9Sstevel@tonic-gate 		endpa += basepa;
47147c478bd9Sstevel@tonic-gate 
47157c478bd9Sstevel@tonic-gate 		/*
47167c478bd9Sstevel@tonic-gate 		 * Check if base address is in phys_install.
47177c478bd9Sstevel@tonic-gate 		 */
47187c478bd9Sstevel@tonic-gate 		memlist_read_lock();
471956f33205SJonathan Adams 		for (ml = phys_install; ml; ml = ml->ml_next)
472056f33205SJonathan Adams 			if ((endpa <= ml->ml_address) ||
472156f33205SJonathan Adams 			    (basepa >= (ml->ml_address + ml->ml_size)))
47227c478bd9Sstevel@tonic-gate 				continue;
47237c478bd9Sstevel@tonic-gate 			else
47247c478bd9Sstevel@tonic-gate 				break;
47257c478bd9Sstevel@tonic-gate 		memlist_read_unlock();
47267c478bd9Sstevel@tonic-gate 
47277c478bd9Sstevel@tonic-gate 		if (ml) {
47287c478bd9Sstevel@tonic-gate 			SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_MEM, i);
47297c478bd9Sstevel@tonic-gate 			DEVSET_ADD(devs_attached, SBD_COMP_MEM, i);
47307c478bd9Sstevel@tonic-gate 			PR_ALL("%s: board %d, mem-unit %d - attached\n",
4731*d5ebc493SDan Cross 			    f, sbp->sb_num, i);
47327c478bd9Sstevel@tonic-gate 		}
47337c478bd9Sstevel@tonic-gate 		sbd_init_mem_unit(sbp, i, ep);
47347c478bd9Sstevel@tonic-gate 	}
47357c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
47367c478bd9Sstevel@tonic-gate 
47377c478bd9Sstevel@tonic-gate 	/*
47387c478bd9Sstevel@tonic-gate 	 * If so far we have found an error, we just log it but continue
47397c478bd9Sstevel@tonic-gate 	 */
47407c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERRNO(ep) != 0)
47417c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s errno has occurred: errno %d", f,
4742*d5ebc493SDan Cross 		    SBD_GET_ERRNO(ep));
47437c478bd9Sstevel@tonic-gate 
47447c478bd9Sstevel@tonic-gate 	/*
47457c478bd9Sstevel@tonic-gate 	 * Check for i/o state.
47467c478bd9Sstevel@tonic-gate 	 */
47477c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
47487c478bd9Sstevel@tonic-gate 
47497c478bd9Sstevel@tonic-gate 		if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_IO, i))
47507c478bd9Sstevel@tonic-gate 			continue;
47517c478bd9Sstevel@tonic-gate 
47527c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_IO)][i];
47537c478bd9Sstevel@tonic-gate 		if (dip == NULL)
47547c478bd9Sstevel@tonic-gate 			continue;
47557c478bd9Sstevel@tonic-gate 
47567c478bd9Sstevel@tonic-gate 		ASSERT(e_ddi_branch_held(dip));
47577c478bd9Sstevel@tonic-gate 
47587c478bd9Sstevel@tonic-gate 		/*
47597c478bd9Sstevel@tonic-gate 		 * XXX Is the devstate check needed ?
47607c478bd9Sstevel@tonic-gate 		 */
4761737d277aScth 		if (i_ddi_devi_attached(dip) ||
47627c478bd9Sstevel@tonic-gate 		    ddi_get_devstate(dip) == DDI_DEVSTATE_UP) {
47637c478bd9Sstevel@tonic-gate 
47647c478bd9Sstevel@tonic-gate 			/*
47657c478bd9Sstevel@tonic-gate 			 * Found it!
47667c478bd9Sstevel@tonic-gate 			 */
47677c478bd9Sstevel@tonic-gate 			SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_IO, i);
47687c478bd9Sstevel@tonic-gate 			DEVSET_ADD(devs_attached, SBD_COMP_IO, i);
47697c478bd9Sstevel@tonic-gate 			PR_ALL("%s: board %d, io-unit %d - attached\n",
4770*d5ebc493SDan Cross 			    f, sbp->sb_num, i);
47717c478bd9Sstevel@tonic-gate 		}
47727c478bd9Sstevel@tonic-gate 		sbd_init_io_unit(sbp, i);
47737c478bd9Sstevel@tonic-gate 	}
47747c478bd9Sstevel@tonic-gate 
47757c478bd9Sstevel@tonic-gate 	SBD_DEVS_CONFIGURE(sbp, devs_attached);
47767c478bd9Sstevel@tonic-gate 	if (devs_attached && ((devs_lost = SBD_DEVS_UNATTACHED(sbp)) != 0)) {
47777c478bd9Sstevel@tonic-gate 		int		ut;
47787c478bd9Sstevel@tonic-gate 		/*
47797c478bd9Sstevel@tonic-gate 		 * A prior comment stated that a partially configured
47807c478bd9Sstevel@tonic-gate 		 * board was not permitted. The Serengeti architecture
47817c478bd9Sstevel@tonic-gate 		 * makes this possible, so the SB_DEVS_DISCONNECT
47827c478bd9Sstevel@tonic-gate 		 * at the end of this block has been removed.
47837c478bd9Sstevel@tonic-gate 		 */
47847c478bd9Sstevel@tonic-gate 
47857c478bd9Sstevel@tonic-gate 		PR_ALL("%s: some devices not configured (0x%x)...\n",
4786*d5ebc493SDan Cross 		    f, devs_lost);
47877c478bd9Sstevel@tonic-gate 
47887c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++)
47897c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devs_lost, SBD_COMP_CPU, ut)) {
47907c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU,
4791*d5ebc493SDan Cross 				    ut, SBD_STATE_UNCONFIGURED);
47927c478bd9Sstevel@tonic-gate 			}
47937c478bd9Sstevel@tonic-gate 
47947c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++)
47957c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devs_lost, SBD_COMP_MEM, ut)) {
47967c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM,
4797*d5ebc493SDan Cross 				    ut, SBD_STATE_UNCONFIGURED);
47987c478bd9Sstevel@tonic-gate 			}
47997c478bd9Sstevel@tonic-gate 
48007c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++)
48017c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devs_lost, SBD_COMP_IO, ut)) {
48027c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO,
4803*d5ebc493SDan Cross 				    ut, SBD_STATE_UNCONFIGURED);
48047c478bd9Sstevel@tonic-gate 			}
48057c478bd9Sstevel@tonic-gate 	}
48067c478bd9Sstevel@tonic-gate }
48077c478bd9Sstevel@tonic-gate 
48087c478bd9Sstevel@tonic-gate static int
hold_rele_branch(dev_info_t * rdip,void * arg)48097c478bd9Sstevel@tonic-gate hold_rele_branch(dev_info_t *rdip, void *arg)
48107c478bd9Sstevel@tonic-gate {
48117c478bd9Sstevel@tonic-gate 	walk_tree_t	*wp = (walk_tree_t *)arg;
48127c478bd9Sstevel@tonic-gate 
48137c478bd9Sstevel@tonic-gate 	ASSERT(wp && (wp->hold == 0 || wp->hold == 1));
48147c478bd9Sstevel@tonic-gate 
48157c478bd9Sstevel@tonic-gate 	switch (get_node_type(wp->sbp, rdip, NULL)) {
48167c478bd9Sstevel@tonic-gate 		case SBD_COMP_CMP:
48177c478bd9Sstevel@tonic-gate 		case SBD_COMP_MEM:
48187c478bd9Sstevel@tonic-gate 		case SBD_COMP_IO:
48197c478bd9Sstevel@tonic-gate 			break;
48207c478bd9Sstevel@tonic-gate 		case SBD_COMP_CPU:
48217c478bd9Sstevel@tonic-gate 
48227c478bd9Sstevel@tonic-gate 			/*
48237c478bd9Sstevel@tonic-gate 			 * All CPU nodes under CMP nodes should have
48247c478bd9Sstevel@tonic-gate 			 * gotten pruned when the CMP node was first
48257c478bd9Sstevel@tonic-gate 			 * encountered.
48267c478bd9Sstevel@tonic-gate 			 */
48277c478bd9Sstevel@tonic-gate 			ASSERT(!sbd_is_cmp_child(rdip));
48287c478bd9Sstevel@tonic-gate 
48297c478bd9Sstevel@tonic-gate 			break;
48307c478bd9Sstevel@tonic-gate 
48317c478bd9Sstevel@tonic-gate 		case SBD_COMP_UNKNOWN:
48327c478bd9Sstevel@tonic-gate 			/* Not of interest to us */
48337c478bd9Sstevel@tonic-gate 			return (DDI_WALK_CONTINUE);
48347c478bd9Sstevel@tonic-gate 		default:
48357c478bd9Sstevel@tonic-gate 			ASSERT(0);
48367c478bd9Sstevel@tonic-gate 			return (DDI_WALK_PRUNECHILD);
48377c478bd9Sstevel@tonic-gate 	}
48387c478bd9Sstevel@tonic-gate 
48397c478bd9Sstevel@tonic-gate 	if (wp->hold) {
48407c478bd9Sstevel@tonic-gate 		ASSERT(!e_ddi_branch_held(rdip));
48417c478bd9Sstevel@tonic-gate 		e_ddi_branch_hold(rdip);
48427c478bd9Sstevel@tonic-gate 	} else {
48437c478bd9Sstevel@tonic-gate 		ASSERT(e_ddi_branch_held(rdip));
48447c478bd9Sstevel@tonic-gate 		e_ddi_branch_rele(rdip);
48457c478bd9Sstevel@tonic-gate 	}
48467c478bd9Sstevel@tonic-gate 
48477c478bd9Sstevel@tonic-gate 	return (DDI_WALK_PRUNECHILD);
48487c478bd9Sstevel@tonic-gate }
48497c478bd9Sstevel@tonic-gate 
48507c478bd9Sstevel@tonic-gate static void
sbd_board_init(sbd_board_t * sbp,sbd_softstate_t * softsp,int bd,dev_info_t * top_dip,int wnode)48517c478bd9Sstevel@tonic-gate sbd_board_init(sbd_board_t *sbp, sbd_softstate_t *softsp,
4852*d5ebc493SDan Cross     int bd, dev_info_t *top_dip, int wnode)
48537c478bd9Sstevel@tonic-gate {
48547c478bd9Sstevel@tonic-gate 	int		i;
48557c478bd9Sstevel@tonic-gate 	dev_info_t	*pdip;
48567c478bd9Sstevel@tonic-gate 	walk_tree_t	walk = {0};
48577c478bd9Sstevel@tonic-gate 
48587c478bd9Sstevel@tonic-gate 	mutex_init(&sbp->sb_mutex, NULL, MUTEX_DRIVER, NULL);
48597c478bd9Sstevel@tonic-gate 	mutex_init(&sbp->sb_flags_mutex, NULL, MUTEX_DRIVER, NULL);
48607c478bd9Sstevel@tonic-gate 	mutex_init(&sbp->sb_slock, NULL, MUTEX_DRIVER, NULL);
48617c478bd9Sstevel@tonic-gate 
48627c478bd9Sstevel@tonic-gate 	sbp->sb_ref = 0;
48637c478bd9Sstevel@tonic-gate 	sbp->sb_num = bd;
48647c478bd9Sstevel@tonic-gate 	sbp->sb_time = gethrestime_sec();
48657c478bd9Sstevel@tonic-gate 	/*
48667c478bd9Sstevel@tonic-gate 	 * For serengeti, top_dip doesn't need to be held because
48677c478bd9Sstevel@tonic-gate 	 * sbp i.e. sbd_board_t will be destroyed in sbd_teardown_instance()
48687c478bd9Sstevel@tonic-gate 	 * before top_dip detaches. For Daktari, top_dip is the
48697c478bd9Sstevel@tonic-gate 	 * root node which never has to be held.
48707c478bd9Sstevel@tonic-gate 	 */
48717c478bd9Sstevel@tonic-gate 	sbp->sb_topdip = top_dip;
48727c478bd9Sstevel@tonic-gate 	sbp->sb_cpuid = -1;
48737c478bd9Sstevel@tonic-gate 	sbp->sb_softsp = (void *) softsp;
48747c478bd9Sstevel@tonic-gate 	sbp->sb_cond = SBD_COND_UNKNOWN;
48757c478bd9Sstevel@tonic-gate 	sbp->sb_wnode = wnode;
48767c478bd9Sstevel@tonic-gate 	sbp->sb_memaccess_ok = 1;
48777c478bd9Sstevel@tonic-gate 
48787c478bd9Sstevel@tonic-gate 	ASSERT(MAX_IO_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD);
48797c478bd9Sstevel@tonic-gate 	ASSERT(MAX_CPU_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD);
48807c478bd9Sstevel@tonic-gate 	ASSERT(MAX_MEM_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD);
48817c478bd9Sstevel@tonic-gate 
48827c478bd9Sstevel@tonic-gate 	/*
48837c478bd9Sstevel@tonic-gate 	 * Allocate the devlist for cpus.
48847c478bd9Sstevel@tonic-gate 	 */
4885*d5ebc493SDan Cross 	sbp->sb_devlist[NIX(SBD_COMP_CPU)] =
4886*d5ebc493SDan Cross 	    GETSTRUCT(dev_info_t *, MAX_CPU_UNITS_PER_BOARD);
48877c478bd9Sstevel@tonic-gate 
48887c478bd9Sstevel@tonic-gate 	/*
48897c478bd9Sstevel@tonic-gate 	 * Allocate the devlist for mem.
48907c478bd9Sstevel@tonic-gate 	 */
4891*d5ebc493SDan Cross 	sbp->sb_devlist[NIX(SBD_COMP_MEM)] =
4892*d5ebc493SDan Cross 	    GETSTRUCT(dev_info_t *, MAX_MEM_UNITS_PER_BOARD);
48937c478bd9Sstevel@tonic-gate 
48947c478bd9Sstevel@tonic-gate 	/*
48957c478bd9Sstevel@tonic-gate 	 * Allocate the devlist for io.
48967c478bd9Sstevel@tonic-gate 	 */
4897*d5ebc493SDan Cross 	sbp->sb_devlist[NIX(SBD_COMP_IO)] =
4898*d5ebc493SDan Cross 	    GETSTRUCT(dev_info_t *, MAX_IO_UNITS_PER_BOARD);
48997c478bd9Sstevel@tonic-gate 
49007c478bd9Sstevel@tonic-gate 
4901*d5ebc493SDan Cross 	sbp->sb_dev[NIX(SBD_COMP_CPU)] =
4902*d5ebc493SDan Cross 	    GETSTRUCT(sbd_dev_unit_t, MAX_CPU_UNITS_PER_BOARD);
49037c478bd9Sstevel@tonic-gate 
4904*d5ebc493SDan Cross 	sbp->sb_dev[NIX(SBD_COMP_MEM)] =
4905*d5ebc493SDan Cross 	    GETSTRUCT(sbd_dev_unit_t, MAX_MEM_UNITS_PER_BOARD);
49067c478bd9Sstevel@tonic-gate 
4907*d5ebc493SDan Cross 	sbp->sb_dev[NIX(SBD_COMP_IO)] =
4908*d5ebc493SDan Cross 	    GETSTRUCT(sbd_dev_unit_t, MAX_IO_UNITS_PER_BOARD);
49097c478bd9Sstevel@tonic-gate 
49107c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
49117c478bd9Sstevel@tonic-gate 		sbp->sb_cpupath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
49127c478bd9Sstevel@tonic-gate 	}
49137c478bd9Sstevel@tonic-gate 
49147c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
49157c478bd9Sstevel@tonic-gate 		sbp->sb_mempath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
49167c478bd9Sstevel@tonic-gate 	}
49177c478bd9Sstevel@tonic-gate 
49187c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
49197c478bd9Sstevel@tonic-gate 		sbp->sb_iopath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
49207c478bd9Sstevel@tonic-gate 	}
49217c478bd9Sstevel@tonic-gate 
49227c478bd9Sstevel@tonic-gate 	/*
49237c478bd9Sstevel@tonic-gate 	 * Walk the device tree, find all top dips on this board and
49247c478bd9Sstevel@tonic-gate 	 * hold the branches rooted at them
49257c478bd9Sstevel@tonic-gate 	 */
49267c478bd9Sstevel@tonic-gate 	ASSERT(sbp->sb_topdip);
49277c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(sbp->sb_topdip);
49287c478bd9Sstevel@tonic-gate 	if (pdip)
49293fe80ca4SDan Cross 		ndi_devi_enter(pdip);
49307c478bd9Sstevel@tonic-gate 	walk.sbp = sbp;
49317c478bd9Sstevel@tonic-gate 	walk.hold = 1;
49327c478bd9Sstevel@tonic-gate 	ddi_walk_devs(sbp->sb_topdip, hold_rele_branch, (void *)&walk);
49337c478bd9Sstevel@tonic-gate 	if (pdip)
49343fe80ca4SDan Cross 		ndi_devi_exit(pdip);
49357c478bd9Sstevel@tonic-gate 
49367c478bd9Sstevel@tonic-gate 	/*
49377c478bd9Sstevel@tonic-gate 	 * Initialize the devlists
49387c478bd9Sstevel@tonic-gate 	 */
49397c478bd9Sstevel@tonic-gate 	if (sbd_init_devlists(sbp) == 0) {
49407c478bd9Sstevel@tonic-gate 		SBD_BOARD_TRANSITION(sbp, SBD_STATE_EMPTY);
49417c478bd9Sstevel@tonic-gate 	} else {
49427c478bd9Sstevel@tonic-gate 		/*
49437c478bd9Sstevel@tonic-gate 		 * Couldn't have made it down here without
49447c478bd9Sstevel@tonic-gate 		 * having found at least one device.
49457c478bd9Sstevel@tonic-gate 		 */
49467c478bd9Sstevel@tonic-gate 		ASSERT(SBD_DEVS_PRESENT(sbp) != 0);
49477c478bd9Sstevel@tonic-gate 		/*
49487c478bd9Sstevel@tonic-gate 		 * Check the state of any possible devices on the
49497c478bd9Sstevel@tonic-gate 		 * board.
49507c478bd9Sstevel@tonic-gate 		 */
49517c478bd9Sstevel@tonic-gate 		sbd_board_discovery(sbp);
49527c478bd9Sstevel@tonic-gate 
49537c478bd9Sstevel@tonic-gate 		if (SBD_DEVS_UNATTACHED(sbp) == 0) {
49547c478bd9Sstevel@tonic-gate 			/*
49557c478bd9Sstevel@tonic-gate 			 * The board has no unattached devices, therefore
49567c478bd9Sstevel@tonic-gate 			 * by reason of insanity it must be configured!
49577c478bd9Sstevel@tonic-gate 			 */
49587c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED);
49597c478bd9Sstevel@tonic-gate 			sbp->sb_cond = SBD_COND_OK;
49607c478bd9Sstevel@tonic-gate 		} else if (SBD_DEVS_ATTACHED(sbp)) {
49617c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL);
49627c478bd9Sstevel@tonic-gate 		} else {
49637c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONNECTED);
49647c478bd9Sstevel@tonic-gate 		}
49657c478bd9Sstevel@tonic-gate 	}
49667c478bd9Sstevel@tonic-gate }
49677c478bd9Sstevel@tonic-gate 
49687c478bd9Sstevel@tonic-gate static void
sbd_board_destroy(sbd_board_t * sbp)49697c478bd9Sstevel@tonic-gate sbd_board_destroy(sbd_board_t *sbp)
49707c478bd9Sstevel@tonic-gate {
49717c478bd9Sstevel@tonic-gate 	int		i;
49727c478bd9Sstevel@tonic-gate 	dev_info_t	*pdip;
49737c478bd9Sstevel@tonic-gate 	walk_tree_t	walk = {0};
49747c478bd9Sstevel@tonic-gate 
49757c478bd9Sstevel@tonic-gate 	SBD_BOARD_TRANSITION(sbp, SBD_STATE_EMPTY);
49767c478bd9Sstevel@tonic-gate 
49777c478bd9Sstevel@tonic-gate #ifdef DEBUG
49787c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
49797c478bd9Sstevel@tonic-gate 		sbd_mem_unit_t *mp;
49807c478bd9Sstevel@tonic-gate 
49817c478bd9Sstevel@tonic-gate 		mp = SBD_GET_BOARD_MEMUNIT(sbp, i);
49827c478bd9Sstevel@tonic-gate 		ASSERT(mp->sbm_mlist == NULL);
49837c478bd9Sstevel@tonic-gate 	}
49847c478bd9Sstevel@tonic-gate #endif /* DEBUG */
49857c478bd9Sstevel@tonic-gate 
49867c478bd9Sstevel@tonic-gate 	/*
49877c478bd9Sstevel@tonic-gate 	 * Free up MEM unit structs.
49887c478bd9Sstevel@tonic-gate 	 */
49897c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_MEM)],
4990*d5ebc493SDan Cross 	    sbd_dev_unit_t, MAX_MEM_UNITS_PER_BOARD);
49917c478bd9Sstevel@tonic-gate 	sbp->sb_dev[NIX(SBD_COMP_MEM)] = NULL;
49927c478bd9Sstevel@tonic-gate 
49937c478bd9Sstevel@tonic-gate 	/*
49947c478bd9Sstevel@tonic-gate 	 * Free up CPU unit structs.
49957c478bd9Sstevel@tonic-gate 	 */
49967c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_CPU)],
4997*d5ebc493SDan Cross 	    sbd_dev_unit_t, MAX_CPU_UNITS_PER_BOARD);
49987c478bd9Sstevel@tonic-gate 	sbp->sb_dev[NIX(SBD_COMP_CPU)] = NULL;
49997c478bd9Sstevel@tonic-gate 
50007c478bd9Sstevel@tonic-gate 	/*
50017c478bd9Sstevel@tonic-gate 	 * Free up IO unit structs.
50027c478bd9Sstevel@tonic-gate 	 */
50037c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_IO)],
5004*d5ebc493SDan Cross 	    sbd_dev_unit_t, MAX_IO_UNITS_PER_BOARD);
50057c478bd9Sstevel@tonic-gate 	sbp->sb_dev[NIX(SBD_COMP_IO)] = NULL;
50067c478bd9Sstevel@tonic-gate 
50077c478bd9Sstevel@tonic-gate 	/*
50087c478bd9Sstevel@tonic-gate 	 * free up CPU devlists.
50097c478bd9Sstevel@tonic-gate 	 */
50107c478bd9Sstevel@tonic-gate 
50117c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
50127c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)sbp->sb_cpupath[i], MAXPATHLEN);
50137c478bd9Sstevel@tonic-gate 	}
50147c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_CPU)], dev_info_t *,
5015*d5ebc493SDan Cross 	    MAX_CPU_UNITS_PER_BOARD);
50167c478bd9Sstevel@tonic-gate 	sbp->sb_devlist[NIX(SBD_COMP_CPU)] = NULL;
50177c478bd9Sstevel@tonic-gate 
50187c478bd9Sstevel@tonic-gate 	/*
50197c478bd9Sstevel@tonic-gate 	 * free up MEM devlists.
50207c478bd9Sstevel@tonic-gate 	 */
50217c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
50227c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)sbp->sb_mempath[i], MAXPATHLEN);
50237c478bd9Sstevel@tonic-gate 	}
50247c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_MEM)], dev_info_t *,
5025*d5ebc493SDan Cross 	    MAX_MEM_UNITS_PER_BOARD);
50267c478bd9Sstevel@tonic-gate 	sbp->sb_devlist[NIX(SBD_COMP_MEM)] = NULL;
50277c478bd9Sstevel@tonic-gate 
50287c478bd9Sstevel@tonic-gate 	/*
50297c478bd9Sstevel@tonic-gate 	 * free up IO devlists.
50307c478bd9Sstevel@tonic-gate 	 */
50317c478bd9Sstevel@tonic-gate 	for (i = 0; i <  MAX_IO_UNITS_PER_BOARD; i++) {
50327c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)sbp->sb_iopath[i], MAXPATHLEN);
50337c478bd9Sstevel@tonic-gate 	}
50347c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_IO)], dev_info_t *,
5035*d5ebc493SDan Cross 	    MAX_IO_UNITS_PER_BOARD);
50367c478bd9Sstevel@tonic-gate 	sbp->sb_devlist[NIX(SBD_COMP_IO)] = NULL;
50377c478bd9Sstevel@tonic-gate 
50387c478bd9Sstevel@tonic-gate 	/*
50397c478bd9Sstevel@tonic-gate 	 * Release all branches held earlier
50407c478bd9Sstevel@tonic-gate 	 */
50417c478bd9Sstevel@tonic-gate 	ASSERT(sbp->sb_topdip);
50427c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(sbp->sb_topdip);
50437c478bd9Sstevel@tonic-gate 	if (pdip)
50443fe80ca4SDan Cross 		ndi_devi_enter(pdip);
50457c478bd9Sstevel@tonic-gate 	walk.sbp = sbp;
50467c478bd9Sstevel@tonic-gate 	walk.hold = 0;
50477c478bd9Sstevel@tonic-gate 	ddi_walk_devs(sbp->sb_topdip, hold_rele_branch, (void *)&walk);
50487c478bd9Sstevel@tonic-gate 	if (pdip)
50493fe80ca4SDan Cross 		ndi_devi_exit(pdip);
50507c478bd9Sstevel@tonic-gate 
50517c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbp->sb_slock);
50527c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbp->sb_flags_mutex);
50537c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbp->sb_mutex);
50547c478bd9Sstevel@tonic-gate }
50557c478bd9Sstevel@tonic-gate 
50567c478bd9Sstevel@tonic-gate sbd_comp_type_t
sbd_cm_type(char * name)50577c478bd9Sstevel@tonic-gate sbd_cm_type(char *name)
50587c478bd9Sstevel@tonic-gate {
50597c478bd9Sstevel@tonic-gate 	sbd_comp_type_t type = SBD_COMP_UNKNOWN;
50607c478bd9Sstevel@tonic-gate 	int i;
50617c478bd9Sstevel@tonic-gate 
50627c478bd9Sstevel@tonic-gate 	/* look up type in table */
50637c478bd9Sstevel@tonic-gate 	for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) {
50647c478bd9Sstevel@tonic-gate 		if (strcmp(name, SBD_OTYPE(i)) == 0) {
50657c478bd9Sstevel@tonic-gate 			type = SBD_COMP(i);
50667c478bd9Sstevel@tonic-gate 			break;
50677c478bd9Sstevel@tonic-gate 		}
50687c478bd9Sstevel@tonic-gate 	}
50697c478bd9Sstevel@tonic-gate 
50707c478bd9Sstevel@tonic-gate 	return (type);
50717c478bd9Sstevel@tonic-gate }
50727c478bd9Sstevel@tonic-gate 
50737c478bd9Sstevel@tonic-gate /*
50747c478bd9Sstevel@tonic-gate  * There are certain cases where obp marks components as failed
50757c478bd9Sstevel@tonic-gate  * If the status is ok the node won't have any status property. It
50767c478bd9Sstevel@tonic-gate  * is only there if the status is other than ok.
50777c478bd9Sstevel@tonic-gate  *
50787c478bd9Sstevel@tonic-gate  * The translation is as follows:
50797c478bd9Sstevel@tonic-gate  * If there is no status prop, the the cond is SBD_COND_OK
50807c478bd9Sstevel@tonic-gate  * If we find a status prop but can't get to it then cond is SBD_COND_UNKNOWN
50817c478bd9Sstevel@tonic-gate  * if we find a stat and it is failed the cond is SBD_COND_FAILED
50827c478bd9Sstevel@tonic-gate  * If the stat is disabled, the cond is SBD_COND_UNUSABLE
50837c478bd9Sstevel@tonic-gate  * Otherwise we return con as SBD_COND_OK
50847c478bd9Sstevel@tonic-gate  */
50857c478bd9Sstevel@tonic-gate sbd_cond_t
sbd_get_comp_cond(dev_info_t * dip)50867c478bd9Sstevel@tonic-gate sbd_get_comp_cond(dev_info_t *dip)
50877c478bd9Sstevel@tonic-gate {
50887c478bd9Sstevel@tonic-gate 	int			len;
50897c478bd9Sstevel@tonic-gate 	char			*status_buf;
50907c478bd9Sstevel@tonic-gate 	static const char	*status = "status";
50917c478bd9Sstevel@tonic-gate 	static const char	*failed = "fail";
50927c478bd9Sstevel@tonic-gate 	static const char	*disabled = "disabled";
50937c478bd9Sstevel@tonic-gate 
50947c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
50957c478bd9Sstevel@tonic-gate 		PR_BYP("dip is NULL\n");
50967c478bd9Sstevel@tonic-gate 		return (SBD_COND_UNKNOWN);
50977c478bd9Sstevel@tonic-gate 	}
50987c478bd9Sstevel@tonic-gate 
509925e8c5aaSvikram 	/*
510025e8c5aaSvikram 	 * If retired, return FAILED
510125e8c5aaSvikram 	 */
510225e8c5aaSvikram 	if (DEVI(dip)->devi_flags & DEVI_RETIRED) {
510325e8c5aaSvikram 		PR_CPU("dip is retired\n");
510425e8c5aaSvikram 		return (SBD_COND_FAILED);
510525e8c5aaSvikram 	}
510625e8c5aaSvikram 
51077c478bd9Sstevel@tonic-gate 	if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
51087c478bd9Sstevel@tonic-gate 	    (char *)status, &len) != DDI_PROP_SUCCESS) {
51097c478bd9Sstevel@tonic-gate 		PR_CPU("status in sbd is ok\n");
51107c478bd9Sstevel@tonic-gate 		return (SBD_COND_OK);
51117c478bd9Sstevel@tonic-gate 	}
51127c478bd9Sstevel@tonic-gate 
51137c478bd9Sstevel@tonic-gate 	status_buf = kmem_zalloc(sizeof (char) * OBP_MAXPROPNAME, KM_SLEEP);
5114a3282898Scth 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
51157c478bd9Sstevel@tonic-gate 	    (char *)status, status_buf, &len) != DDI_PROP_SUCCESS) {
51167c478bd9Sstevel@tonic-gate 		PR_CPU("status in sbd is unknown\n");
51177c478bd9Sstevel@tonic-gate 		return (SBD_COND_UNKNOWN);
51187c478bd9Sstevel@tonic-gate 	}
51197c478bd9Sstevel@tonic-gate 
51207c478bd9Sstevel@tonic-gate 	if (strncmp(status_buf, failed, strlen(failed)) == 0) {
51217c478bd9Sstevel@tonic-gate 		PR_CPU("status in sbd is failed\n");
51227c478bd9Sstevel@tonic-gate 		kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME);
51237c478bd9Sstevel@tonic-gate 		return (SBD_COND_FAILED);
51247c478bd9Sstevel@tonic-gate 	}
51257c478bd9Sstevel@tonic-gate 
51267c478bd9Sstevel@tonic-gate 	if (strcmp(status_buf, disabled) == 0) {
51277c478bd9Sstevel@tonic-gate 		PR_CPU("status in sbd is unusable\n");
51287c478bd9Sstevel@tonic-gate 		kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME);
51297c478bd9Sstevel@tonic-gate 		return (SBD_COND_UNUSABLE);
51307c478bd9Sstevel@tonic-gate 	}
51317c478bd9Sstevel@tonic-gate 
51327c478bd9Sstevel@tonic-gate 	kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME);
51337c478bd9Sstevel@tonic-gate 	return (SBD_COND_OK);
51347c478bd9Sstevel@tonic-gate }
51357c478bd9Sstevel@tonic-gate 
51367c478bd9Sstevel@tonic-gate #ifdef SBD_DEBUG_ERRS
51377c478bd9Sstevel@tonic-gate 
51387c478bd9Sstevel@tonic-gate /* function to simulate errors throughout the sbd code */
51397c478bd9Sstevel@tonic-gate void
sbd_inject_err(int error,sbderror_t * ep,int Errno,int ecode,char * rsc)51407c478bd9Sstevel@tonic-gate sbd_inject_err(int error, sbderror_t *ep, int Errno, int ecode,
5141*d5ebc493SDan Cross     char *rsc)
51427c478bd9Sstevel@tonic-gate {
51437c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_inject_err";
51447c478bd9Sstevel@tonic-gate 
51457c478bd9Sstevel@tonic-gate 	if (sbd_err_debug == 0)
51467c478bd9Sstevel@tonic-gate 		return;
51477c478bd9Sstevel@tonic-gate 
51487c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
51497c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s ep is NULL", f);
51507c478bd9Sstevel@tonic-gate 		return;
51517c478bd9Sstevel@tonic-gate 	}
51527c478bd9Sstevel@tonic-gate 
51537c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERRNO(ep) != 0) {
51547c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s errno already set to %d", f,
5155*d5ebc493SDan Cross 		    SBD_GET_ERRNO(ep));
51567c478bd9Sstevel@tonic-gate 		return;
51577c478bd9Sstevel@tonic-gate 	}
51587c478bd9Sstevel@tonic-gate 
51597c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERR(ep) != 0) {
51607c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s code already set to %d", f,
5161*d5ebc493SDan Cross 		    SBD_GET_ERR(ep));
51627c478bd9Sstevel@tonic-gate 		return;
51637c478bd9Sstevel@tonic-gate 	}
51647c478bd9Sstevel@tonic-gate 
51657c478bd9Sstevel@tonic-gate 	if ((sbd_err_debug & (1 << error)) != 0) {
51667c478bd9Sstevel@tonic-gate 		ep->e_errno = Errno;
51677c478bd9Sstevel@tonic-gate 		ep->e_code = ecode;
51687c478bd9Sstevel@tonic-gate 
51697c478bd9Sstevel@tonic-gate 		if (rsc != NULL)
5170*d5ebc493SDan Cross 			bcopy((caddr_t)rsc, (caddr_t)ep->e_rsc,
5171*d5ebc493SDan Cross 			    sizeof (ep->e_rsc));
51727c478bd9Sstevel@tonic-gate 
51737c478bd9Sstevel@tonic-gate 		if (Errno != 0)
51747c478bd9Sstevel@tonic-gate 			PR_ERR_ERRNO("%s set errno to %d", f, ep->e_errno);
51757c478bd9Sstevel@tonic-gate 
51767c478bd9Sstevel@tonic-gate 		if (ecode != 0)
51777c478bd9Sstevel@tonic-gate 			PR_ERR_ECODE("%s set ecode to %d", f, ep->e_code);
51787c478bd9Sstevel@tonic-gate 
51797c478bd9Sstevel@tonic-gate 		if (rsc != NULL)
51807c478bd9Sstevel@tonic-gate 			PR_ERR_RSC("%s set rsc to %s", f, ep->e_rsc);
51817c478bd9Sstevel@tonic-gate 	}
51827c478bd9Sstevel@tonic-gate }
51837c478bd9Sstevel@tonic-gate #endif
5184