xref: /titanic_51/usr/src/uts/sun4u/io/sbd.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * safari system board DR module.
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/devops.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/poll.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/mem_config.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/mem_cage.h>
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate #include <sys/sbdpriv.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/sbd_io.h>
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate /* start sbd includes */
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
66*7c478bd9Sstevel@tonic-gate #include <sys/x_call.h>
67*7c478bd9Sstevel@tonic-gate #include <sys/membar.h>
68*7c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate extern int nulldev();
71*7c478bd9Sstevel@tonic-gate extern int nodev();
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate typedef struct {		/* arg to sbd_get_handle */
74*7c478bd9Sstevel@tonic-gate 	dev_t	dev;
75*7c478bd9Sstevel@tonic-gate 	int	cmd;
76*7c478bd9Sstevel@tonic-gate 	int	mode;
77*7c478bd9Sstevel@tonic-gate 	sbd_ioctl_arg_t *ioargp;
78*7c478bd9Sstevel@tonic-gate } sbd_init_arg_t;
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * sbd support operations.
83*7c478bd9Sstevel@tonic-gate  */
84*7c478bd9Sstevel@tonic-gate static void	sbd_exec_op(sbd_handle_t *hp);
85*7c478bd9Sstevel@tonic-gate static void	sbd_dev_configure(sbd_handle_t *hp);
86*7c478bd9Sstevel@tonic-gate static int	sbd_dev_release(sbd_handle_t *hp);
87*7c478bd9Sstevel@tonic-gate static int	sbd_dev_unconfigure(sbd_handle_t *hp);
88*7c478bd9Sstevel@tonic-gate static void	sbd_attach_cpu(sbd_handle_t *hp, sbderror_t *ep,
89*7c478bd9Sstevel@tonic-gate 				dev_info_t *dip, int unit);
90*7c478bd9Sstevel@tonic-gate static void	sbd_detach_cpu(sbd_handle_t *hp, sbderror_t *ep,
91*7c478bd9Sstevel@tonic-gate 				dev_info_t *dip, int unit);
92*7c478bd9Sstevel@tonic-gate static int	sbd_detach_mem(sbd_handle_t *hp, sbderror_t *ep, int unit);
93*7c478bd9Sstevel@tonic-gate static void	sbd_cancel(sbd_handle_t *hp);
94*7c478bd9Sstevel@tonic-gate void 	sbd_errno_decode(int err, sbderror_t *ep, dev_info_t *dip);
95*7c478bd9Sstevel@tonic-gate int		sbd_dealloc_instance(sbd_board_t *sbp, int max_boards);
96*7c478bd9Sstevel@tonic-gate int		sbd_errno2ecode(int error);
97*7c478bd9Sstevel@tonic-gate #pragma weak sbdp_cpu_get_impl
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
100*7c478bd9Sstevel@tonic-gate uint_t	sbd_debug	=	(uint_t)0x0;
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate #ifdef SBD_DEBUG_ERRS
103*7c478bd9Sstevel@tonic-gate /* controls which errors are injected */
104*7c478bd9Sstevel@tonic-gate uint_t	sbd_err_debug	=	(uint_t)0x0;
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate /* controls printing about error injection */
107*7c478bd9Sstevel@tonic-gate uint_t	sbd_print_errs	=	(uint_t)0x0;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate #endif /* SBD_DEBUG_ERRS */
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate char	*sbd_state_str[] = {
114*7c478bd9Sstevel@tonic-gate 	"EMPTY", "OCCUPIED", "CONNECTED", "UNCONFIGURED",
115*7c478bd9Sstevel@tonic-gate 	"PARTIAL", "CONFIGURED", "RELEASE", "UNREFERENCED",
116*7c478bd9Sstevel@tonic-gate 	"FATAL"
117*7c478bd9Sstevel@tonic-gate };
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate /*	Note: this must be changed in tandem with sbd_ioctl.h	*/
120*7c478bd9Sstevel@tonic-gate char	*sbd_ct_str[] = {
121*7c478bd9Sstevel@tonic-gate 	"NONE", "CPU", "MEM", "IO", "UNKNOWN"
122*7c478bd9Sstevel@tonic-gate };
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate /*	Note: this must also be changed in tandem with sbd_ioctl.h */
125*7c478bd9Sstevel@tonic-gate #define	SBD_CMD_STR(c) \
126*7c478bd9Sstevel@tonic-gate 	(((c) == SBD_CMD_ASSIGN)	? "ASSIGN"	: \
127*7c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_UNASSIGN)	? "UNASSIGN"	: \
128*7c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_POWERON)	? "POWERON"	: \
129*7c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_POWEROFF)	? "POWEROFF"	: \
130*7c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_TEST)		? "TEST"	: \
131*7c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_CONNECT)	? "CONNECT"	: \
132*7c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_CONFIGURE)	? "CONFIGURE"	: \
133*7c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_UNCONFIGURE)	? "UNCONFIGURE"	: \
134*7c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_DISCONNECT)	? "DISCONNECT"	: \
135*7c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_STATUS)		? "STATUS"	: \
136*7c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_GETNCM)		? "GETNCM"	: \
137*7c478bd9Sstevel@tonic-gate 	((c) == SBD_CMD_PASSTHRU)	? "PASSTHRU"	: "unknown")
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate /*
140*7c478bd9Sstevel@tonic-gate  * Defines and structures for device tree naming and mapping
141*7c478bd9Sstevel@tonic-gate  * to node types
142*7c478bd9Sstevel@tonic-gate  */
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate sbd_devattr_t *sbd_devattr;
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate /* defines to access the attribute struct */
147*7c478bd9Sstevel@tonic-gate #define	SBD_DEVNAME(i)		sbd_devattr[i].s_devname
148*7c478bd9Sstevel@tonic-gate #define	SBD_OTYPE(i)		sbd_devattr[(i)].s_obp_type
149*7c478bd9Sstevel@tonic-gate #define	SBD_COMP(i)		sbd_devattr[i].s_dnodetype
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate /*
152*7c478bd9Sstevel@tonic-gate  * State transition table.  States valid transitions for "board" state.
153*7c478bd9Sstevel@tonic-gate  * Recall that non-zero return value terminates operation, however
154*7c478bd9Sstevel@tonic-gate  * the herrno value is what really indicates an error , if any.
155*7c478bd9Sstevel@tonic-gate  */
156*7c478bd9Sstevel@tonic-gate static int
157*7c478bd9Sstevel@tonic-gate _cmd2index(int c)
158*7c478bd9Sstevel@tonic-gate {
159*7c478bd9Sstevel@tonic-gate 	/*
160*7c478bd9Sstevel@tonic-gate 	 * Translate DR CMD to index into sbd_state_transition.
161*7c478bd9Sstevel@tonic-gate 	 */
162*7c478bd9Sstevel@tonic-gate 	switch (c) {
163*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_CONNECT:		return (0);
164*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:	return (1);
165*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:		return (2);
166*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:	return (3);
167*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_POWEROFF:		return (4);
168*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_POWERON:		return (5);
169*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_UNASSIGN:		return (6);
170*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_ASSIGN:		return (7);
171*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_TEST:		return (8);
172*7c478bd9Sstevel@tonic-gate 	default:			return (-1);
173*7c478bd9Sstevel@tonic-gate 	}
174*7c478bd9Sstevel@tonic-gate }
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate #define	CMD2INDEX(c)	_cmd2index(c)
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate static struct sbd_state_trans {
179*7c478bd9Sstevel@tonic-gate 	int	x_cmd;
180*7c478bd9Sstevel@tonic-gate 	struct {
181*7c478bd9Sstevel@tonic-gate 		int	x_rv;		/* return value of pre_op */
182*7c478bd9Sstevel@tonic-gate 		int	x_err;		/* errno, if any */
183*7c478bd9Sstevel@tonic-gate 	} x_op[SBD_NUM_STATES];
184*7c478bd9Sstevel@tonic-gate } sbd_state_transition[] = {
185*7c478bd9Sstevel@tonic-gate 	{ SBD_CMD_CONNECT,
186*7c478bd9Sstevel@tonic-gate 		{
187*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* empty */
188*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
189*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
190*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
191*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
192*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
193*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
194*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
195*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
196*7c478bd9Sstevel@tonic-gate 		}
197*7c478bd9Sstevel@tonic-gate 	},
198*7c478bd9Sstevel@tonic-gate 	{ SBD_CMD_DISCONNECT,
199*7c478bd9Sstevel@tonic-gate 		{
200*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
201*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
202*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* connected */
203*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* unconfigured */
204*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
205*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
206*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
207*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
208*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
209*7c478bd9Sstevel@tonic-gate 		}
210*7c478bd9Sstevel@tonic-gate 	},
211*7c478bd9Sstevel@tonic-gate 	{ SBD_CMD_CONFIGURE,
212*7c478bd9Sstevel@tonic-gate 		{
213*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
214*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* occupied */
215*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* connected */
216*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* unconfigured */
217*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* partial */
218*7c478bd9Sstevel@tonic-gate 			{ 1, 0 },	/* configured */
219*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* release */
220*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* unreferenced */
221*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
222*7c478bd9Sstevel@tonic-gate 		}
223*7c478bd9Sstevel@tonic-gate 	},
224*7c478bd9Sstevel@tonic-gate 	{ SBD_CMD_UNCONFIGURE,
225*7c478bd9Sstevel@tonic-gate 		{
226*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
227*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* occupied */
228*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
229*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
230*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
231*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* configured */
232*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* release */
233*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* unreferenced */
234*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
235*7c478bd9Sstevel@tonic-gate 		}
236*7c478bd9Sstevel@tonic-gate 	},
237*7c478bd9Sstevel@tonic-gate 	{ SBD_CMD_POWEROFF,
238*7c478bd9Sstevel@tonic-gate 		{
239*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
240*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
241*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
242*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
243*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
244*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
245*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
246*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
247*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
248*7c478bd9Sstevel@tonic-gate 		}
249*7c478bd9Sstevel@tonic-gate 	},
250*7c478bd9Sstevel@tonic-gate 	{ SBD_CMD_POWERON,
251*7c478bd9Sstevel@tonic-gate 		{
252*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
253*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
254*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
255*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
256*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
257*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
258*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
259*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
260*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
261*7c478bd9Sstevel@tonic-gate 		}
262*7c478bd9Sstevel@tonic-gate 	},
263*7c478bd9Sstevel@tonic-gate 	{ SBD_CMD_UNASSIGN,
264*7c478bd9Sstevel@tonic-gate 		{
265*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
266*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
267*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
268*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
269*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
270*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
271*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
272*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
273*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
274*7c478bd9Sstevel@tonic-gate 		}
275*7c478bd9Sstevel@tonic-gate 	},
276*7c478bd9Sstevel@tonic-gate 	{ SBD_CMD_ASSIGN,
277*7c478bd9Sstevel@tonic-gate 		{
278*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
279*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
280*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
281*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
282*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
283*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
284*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
285*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
286*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
287*7c478bd9Sstevel@tonic-gate 		}
288*7c478bd9Sstevel@tonic-gate 	},
289*7c478bd9Sstevel@tonic-gate 	{ SBD_CMD_TEST,
290*7c478bd9Sstevel@tonic-gate 		{
291*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* empty */
292*7c478bd9Sstevel@tonic-gate 			{ 0, 0 },	/* occupied */
293*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* connected */
294*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unconfigured */
295*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* partial */
296*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* configured */
297*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* release */
298*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* unreferenced */
299*7c478bd9Sstevel@tonic-gate 			{ 1, EIO },	/* fatal */
300*7c478bd9Sstevel@tonic-gate 		}
301*7c478bd9Sstevel@tonic-gate 	},
302*7c478bd9Sstevel@tonic-gate };
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate /*
305*7c478bd9Sstevel@tonic-gate  * Global R/W lock to synchronize access across
306*7c478bd9Sstevel@tonic-gate  * multiple boards.  Users wanting multi-board access
307*7c478bd9Sstevel@tonic-gate  * must grab WRITE lock, others must grab READ lock.
308*7c478bd9Sstevel@tonic-gate  */
309*7c478bd9Sstevel@tonic-gate krwlock_t	sbd_grwlock;
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate /*
312*7c478bd9Sstevel@tonic-gate  * Global to determine if an event needs to be sent
313*7c478bd9Sstevel@tonic-gate  */
314*7c478bd9Sstevel@tonic-gate char send_event = 0;
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate /*
317*7c478bd9Sstevel@tonic-gate  * Required/Expected functions.
318*7c478bd9Sstevel@tonic-gate  */
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate static sbd_handle_t	*sbd_get_handle(dev_t dev, sbd_softstate_t *softsp,
321*7c478bd9Sstevel@tonic-gate 				intptr_t arg, sbd_init_arg_t *iap);
322*7c478bd9Sstevel@tonic-gate static void		sbd_release_handle(sbd_handle_t *hp);
323*7c478bd9Sstevel@tonic-gate static int		sbd_pre_op(sbd_handle_t *hp);
324*7c478bd9Sstevel@tonic-gate static void		sbd_post_op(sbd_handle_t *hp);
325*7c478bd9Sstevel@tonic-gate static int		sbd_probe_board(sbd_handle_t *hp);
326*7c478bd9Sstevel@tonic-gate static int		sbd_deprobe_board(sbd_handle_t *hp);
327*7c478bd9Sstevel@tonic-gate static void		sbd_connect(sbd_handle_t *hp);
328*7c478bd9Sstevel@tonic-gate static void		sbd_assign_board(sbd_handle_t *hp);
329*7c478bd9Sstevel@tonic-gate static void		sbd_unassign_board(sbd_handle_t *hp);
330*7c478bd9Sstevel@tonic-gate static void		sbd_poweron_board(sbd_handle_t *hp);
331*7c478bd9Sstevel@tonic-gate static void		sbd_poweroff_board(sbd_handle_t *hp);
332*7c478bd9Sstevel@tonic-gate static void		sbd_test_board(sbd_handle_t *hp);
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate static int		sbd_disconnect(sbd_handle_t *hp);
335*7c478bd9Sstevel@tonic-gate static sbd_devlist_t	*sbd_get_attach_devlist(sbd_handle_t *hp,
336*7c478bd9Sstevel@tonic-gate 					int32_t *devnump, int32_t pass);
337*7c478bd9Sstevel@tonic-gate static int		sbd_pre_attach_devlist(sbd_handle_t *hp,
338*7c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
339*7c478bd9Sstevel@tonic-gate static int		sbd_post_attach_devlist(sbd_handle_t *hp,
340*7c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
341*7c478bd9Sstevel@tonic-gate static sbd_devlist_t	*sbd_get_release_devlist(sbd_handle_t *hp,
342*7c478bd9Sstevel@tonic-gate 					int32_t *devnump, int32_t pass);
343*7c478bd9Sstevel@tonic-gate static int		sbd_pre_release_devlist(sbd_handle_t *hp,
344*7c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
345*7c478bd9Sstevel@tonic-gate static int		sbd_post_release_devlist(sbd_handle_t *hp,
346*7c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
347*7c478bd9Sstevel@tonic-gate static void		sbd_release_done(sbd_handle_t *hp,
348*7c478bd9Sstevel@tonic-gate 					sbd_comp_type_t nodetype,
349*7c478bd9Sstevel@tonic-gate 					dev_info_t *dip);
350*7c478bd9Sstevel@tonic-gate static sbd_devlist_t	*sbd_get_detach_devlist(sbd_handle_t *hp,
351*7c478bd9Sstevel@tonic-gate 					int32_t *devnump, int32_t pass);
352*7c478bd9Sstevel@tonic-gate static int		sbd_pre_detach_devlist(sbd_handle_t *hp,
353*7c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
354*7c478bd9Sstevel@tonic-gate static int		sbd_post_detach_devlist(sbd_handle_t *hp,
355*7c478bd9Sstevel@tonic-gate 					sbd_devlist_t *devlist, int32_t devnum);
356*7c478bd9Sstevel@tonic-gate static void		sbd_status(sbd_handle_t *hp);
357*7c478bd9Sstevel@tonic-gate static void		sbd_get_ncm(sbd_handle_t *hp);
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate /*
361*7c478bd9Sstevel@tonic-gate  * Support functions.
362*7c478bd9Sstevel@tonic-gate  */
363*7c478bd9Sstevel@tonic-gate static sbd_devset_t	sbd_dev2devset(sbd_comp_id_t *cid);
364*7c478bd9Sstevel@tonic-gate static int		sbd_copyin_ioarg(sbd_handle_t *hp, int mode, int cmd,
365*7c478bd9Sstevel@tonic-gate 				sbd_cmd_t *cmdp, sbd_ioctl_arg_t *iap);
366*7c478bd9Sstevel@tonic-gate static int		sbd_copyout_errs(int mode, sbd_ioctl_arg_t *iap,
367*7c478bd9Sstevel@tonic-gate 					void *arg);
368*7c478bd9Sstevel@tonic-gate static int		sbd_copyout_ioarg(int mode, int cmd, sbd_cmd_t *scp,
369*7c478bd9Sstevel@tonic-gate 				sbd_ioctl_arg_t *iap);
370*7c478bd9Sstevel@tonic-gate static int		sbd_check_transition(sbd_board_t *sbp,
371*7c478bd9Sstevel@tonic-gate 					sbd_devset_t *devsetp,
372*7c478bd9Sstevel@tonic-gate 					struct sbd_state_trans *transp);
373*7c478bd9Sstevel@tonic-gate static sbd_devlist_t	*sbd_get_devlist(sbd_handle_t *hp,
374*7c478bd9Sstevel@tonic-gate 					sbd_board_t *sbp,
375*7c478bd9Sstevel@tonic-gate 					sbd_comp_type_t nodetype,
376*7c478bd9Sstevel@tonic-gate 					int max_units, uint_t uset,
377*7c478bd9Sstevel@tonic-gate 					int *count, int present_only);
378*7c478bd9Sstevel@tonic-gate static int		sbd_mem_status(sbd_handle_t *hp, sbd_devset_t devset,
379*7c478bd9Sstevel@tonic-gate 					sbd_dev_stat_t *dsp);
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate static int		sbd_init_devlists(sbd_board_t *sbp);
382*7c478bd9Sstevel@tonic-gate static int		sbd_name_to_idx(char *name);
383*7c478bd9Sstevel@tonic-gate static int		sbd_otype_to_idx(char *otpye);
384*7c478bd9Sstevel@tonic-gate static int		sbd_setup_devlists(dev_info_t *dip, void *arg);
385*7c478bd9Sstevel@tonic-gate static void		sbd_init_mem_devlists(sbd_board_t *sbp);
386*7c478bd9Sstevel@tonic-gate static void		sbd_init_cpu_unit(sbd_board_t *sbp, int unit);
387*7c478bd9Sstevel@tonic-gate static void		sbd_board_discovery(sbd_board_t *sbp);
388*7c478bd9Sstevel@tonic-gate static void		sbd_board_init(sbd_board_t *sbp,
389*7c478bd9Sstevel@tonic-gate 				sbd_softstate_t *softsp,
390*7c478bd9Sstevel@tonic-gate 				int bd, dev_info_t *dip, int wnode);
391*7c478bd9Sstevel@tonic-gate static void		sbd_board_destroy(sbd_board_t *sbp);
392*7c478bd9Sstevel@tonic-gate static int		sbd_check_unit_attached(sbd_board_t *sbp,
393*7c478bd9Sstevel@tonic-gate 				dev_info_t *dip, int unit,
394*7c478bd9Sstevel@tonic-gate 				sbd_comp_type_t nodetype, sbderror_t *ep);
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate static sbd_state_t 	rstate_cvt(sbd_istate_t state);
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate /*
399*7c478bd9Sstevel@tonic-gate  * Autoconfiguration data structures
400*7c478bd9Sstevel@tonic-gate  */
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops;
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
405*7c478bd9Sstevel@tonic-gate 	&mod_miscops,
406*7c478bd9Sstevel@tonic-gate 	"System Board DR v%I%"
407*7c478bd9Sstevel@tonic-gate };
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
410*7c478bd9Sstevel@tonic-gate 	MODREV_1,
411*7c478bd9Sstevel@tonic-gate 	(void *)&modlmisc,
412*7c478bd9Sstevel@tonic-gate 	NULL
413*7c478bd9Sstevel@tonic-gate };
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate static int sbd_instances = 0;
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate /*
418*7c478bd9Sstevel@tonic-gate  * dr Global data elements
419*7c478bd9Sstevel@tonic-gate  */
420*7c478bd9Sstevel@tonic-gate sbd_global sbd_g;
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate /*
423*7c478bd9Sstevel@tonic-gate  * We want to be able to unload the module when we wish to do so, but we don't
424*7c478bd9Sstevel@tonic-gate  * want anything else to unload it.  Unloading cannot occur until
425*7c478bd9Sstevel@tonic-gate  * sbd_teardown_instance is called by an explicit IOCTL into the parent node.
426*7c478bd9Sstevel@tonic-gate  * This support is for debugging purposes and should it be expected to work
427*7c478bd9Sstevel@tonic-gate  * on the field, it should be enhanced:
428*7c478bd9Sstevel@tonic-gate  * Currently, there is still a window where sbd_teardow_instance gets called,
429*7c478bd9Sstevel@tonic-gate  * sbd_prevent_unloading now = 0, the driver doesn't get unloaded, and
430*7c478bd9Sstevel@tonic-gate  * sbd_setup_instance gets called.  This may cause a panic.
431*7c478bd9Sstevel@tonic-gate  */
432*7c478bd9Sstevel@tonic-gate int sbd_prevent_unloading = 1;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate /*
435*7c478bd9Sstevel@tonic-gate  * Driver entry points.
436*7c478bd9Sstevel@tonic-gate  */
437*7c478bd9Sstevel@tonic-gate int
438*7c478bd9Sstevel@tonic-gate _init(void)
439*7c478bd9Sstevel@tonic-gate {
440*7c478bd9Sstevel@tonic-gate 	int	err;
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	/*
443*7c478bd9Sstevel@tonic-gate 	 * If you need to support multiple nodes (instances), then
444*7c478bd9Sstevel@tonic-gate 	 * whatever the maximum number of supported nodes is would
445*7c478bd9Sstevel@tonic-gate 	 * need to passed as the third parameter to ddi_soft_state_init().
446*7c478bd9Sstevel@tonic-gate 	 * Alternative would be to dynamically fini and re-init the
447*7c478bd9Sstevel@tonic-gate 	 * soft state structure each time a node is attached.
448*7c478bd9Sstevel@tonic-gate 	 */
449*7c478bd9Sstevel@tonic-gate 	err = ddi_soft_state_init((void **)&sbd_g.softsp,
450*7c478bd9Sstevel@tonic-gate 		sizeof (sbd_softstate_t), SBD_MAX_INSTANCES);
451*7c478bd9Sstevel@tonic-gate 	if (err)
452*7c478bd9Sstevel@tonic-gate 		return (err);
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	if ((err = mod_install(&modlinkage)) != 0) {
455*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini((void **)&sbd_g.softsp);
456*7c478bd9Sstevel@tonic-gate 		return (err);
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	/* Get the array of names from platform helper routine */
460*7c478bd9Sstevel@tonic-gate 	sbd_devattr = sbdp_get_devattr();
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	return (err);
463*7c478bd9Sstevel@tonic-gate }
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate int
466*7c478bd9Sstevel@tonic-gate _fini(void)
467*7c478bd9Sstevel@tonic-gate {
468*7c478bd9Sstevel@tonic-gate 	int	err;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	if (sbd_prevent_unloading)
471*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	ASSERT(sbd_instances == 0);
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	if ((err = mod_remove(&modlinkage)) != 0)
476*7c478bd9Sstevel@tonic-gate 		return (err);
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini((void **)&sbd_g.softsp);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	return (0);
481*7c478bd9Sstevel@tonic-gate }
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate int
484*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
485*7c478bd9Sstevel@tonic-gate {
486*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
487*7c478bd9Sstevel@tonic-gate }
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate int
490*7c478bd9Sstevel@tonic-gate sbd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, char *event)
491*7c478bd9Sstevel@tonic-gate {
492*7c478bd9Sstevel@tonic-gate 	int		rv = 0, instance;
493*7c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp;
494*7c478bd9Sstevel@tonic-gate 	sbd_softstate_t	*softsp;
495*7c478bd9Sstevel@tonic-gate 	sbd_init_arg_t	init_arg;
496*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_ioctl";
497*7c478bd9Sstevel@tonic-gate 	int		dr_avail;
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	PR_BYP("sbd_ioctl cmd=%x, arg=%x\n", cmd, arg);
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	/* Note: this must also be changed in tandem with sbd_ioctl.h */
502*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
503*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_ASSIGN:
504*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_UNASSIGN:
505*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_POWERON:
506*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_POWEROFF:
507*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_TEST:
508*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONNECT:
509*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONFIGURE:
510*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_UNCONFIGURE:
511*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_DISCONNECT:
512*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_STATUS:
513*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_GETNCM:
514*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_PASSTHRU:
515*7c478bd9Sstevel@tonic-gate 			break;
516*7c478bd9Sstevel@tonic-gate 		default:
517*7c478bd9Sstevel@tonic-gate 			return (ENOTTY);
518*7c478bd9Sstevel@tonic-gate 	}
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	instance = SBD_GET_MINOR2INST(getminor(dev));
521*7c478bd9Sstevel@tonic-gate 	if ((softsp = (sbd_softstate_t *)GET_SOFTC(instance)) == NULL) {
522*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
523*7c478bd9Sstevel@tonic-gate 			"sbd:%s:%d: module not yet attached",
524*7c478bd9Sstevel@tonic-gate 			f, instance);
525*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
526*7c478bd9Sstevel@tonic-gate 	}
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	init_arg.dev = dev;
529*7c478bd9Sstevel@tonic-gate 	init_arg.cmd = cmd;
530*7c478bd9Sstevel@tonic-gate 	init_arg.mode = mode;
531*7c478bd9Sstevel@tonic-gate 	init_arg.ioargp = (sbd_ioctl_arg_t *)arg;
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	hp = sbd_get_handle(dev, softsp, arg, &init_arg);
534*7c478bd9Sstevel@tonic-gate 	/* Check to see if we support dr */
535*7c478bd9Sstevel@tonic-gate 	dr_avail = sbdp_dr_avail();
536*7c478bd9Sstevel@tonic-gate 	if (dr_avail != 1) {
537*7c478bd9Sstevel@tonic-gate 		switch (hp->h_cmd) {
538*7c478bd9Sstevel@tonic-gate 			case SBD_CMD_STATUS:
539*7c478bd9Sstevel@tonic-gate 			case SBD_CMD_GETNCM:
540*7c478bd9Sstevel@tonic-gate 			case SBD_CMD_PASSTHRU:
541*7c478bd9Sstevel@tonic-gate 				break;
542*7c478bd9Sstevel@tonic-gate 			default:
543*7c478bd9Sstevel@tonic-gate 				sbd_release_handle(hp);
544*7c478bd9Sstevel@tonic-gate 				return (ENOTSUP);
545*7c478bd9Sstevel@tonic-gate 		}
546*7c478bd9Sstevel@tonic-gate 	}
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	switch (hp->h_cmd) {
549*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_STATUS:
550*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
551*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_PASSTHRU:
552*7c478bd9Sstevel@tonic-gate 		/* no locks needed for these commands */
553*7c478bd9Sstevel@tonic-gate 		break;
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	default:
556*7c478bd9Sstevel@tonic-gate 		rw_enter(&sbd_grwlock, RW_WRITER);
557*7c478bd9Sstevel@tonic-gate 		mutex_enter(&SBDH2BD(hp->h_sbd)->sb_mutex);
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 		/*
560*7c478bd9Sstevel@tonic-gate 		 * If we're dealing with memory at all, then we have
561*7c478bd9Sstevel@tonic-gate 		 * to keep the "exclusive" global lock held.  This is
562*7c478bd9Sstevel@tonic-gate 		 * necessary since we will probably need to look at
563*7c478bd9Sstevel@tonic-gate 		 * multiple board structs.  Otherwise, we only have
564*7c478bd9Sstevel@tonic-gate 		 * to deal with the board in question and so can drop
565*7c478bd9Sstevel@tonic-gate 		 * the global lock to "shared".
566*7c478bd9Sstevel@tonic-gate 		 */
567*7c478bd9Sstevel@tonic-gate 		/*
568*7c478bd9Sstevel@tonic-gate 		 * XXX This is incorrect. The sh_devset has not
569*7c478bd9Sstevel@tonic-gate 		 * been set at this point - it is 0.
570*7c478bd9Sstevel@tonic-gate 		 */
571*7c478bd9Sstevel@tonic-gate 		rv = DEVSET_IN_SET(HD2MACHHD(hp)->sh_devset,
572*7c478bd9Sstevel@tonic-gate 		    SBD_COMP_MEM, DEVSET_ANYUNIT);
573*7c478bd9Sstevel@tonic-gate 		if (rv == 0)
574*7c478bd9Sstevel@tonic-gate 			rw_downgrade(&sbd_grwlock);
575*7c478bd9Sstevel@tonic-gate 		break;
576*7c478bd9Sstevel@tonic-gate 	}
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	/*
579*7c478bd9Sstevel@tonic-gate 	 * Before any operations happen, reset the event flag
580*7c478bd9Sstevel@tonic-gate 	 */
581*7c478bd9Sstevel@tonic-gate 	send_event = 0;
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	if (sbd_pre_op(hp) == 0) {
584*7c478bd9Sstevel@tonic-gate 		sbd_exec_op(hp);
585*7c478bd9Sstevel@tonic-gate 		sbd_post_op(hp);
586*7c478bd9Sstevel@tonic-gate 	}
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	rv = SBD_GET_ERRNO(SBD_HD2ERR(hp));
589*7c478bd9Sstevel@tonic-gate 	*event = send_event;
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	/* undo locking, if any, done before sbd_pre_op */
592*7c478bd9Sstevel@tonic-gate 	switch (hp->h_cmd) {
593*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_STATUS:
594*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
595*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_PASSTHRU:
596*7c478bd9Sstevel@tonic-gate 		break;
597*7c478bd9Sstevel@tonic-gate 	default:
598*7c478bd9Sstevel@tonic-gate 		mutex_exit(&SBDH2BD(hp->h_sbd)->sb_mutex);
599*7c478bd9Sstevel@tonic-gate 		rw_exit(&sbd_grwlock);
600*7c478bd9Sstevel@tonic-gate 	}
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	sbd_release_handle(hp);
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	return (rv);
605*7c478bd9Sstevel@tonic-gate }
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate int
608*7c478bd9Sstevel@tonic-gate sbd_setup_instance(int instance, dev_info_t *root, int max_boards, int wnode,
609*7c478bd9Sstevel@tonic-gate 		caddr_t sbdp_arg)
610*7c478bd9Sstevel@tonic-gate {
611*7c478bd9Sstevel@tonic-gate 	int 		b;
612*7c478bd9Sstevel@tonic-gate 	sbd_softstate_t	*softsp;
613*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbd_boardlist;
614*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_setup_instance";
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 	sbd_instances++;
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 	if (sbdp_setup_instance(sbdp_arg) != DDI_SUCCESS) {
619*7c478bd9Sstevel@tonic-gate 		sbd_instances--;
620*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
621*7c478bd9Sstevel@tonic-gate 	}
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 	if (ALLOC_SOFTC(instance) != DDI_SUCCESS) {
624*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
625*7c478bd9Sstevel@tonic-gate 			"sbd:%s:%d: failed to alloc soft-state",
626*7c478bd9Sstevel@tonic-gate 			f, instance);
627*7c478bd9Sstevel@tonic-gate 		sbdp_teardown_instance(sbdp_arg);
628*7c478bd9Sstevel@tonic-gate 		sbd_instances--;
629*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
630*7c478bd9Sstevel@tonic-gate 	}
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	softsp = (sbd_softstate_t *)GET_SOFTC(instance);
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	if (softsp == NULL) {
635*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
636*7c478bd9Sstevel@tonic-gate 			"sbd:%s:%d: failed to get soft-state instance",
637*7c478bd9Sstevel@tonic-gate 			f, instance);
638*7c478bd9Sstevel@tonic-gate 		goto exit;
639*7c478bd9Sstevel@tonic-gate 	}
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	sbd_boardlist = GETSTRUCT(sbd_board_t, max_boards);
642*7c478bd9Sstevel@tonic-gate 	if (sbd_boardlist == NULL) {
643*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
644*7c478bd9Sstevel@tonic-gate 			"sbd:%s: failed to alloc board list %d",
645*7c478bd9Sstevel@tonic-gate 			f, instance);
646*7c478bd9Sstevel@tonic-gate 		goto exit;
647*7c478bd9Sstevel@tonic-gate 	}
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 	softsp->sbd_boardlist  = (void *)sbd_boardlist;
651*7c478bd9Sstevel@tonic-gate 	softsp->max_boards  = max_boards;
652*7c478bd9Sstevel@tonic-gate 	softsp->wnode  = wnode;
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 	for (b = 0; b < max_boards; b++) {
656*7c478bd9Sstevel@tonic-gate 		sbd_board_init(sbd_boardlist++, softsp, b, root, wnode);
657*7c478bd9Sstevel@tonic-gate 	}
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
661*7c478bd9Sstevel@tonic-gate exit:
662*7c478bd9Sstevel@tonic-gate 	(void) sbdp_teardown_instance(sbdp_arg);
663*7c478bd9Sstevel@tonic-gate 	FREE_SOFTC(instance);
664*7c478bd9Sstevel@tonic-gate 	sbd_instances--;
665*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
666*7c478bd9Sstevel@tonic-gate }
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate int
669*7c478bd9Sstevel@tonic-gate sbd_teardown_instance(int instance, caddr_t sbdp_arg)
670*7c478bd9Sstevel@tonic-gate {
671*7c478bd9Sstevel@tonic-gate 	sbd_softstate_t	*softsp;
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 	if (sbdp_teardown_instance(sbdp_arg) != DDI_SUCCESS)
674*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 	softsp = (sbd_softstate_t *)GET_SOFTC(instance);
677*7c478bd9Sstevel@tonic-gate 	if (softsp == NULL) {
678*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
679*7c478bd9Sstevel@tonic-gate 	}
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	(void) sbd_dealloc_instance((sbd_board_t *)softsp->sbd_boardlist,
682*7c478bd9Sstevel@tonic-gate 		softsp->max_boards);
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 	FREE_SOFTC(instance);
685*7c478bd9Sstevel@tonic-gate 	sbd_instances--;
686*7c478bd9Sstevel@tonic-gate 	sbd_prevent_unloading = 0;
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
689*7c478bd9Sstevel@tonic-gate }
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate static void
692*7c478bd9Sstevel@tonic-gate sbd_exec_op(sbd_handle_t *hp)
693*7c478bd9Sstevel@tonic-gate {
694*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
695*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_exec_op";
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	switch (hp->h_cmd) {
698*7c478bd9Sstevel@tonic-gate 		int	dev_canceled;
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_CONNECT:
701*7c478bd9Sstevel@tonic-gate 		if (sbd_probe_board(hp))
702*7c478bd9Sstevel@tonic-gate 			break;
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 		sbd_connect(hp);
705*7c478bd9Sstevel@tonic-gate 		break;
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:
708*7c478bd9Sstevel@tonic-gate 		sbd_dev_configure(hp);
709*7c478bd9Sstevel@tonic-gate 		break;
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:
712*7c478bd9Sstevel@tonic-gate 		if (((dev_canceled = sbd_dev_release(hp)) == 0) &&
713*7c478bd9Sstevel@tonic-gate 		    (SBD_GET_ERRNO(SBD_HD2ERR(hp)) == 0 &&
714*7c478bd9Sstevel@tonic-gate 		    SBD_GET_ERR(SBD_HD2ERR(hp)) == 0))
715*7c478bd9Sstevel@tonic-gate 			dev_canceled = sbd_dev_unconfigure(hp);
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 		if (dev_canceled)
718*7c478bd9Sstevel@tonic-gate 			sbd_cancel(hp);
719*7c478bd9Sstevel@tonic-gate 		break;
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:
722*7c478bd9Sstevel@tonic-gate 		mutex_enter(&sbp->sb_slock);
723*7c478bd9Sstevel@tonic-gate 		if (sbd_disconnect(hp) == 0)
724*7c478bd9Sstevel@tonic-gate 			(void) sbd_deprobe_board(hp);
725*7c478bd9Sstevel@tonic-gate 		mutex_exit(&sbp->sb_slock);
726*7c478bd9Sstevel@tonic-gate 		break;
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_STATUS:
729*7c478bd9Sstevel@tonic-gate 		sbd_status(hp);
730*7c478bd9Sstevel@tonic-gate 		break;
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
733*7c478bd9Sstevel@tonic-gate 		sbd_get_ncm(hp);
734*7c478bd9Sstevel@tonic-gate 		break;
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_ASSIGN:
737*7c478bd9Sstevel@tonic-gate 		sbd_assign_board(hp);
738*7c478bd9Sstevel@tonic-gate 		break;
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_UNASSIGN:
741*7c478bd9Sstevel@tonic-gate 		sbd_unassign_board(hp);
742*7c478bd9Sstevel@tonic-gate 		break;
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_POWEROFF:
745*7c478bd9Sstevel@tonic-gate 		sbd_poweroff_board(hp);
746*7c478bd9Sstevel@tonic-gate 		break;
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_POWERON:
749*7c478bd9Sstevel@tonic-gate 		sbd_poweron_board(hp);
750*7c478bd9Sstevel@tonic-gate 		break;
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_TEST:
753*7c478bd9Sstevel@tonic-gate 		sbd_test_board(hp);
754*7c478bd9Sstevel@tonic-gate 		break;
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	case SBD_CMD_PASSTHRU:
757*7c478bd9Sstevel@tonic-gate 	{
758*7c478bd9Sstevel@tonic-gate 		int			rv;
759*7c478bd9Sstevel@tonic-gate 		sbdp_handle_t		*hdp;
760*7c478bd9Sstevel@tonic-gate 		sbderror_t		*ep = SBD_HD2ERR(hp);
761*7c478bd9Sstevel@tonic-gate 		sbdp_ioctl_arg_t	ia, *iap;
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 		iap = &ia;
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 		iap->h_dev = hp->h_dev;
766*7c478bd9Sstevel@tonic-gate 		iap->h_cmd = hp->h_cmd;
767*7c478bd9Sstevel@tonic-gate 		iap->h_iap = (intptr_t)hp->h_iap;
768*7c478bd9Sstevel@tonic-gate 		iap->h_mode = hp->h_mode;
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 		hdp = sbd_get_sbdp_handle(sbp, hp);
771*7c478bd9Sstevel@tonic-gate 		rv = sbdp_ioctl(hdp, iap);
772*7c478bd9Sstevel@tonic-gate 		if (rv != 0) {
773*7c478bd9Sstevel@tonic-gate 			SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
774*7c478bd9Sstevel@tonic-gate 			ep->e_errno = rv;
775*7c478bd9Sstevel@tonic-gate 		}
776*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
777*7c478bd9Sstevel@tonic-gate 		break;
778*7c478bd9Sstevel@tonic-gate 	}
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 	default:
781*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(SBD_HD2ERR(hp), ENOTTY);
782*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
783*7c478bd9Sstevel@tonic-gate 			"sbd:%s: unknown command (%d)",
784*7c478bd9Sstevel@tonic-gate 			f, hp->h_cmd);
785*7c478bd9Sstevel@tonic-gate 		break;
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 	}
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERR(SBD_HD2ERR(hp)))
790*7c478bd9Sstevel@tonic-gate 		PR_BYP("XXX e_code=%d", SBD_GET_ERR(SBD_HD2ERR(hp)));
791*7c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERRNO(SBD_HD2ERR(hp)))
792*7c478bd9Sstevel@tonic-gate 		PR_BYP("XXX errno=%d", SBD_GET_ERRNO(SBD_HD2ERR(hp)));
793*7c478bd9Sstevel@tonic-gate }
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate sbd_comp_type_t
796*7c478bd9Sstevel@tonic-gate sbd_get_devtype(sbd_handle_t *hp, dev_info_t *dip)
797*7c478bd9Sstevel@tonic-gate {
798*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = hp ? SBDH2BD(hp->h_sbd) : NULL;
799*7c478bd9Sstevel@tonic-gate 	sbd_istate_t	bstate;
800*7c478bd9Sstevel@tonic-gate 	dev_info_t	**devlist;
801*7c478bd9Sstevel@tonic-gate 	int		i;
802*7c478bd9Sstevel@tonic-gate 	char		device[OBP_MAXDRVNAME];
803*7c478bd9Sstevel@tonic-gate 	int		devicelen;
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	devicelen = sizeof (device);
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 	bstate = sbp ? SBD_BOARD_STATE(sbp) : SBD_STATE_EMPTY;
808*7c478bd9Sstevel@tonic-gate 	/*
809*7c478bd9Sstevel@tonic-gate 	 * if the board's connected or configured, search the
810*7c478bd9Sstevel@tonic-gate 	 * devlists.  Otherwise check the device tree
811*7c478bd9Sstevel@tonic-gate 	 */
812*7c478bd9Sstevel@tonic-gate 	switch (bstate) {
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONNECTED:
815*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONFIGURED:
816*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNREFERENCED:
817*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNCONFIGURED:
818*7c478bd9Sstevel@tonic-gate 		devlist = sbp->sb_devlist[NIX(SBD_COMP_MEM)];
819*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++)
820*7c478bd9Sstevel@tonic-gate 			if (devlist[i] == dip)
821*7c478bd9Sstevel@tonic-gate 				return (SBD_COMP_MEM);
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 		devlist = sbp->sb_devlist[NIX(SBD_COMP_CPU)];
824*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++)
825*7c478bd9Sstevel@tonic-gate 			if (devlist[i] == dip)
826*7c478bd9Sstevel@tonic-gate 				return (SBD_COMP_CPU);
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 		devlist = sbp->sb_devlist[NIX(SBD_COMP_IO)];
829*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++)
830*7c478bd9Sstevel@tonic-gate 			if (devlist[i] == dip)
831*7c478bd9Sstevel@tonic-gate 				return (SBD_COMP_IO);
832*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	default:
835*7c478bd9Sstevel@tonic-gate 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
836*7c478bd9Sstevel@tonic-gate 		    OBP_DEVICETYPE,  (caddr_t)device, &devicelen))
837*7c478bd9Sstevel@tonic-gate 			break;
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 		for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) {
840*7c478bd9Sstevel@tonic-gate 			if (strcmp(device, SBD_OTYPE(i)) != 0)
841*7c478bd9Sstevel@tonic-gate 				continue;
842*7c478bd9Sstevel@tonic-gate 			return (SBD_COMP(i));
843*7c478bd9Sstevel@tonic-gate 		}
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 		break;
846*7c478bd9Sstevel@tonic-gate 	}
847*7c478bd9Sstevel@tonic-gate 	return (SBD_COMP_UNKNOWN);
848*7c478bd9Sstevel@tonic-gate }
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate static void
851*7c478bd9Sstevel@tonic-gate sbd_dev_configure(sbd_handle_t *hp)
852*7c478bd9Sstevel@tonic-gate {
853*7c478bd9Sstevel@tonic-gate 	int		n, unit;
854*7c478bd9Sstevel@tonic-gate 	int32_t		pass, devnum;
855*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
856*7c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*devlist;
857*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
858*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
859*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 	pass = 1;
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
864*7c478bd9Sstevel@tonic-gate 	while ((devlist = sbd_get_attach_devlist(hp, &devnum, pass)) != NULL) {
865*7c478bd9Sstevel@tonic-gate 		int	err;
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate 		err = sbd_pre_attach_devlist(hp, devlist, devnum);
868*7c478bd9Sstevel@tonic-gate 		if (err < 0) {
869*7c478bd9Sstevel@tonic-gate 			break;
870*7c478bd9Sstevel@tonic-gate 		} else if (err > 0) {
871*7c478bd9Sstevel@tonic-gate 			pass++;
872*7c478bd9Sstevel@tonic-gate 			continue;
873*7c478bd9Sstevel@tonic-gate 		}
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 		for (n = 0; n < devnum; n++) {
876*7c478bd9Sstevel@tonic-gate 			sbderror_t	*ep;
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 			ep = &devlist[n].dv_error;
879*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, 0);
880*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(ep, 0);
881*7c478bd9Sstevel@tonic-gate 			dip = devlist[n].dv_dip;
882*7c478bd9Sstevel@tonic-gate 			nodetype = sbd_get_devtype(hp, dip);
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 			unit = sbdp_get_unit_num(hdp, dip);
885*7c478bd9Sstevel@tonic-gate 			if (unit < 0) {
886*7c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
887*7c478bd9Sstevel@tonic-gate 				break;
888*7c478bd9Sstevel@tonic-gate 			}
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 			switch (nodetype) {
891*7c478bd9Sstevel@tonic-gate 			case SBD_COMP_MEM:
892*7c478bd9Sstevel@tonic-gate 				sbd_attach_mem(hp, ep);
893*7c478bd9Sstevel@tonic-gate 				if (SBD_GET_ERR(ep) == ESBD_CPUONLINE) {
894*7c478bd9Sstevel@tonic-gate 					FREESTRUCT(devlist, sbd_devlist_t,
895*7c478bd9Sstevel@tonic-gate 						MAX_MEM_UNITS_PER_BOARD);
896*7c478bd9Sstevel@tonic-gate 					sbd_release_sbdp_handle(hdp);
897*7c478bd9Sstevel@tonic-gate 					return;
898*7c478bd9Sstevel@tonic-gate 				}
899*7c478bd9Sstevel@tonic-gate 				break;
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 			case SBD_COMP_CPU:
902*7c478bd9Sstevel@tonic-gate 				sbd_attach_cpu(hp, ep, dip, unit);
903*7c478bd9Sstevel@tonic-gate 				break;
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 			case SBD_COMP_IO:
906*7c478bd9Sstevel@tonic-gate 				sbd_attach_io(hp, ep, dip, unit);
907*7c478bd9Sstevel@tonic-gate 				break;
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 			default:
910*7c478bd9Sstevel@tonic-gate 				SBD_SET_ERRNO(ep, ENOTTY);
911*7c478bd9Sstevel@tonic-gate 				break;
912*7c478bd9Sstevel@tonic-gate 			}
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate 			if (sbd_set_err_in_hdl(hp, ep) == 0)
915*7c478bd9Sstevel@tonic-gate 				continue;
916*7c478bd9Sstevel@tonic-gate 		}
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate 		err = sbd_post_attach_devlist(hp, devlist, devnum);
919*7c478bd9Sstevel@tonic-gate 		if (err < 0)
920*7c478bd9Sstevel@tonic-gate 			break;
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 		pass++;
923*7c478bd9Sstevel@tonic-gate 	}
924*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
925*7c478bd9Sstevel@tonic-gate }
926*7c478bd9Sstevel@tonic-gate 
927*7c478bd9Sstevel@tonic-gate static int
928*7c478bd9Sstevel@tonic-gate sbd_dev_release(sbd_handle_t *hp)
929*7c478bd9Sstevel@tonic-gate {
930*7c478bd9Sstevel@tonic-gate 	int		n, unit;
931*7c478bd9Sstevel@tonic-gate 	int32_t		pass, devnum;
932*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
933*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
934*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
935*7c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*devlist;
936*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
937*7c478bd9Sstevel@tonic-gate 	int		err = 0;
938*7c478bd9Sstevel@tonic-gate 	int		dev_canceled;
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 	pass = 1;
941*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 	sbp->sb_busy = 1;
944*7c478bd9Sstevel@tonic-gate 	while ((devlist =
945*7c478bd9Sstevel@tonic-gate 		sbd_get_release_devlist(hp, &devnum, pass)) != NULL) {
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 		err = sbd_pre_release_devlist(hp, devlist, devnum);
948*7c478bd9Sstevel@tonic-gate 		if (err < 0) {
949*7c478bd9Sstevel@tonic-gate 			dev_canceled = 1;
950*7c478bd9Sstevel@tonic-gate 			break;
951*7c478bd9Sstevel@tonic-gate 		} else if (err > 0) {
952*7c478bd9Sstevel@tonic-gate 			pass++;
953*7c478bd9Sstevel@tonic-gate 			continue;
954*7c478bd9Sstevel@tonic-gate 		}
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 		dev_canceled = 0;
957*7c478bd9Sstevel@tonic-gate 		for (n = 0; n < devnum; n++) {
958*7c478bd9Sstevel@tonic-gate 			dip = devlist[n].dv_dip;
959*7c478bd9Sstevel@tonic-gate 			nodetype = sbd_get_devtype(hp, dip);
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 			unit = sbdp_get_unit_num(hdp, dip);
962*7c478bd9Sstevel@tonic-gate 			if (unit < 0) {
963*7c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
964*7c478bd9Sstevel@tonic-gate 				break;
965*7c478bd9Sstevel@tonic-gate 			}
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 			if ((nodetype == SBD_COMP_MEM) &&
968*7c478bd9Sstevel@tonic-gate 			    sbd_release_mem(hp, dip, unit)) {
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 				dev_canceled++;
971*7c478bd9Sstevel@tonic-gate 			}
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 			sbd_release_done(hp, nodetype, dip);
974*7c478bd9Sstevel@tonic-gate 		}
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate 		err = sbd_post_release_devlist(hp, devlist, devnum);
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate 		if (err < 0)
979*7c478bd9Sstevel@tonic-gate 			break;
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 		if (dev_canceled)
982*7c478bd9Sstevel@tonic-gate 			break;
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 		pass++;
985*7c478bd9Sstevel@tonic-gate 	}
986*7c478bd9Sstevel@tonic-gate 	sbp->sb_busy = 0;
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 	if (dev_canceled)
991*7c478bd9Sstevel@tonic-gate 		return (dev_canceled);
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate 	return (err);
994*7c478bd9Sstevel@tonic-gate }
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate static int
997*7c478bd9Sstevel@tonic-gate sbd_dev_unconfigure(sbd_handle_t *hp)
998*7c478bd9Sstevel@tonic-gate {
999*7c478bd9Sstevel@tonic-gate 	int		n, unit;
1000*7c478bd9Sstevel@tonic-gate 	int32_t		pass, devnum;
1001*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
1002*7c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*devlist;
1003*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
1004*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
1005*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
1006*7c478bd9Sstevel@tonic-gate 	int		dev_canceled = 0;
1007*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_dev_unconfigure";
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate 	pass = 1;
1012*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate 	while ((devlist = sbd_get_detach_devlist(hp, &devnum, pass)) != NULL) {
1015*7c478bd9Sstevel@tonic-gate 		int	err, detach_err = 0;
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate 		err = sbd_pre_detach_devlist(hp, devlist, devnum);
1018*7c478bd9Sstevel@tonic-gate 		if (err) {
1019*7c478bd9Sstevel@tonic-gate 			/*
1020*7c478bd9Sstevel@tonic-gate 			 * Only cancel the operation for memory in
1021*7c478bd9Sstevel@tonic-gate 			 * case of failure.
1022*7c478bd9Sstevel@tonic-gate 			 */
1023*7c478bd9Sstevel@tonic-gate 			nodetype = sbd_get_devtype(hp, devlist->dv_dip);
1024*7c478bd9Sstevel@tonic-gate 			if (nodetype == SBD_COMP_MEM)
1025*7c478bd9Sstevel@tonic-gate 				dev_canceled = 1;
1026*7c478bd9Sstevel@tonic-gate 			(void) sbd_post_detach_devlist(hp, devlist, devnum);
1027*7c478bd9Sstevel@tonic-gate 			break;
1028*7c478bd9Sstevel@tonic-gate 		}
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 		for (n = 0; n < devnum; n++) {
1031*7c478bd9Sstevel@tonic-gate 			sbderror_t	*ep;
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 			ep = &devlist[n].dv_error;
1034*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, 0);
1035*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(ep, 0);
1036*7c478bd9Sstevel@tonic-gate 			dip = devlist[n].dv_dip;
1037*7c478bd9Sstevel@tonic-gate 			nodetype = sbd_get_devtype(hp, dip);
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate 			unit = sbdp_get_unit_num(hdp, dip);
1040*7c478bd9Sstevel@tonic-gate 			if (unit < 0) {
1041*7c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
1042*7c478bd9Sstevel@tonic-gate 				break;
1043*7c478bd9Sstevel@tonic-gate 			}
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate 			switch (nodetype) {
1046*7c478bd9Sstevel@tonic-gate 			case SBD_COMP_MEM:
1047*7c478bd9Sstevel@tonic-gate 				dev_canceled = sbd_detach_mem(hp, ep, unit);
1048*7c478bd9Sstevel@tonic-gate 				break;
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 			case SBD_COMP_CPU:
1051*7c478bd9Sstevel@tonic-gate 				sbd_detach_cpu(hp, ep, dip, unit);
1052*7c478bd9Sstevel@tonic-gate 				break;
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate 			case SBD_COMP_IO:
1055*7c478bd9Sstevel@tonic-gate 				sbd_detach_io(hp, ep, dip, unit);
1056*7c478bd9Sstevel@tonic-gate 				break;
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate 			default:
1059*7c478bd9Sstevel@tonic-gate 				SBD_SET_ERRNO(ep, ENOTTY);
1060*7c478bd9Sstevel@tonic-gate 				break;
1061*7c478bd9Sstevel@tonic-gate 			}
1062*7c478bd9Sstevel@tonic-gate 
1063*7c478bd9Sstevel@tonic-gate 			if (sbd_set_err_in_hdl(hp, ep) == 0) {
1064*7c478bd9Sstevel@tonic-gate 				detach_err = -1;
1065*7c478bd9Sstevel@tonic-gate 				break;
1066*7c478bd9Sstevel@tonic-gate 			}
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 		}
1069*7c478bd9Sstevel@tonic-gate 		err = sbd_post_detach_devlist(hp, devlist, devnum);
1070*7c478bd9Sstevel@tonic-gate 		if ((err < 0) || (detach_err < 0))
1071*7c478bd9Sstevel@tonic-gate 			break;
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 		pass++;
1074*7c478bd9Sstevel@tonic-gate 	}
1075*7c478bd9Sstevel@tonic-gate 
1076*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
1077*7c478bd9Sstevel@tonic-gate 	return (dev_canceled);
1078*7c478bd9Sstevel@tonic-gate }
1079*7c478bd9Sstevel@tonic-gate 
1080*7c478bd9Sstevel@tonic-gate int
1081*7c478bd9Sstevel@tonic-gate sbd_errno2ecode(int error)
1082*7c478bd9Sstevel@tonic-gate {
1083*7c478bd9Sstevel@tonic-gate 	int	rv;
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 	switch (error) {
1086*7c478bd9Sstevel@tonic-gate 	case EBUSY:
1087*7c478bd9Sstevel@tonic-gate 		rv = ESBD_BUSY;
1088*7c478bd9Sstevel@tonic-gate 		break;
1089*7c478bd9Sstevel@tonic-gate 	case EINVAL:
1090*7c478bd9Sstevel@tonic-gate 		rv = ESBD_INVAL;
1091*7c478bd9Sstevel@tonic-gate 		break;
1092*7c478bd9Sstevel@tonic-gate 	case EALREADY:
1093*7c478bd9Sstevel@tonic-gate 		rv = ESBD_ALREADY;
1094*7c478bd9Sstevel@tonic-gate 		break;
1095*7c478bd9Sstevel@tonic-gate 	case ENODEV:
1096*7c478bd9Sstevel@tonic-gate 		rv = ESBD_NODEV;
1097*7c478bd9Sstevel@tonic-gate 		break;
1098*7c478bd9Sstevel@tonic-gate 	case ENOMEM:
1099*7c478bd9Sstevel@tonic-gate 		rv = ESBD_NOMEM;
1100*7c478bd9Sstevel@tonic-gate 		break;
1101*7c478bd9Sstevel@tonic-gate 	default:
1102*7c478bd9Sstevel@tonic-gate 		rv = ESBD_INVAL;
1103*7c478bd9Sstevel@tonic-gate 	}
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 	return (rv);
1106*7c478bd9Sstevel@tonic-gate }
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate static void
1109*7c478bd9Sstevel@tonic-gate sbd_attach_cpu(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit)
1110*7c478bd9Sstevel@tonic-gate {
1111*7c478bd9Sstevel@tonic-gate 	int rv = 0;
1112*7c478bd9Sstevel@tonic-gate 	processorid_t	cpuid;
1113*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
1114*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
1115*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_attach_cpu";
1116*7c478bd9Sstevel@tonic-gate 	char		*pathname;
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate 	ASSERT(dip);
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 	/*
1123*7c478bd9Sstevel@tonic-gate 	 * With the introduction of CMP devices, the CPU nodes
1124*7c478bd9Sstevel@tonic-gate 	 * are no longer directly under the top node. Since
1125*7c478bd9Sstevel@tonic-gate 	 * there is no plan to support CPU attach in the near
1126*7c478bd9Sstevel@tonic-gate 	 * future, a branch configure operation is not required.
1127*7c478bd9Sstevel@tonic-gate 	 */
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
1130*7c478bd9Sstevel@tonic-gate 	cpuid = sbdp_get_cpuid(hdp, dip);
1131*7c478bd9Sstevel@tonic-gate 	if (cpuid < 0) {
1132*7c478bd9Sstevel@tonic-gate 		rv = -1;
1133*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
1134*7c478bd9Sstevel@tonic-gate 	} else if ((rv = cpu_configure(cpuid)) != 0) {
1135*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1136*7c478bd9Sstevel@tonic-gate 			"sbd:%s: cpu_configure for cpuid %d failed",
1137*7c478bd9Sstevel@tonic-gate 			f, cpuid);
1138*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, sbd_errno2ecode(rv));
1139*7c478bd9Sstevel@tonic-gate 	}
1140*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate 	if (rv == 0) {
1143*7c478bd9Sstevel@tonic-gate 		ASSERT(sbp->sb_cpupath[unit] != NULL);
1144*7c478bd9Sstevel@tonic-gate 		pathname = sbp->sb_cpupath[unit];
1145*7c478bd9Sstevel@tonic-gate 		(void) ddi_pathname(dip, pathname);
1146*7c478bd9Sstevel@tonic-gate 	}
1147*7c478bd9Sstevel@tonic-gate }
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate /*
1150*7c478bd9Sstevel@tonic-gate  *	translate errno
1151*7c478bd9Sstevel@tonic-gate  */
1152*7c478bd9Sstevel@tonic-gate void
1153*7c478bd9Sstevel@tonic-gate sbd_errno_decode(int err, sbderror_t *ep, dev_info_t *dip)
1154*7c478bd9Sstevel@tonic-gate {
1155*7c478bd9Sstevel@tonic-gate 	ASSERT(err != 0);
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	switch (err) {
1158*7c478bd9Sstevel@tonic-gate 	case ENOMEM:
1159*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_NOMEM);
1160*7c478bd9Sstevel@tonic-gate 		break;
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate 	case EBUSY:
1163*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_BUSY);
1164*7c478bd9Sstevel@tonic-gate 		break;
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate 	case EIO:
1167*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_IO);
1168*7c478bd9Sstevel@tonic-gate 		break;
1169*7c478bd9Sstevel@tonic-gate 
1170*7c478bd9Sstevel@tonic-gate 	case ENXIO:
1171*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_NODEV);
1172*7c478bd9Sstevel@tonic-gate 		break;
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	case EINVAL:
1175*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_INVAL);
1176*7c478bd9Sstevel@tonic-gate 		break;
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate 	case EFAULT:
1179*7c478bd9Sstevel@tonic-gate 	default:
1180*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_FAULT);
1181*7c478bd9Sstevel@tonic-gate 		break;
1182*7c478bd9Sstevel@tonic-gate 	}
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	(void) ddi_pathname(dip, SBD_GET_ERRSTR(ep));
1185*7c478bd9Sstevel@tonic-gate }
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate static void
1188*7c478bd9Sstevel@tonic-gate sbd_detach_cpu(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit)
1189*7c478bd9Sstevel@tonic-gate {
1190*7c478bd9Sstevel@tonic-gate 	processorid_t	cpuid;
1191*7c478bd9Sstevel@tonic-gate 	int		rv;
1192*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
1193*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
1194*7c478bd9Sstevel@tonic-gate 	sbd_error_t	*spe;
1195*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_detach_cpu";
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 	ASSERT(dip);
1200*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
1201*7c478bd9Sstevel@tonic-gate 	spe = hdp->h_err;
1202*7c478bd9Sstevel@tonic-gate 	cpuid = sbdp_get_cpuid(hdp, dip);
1203*7c478bd9Sstevel@tonic-gate 	if (cpuid < 0) {
1204*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(spe, ep);
1205*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
1206*7c478bd9Sstevel@tonic-gate 		return;
1207*7c478bd9Sstevel@tonic-gate 	}
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate 	if ((rv = cpu_unconfigure(cpuid)) != 0) {
1210*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, sbd_errno2ecode(rv));
1211*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(ep, sbp->sb_cpupath[unit]);
1212*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1213*7c478bd9Sstevel@tonic-gate 			"sbd:%s: cpu_unconfigure for cpu %d failed",
1214*7c478bd9Sstevel@tonic-gate 			f, cpuid);
1215*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
1216*7c478bd9Sstevel@tonic-gate 		return;
1217*7c478bd9Sstevel@tonic-gate 	}
1218*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate 	/*
1221*7c478bd9Sstevel@tonic-gate 	 * Since CPU nodes are no longer configured in CPU
1222*7c478bd9Sstevel@tonic-gate 	 * attach, the corresponding branch unconfigure
1223*7c478bd9Sstevel@tonic-gate 	 * operation that would be performed here is also
1224*7c478bd9Sstevel@tonic-gate 	 * no longer required.
1225*7c478bd9Sstevel@tonic-gate 	 */
1226*7c478bd9Sstevel@tonic-gate }
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate int
1230*7c478bd9Sstevel@tonic-gate sbd_detach_mem(sbd_handle_t *hp, sbderror_t *ep, int unit)
1231*7c478bd9Sstevel@tonic-gate {
1232*7c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
1233*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
1234*7c478bd9Sstevel@tonic-gate 	int		i, rv;
1235*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_detach_mem";
1236*7c478bd9Sstevel@tonic-gate 
1237*7c478bd9Sstevel@tonic-gate 	mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
1238*7c478bd9Sstevel@tonic-gate 
1239*7c478bd9Sstevel@tonic-gate 	if (sbd_detach_memory(hp, ep, mp, unit)) {
1240*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: detach fail", f);
1241*7c478bd9Sstevel@tonic-gate 		return (-1);
1242*7c478bd9Sstevel@tonic-gate 	}
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 	/*
1245*7c478bd9Sstevel@tonic-gate 	 * Now detach mem devinfo nodes with status lock held.
1246*7c478bd9Sstevel@tonic-gate 	 */
1247*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
1248*7c478bd9Sstevel@tonic-gate 		dev_info_t	*fdip = NULL;
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate 		if (mp->sbm_dip[i] == NULL)
1251*7c478bd9Sstevel@tonic-gate 			continue;
1252*7c478bd9Sstevel@tonic-gate 		ASSERT(e_ddi_branch_held(mp->sbm_dip[i]));
1253*7c478bd9Sstevel@tonic-gate 		mutex_enter(&sbp->sb_slock);
1254*7c478bd9Sstevel@tonic-gate 		rv = e_ddi_branch_unconfigure(mp->sbm_dip[i], &fdip,
1255*7c478bd9Sstevel@tonic-gate 		    DEVI_BRANCH_EVENT);
1256*7c478bd9Sstevel@tonic-gate 		mutex_exit(&sbp->sb_slock);
1257*7c478bd9Sstevel@tonic-gate 		if (rv) {
1258*7c478bd9Sstevel@tonic-gate 			/*
1259*7c478bd9Sstevel@tonic-gate 			 * If non-NULL, fdip is returned held and must be
1260*7c478bd9Sstevel@tonic-gate 			 * released.
1261*7c478bd9Sstevel@tonic-gate 			 */
1262*7c478bd9Sstevel@tonic-gate 			if (fdip != NULL) {
1263*7c478bd9Sstevel@tonic-gate 				sbd_errno_decode(rv, ep, fdip);
1264*7c478bd9Sstevel@tonic-gate 				ddi_release_devi(fdip);
1265*7c478bd9Sstevel@tonic-gate 			} else {
1266*7c478bd9Sstevel@tonic-gate 				sbd_errno_decode(rv, ep, mp->sbm_dip[i]);
1267*7c478bd9Sstevel@tonic-gate 			}
1268*7c478bd9Sstevel@tonic-gate 		}
1269*7c478bd9Sstevel@tonic-gate 	}
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	return (0);
1272*7c478bd9Sstevel@tonic-gate }
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate /* start beginning of sbd.c */
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate /*
1277*7c478bd9Sstevel@tonic-gate  * MDR          memory support - somewhat disabled for now.
1278*7c478bd9Sstevel@tonic-gate  * UNSAFE       unsafe driver code - I don't think we want this.
1279*7c478bd9Sstevel@tonic-gate  *              need to check.
1280*7c478bd9Sstevel@tonic-gate  * DEVNODE      This driver creates attachment points for individual
1281*7c478bd9Sstevel@tonic-gate  *              components as well as boards.  We only need board
1282*7c478bd9Sstevel@tonic-gate  *              support.
1283*7c478bd9Sstevel@tonic-gate  * DEV2DEVSET   Put only present devices in devset.
1284*7c478bd9Sstevel@tonic-gate  */
1285*7c478bd9Sstevel@tonic-gate 
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate static sbd_state_t
1288*7c478bd9Sstevel@tonic-gate rstate_cvt(sbd_istate_t state)
1289*7c478bd9Sstevel@tonic-gate {
1290*7c478bd9Sstevel@tonic-gate 	sbd_state_t cs;
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	switch (state) {
1293*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_EMPTY:
1294*7c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_EMPTY;
1295*7c478bd9Sstevel@tonic-gate 		break;
1296*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_OCCUPIED:
1297*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_FATAL:
1298*7c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_DISCONNECTED;
1299*7c478bd9Sstevel@tonic-gate 		break;
1300*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONFIGURED:
1301*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONNECTED:
1302*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNCONFIGURED:
1303*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_PARTIAL:
1304*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_RELEASE:
1305*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNREFERENCED:
1306*7c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_CONNECTED;
1307*7c478bd9Sstevel@tonic-gate 		break;
1308*7c478bd9Sstevel@tonic-gate 	default:
1309*7c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_NONE;
1310*7c478bd9Sstevel@tonic-gate 		break;
1311*7c478bd9Sstevel@tonic-gate 	}
1312*7c478bd9Sstevel@tonic-gate 
1313*7c478bd9Sstevel@tonic-gate 	return (cs);
1314*7c478bd9Sstevel@tonic-gate }
1315*7c478bd9Sstevel@tonic-gate 
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate sbd_state_t
1318*7c478bd9Sstevel@tonic-gate ostate_cvt(sbd_istate_t state)
1319*7c478bd9Sstevel@tonic-gate {
1320*7c478bd9Sstevel@tonic-gate 	sbd_state_t cs;
1321*7c478bd9Sstevel@tonic-gate 
1322*7c478bd9Sstevel@tonic-gate 	switch (state) {
1323*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_EMPTY:
1324*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_OCCUPIED:
1325*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNCONFIGURED:
1326*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONNECTED:
1327*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_FATAL:
1328*7c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_UNCONFIGURED;
1329*7c478bd9Sstevel@tonic-gate 		break;
1330*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_PARTIAL:
1331*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONFIGURED:
1332*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_RELEASE:
1333*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNREFERENCED:
1334*7c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_CONFIGURED;
1335*7c478bd9Sstevel@tonic-gate 		break;
1336*7c478bd9Sstevel@tonic-gate 	default:
1337*7c478bd9Sstevel@tonic-gate 		cs = SBD_STAT_NONE;
1338*7c478bd9Sstevel@tonic-gate 		break;
1339*7c478bd9Sstevel@tonic-gate 	}
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate 	return (cs);
1342*7c478bd9Sstevel@tonic-gate }
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate int
1345*7c478bd9Sstevel@tonic-gate sbd_dealloc_instance(sbd_board_t *sbp, int max_boards)
1346*7c478bd9Sstevel@tonic-gate {
1347*7c478bd9Sstevel@tonic-gate 	int		b;
1348*7c478bd9Sstevel@tonic-gate 	sbd_board_t    *list = sbp;
1349*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_dealloc_instance";
1350*7c478bd9Sstevel@tonic-gate 
1351*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
1352*7c478bd9Sstevel@tonic-gate 
1353*7c478bd9Sstevel@tonic-gate 	if (sbp == NULL) {
1354*7c478bd9Sstevel@tonic-gate 		return (-1);
1355*7c478bd9Sstevel@tonic-gate 	}
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate 	for (b = 0; b < max_boards; b++) {
1358*7c478bd9Sstevel@tonic-gate 		sbd_board_destroy(sbp++);
1359*7c478bd9Sstevel@tonic-gate 	}
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate 	FREESTRUCT(list, sbd_board_t, max_boards);
1362*7c478bd9Sstevel@tonic-gate 
1363*7c478bd9Sstevel@tonic-gate 	return (0);
1364*7c478bd9Sstevel@tonic-gate }
1365*7c478bd9Sstevel@tonic-gate 
1366*7c478bd9Sstevel@tonic-gate static sbd_devset_t
1367*7c478bd9Sstevel@tonic-gate sbd_dev2devset(sbd_comp_id_t *cid)
1368*7c478bd9Sstevel@tonic-gate {
1369*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_dev2devset";
1370*7c478bd9Sstevel@tonic-gate 
1371*7c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
1372*7c478bd9Sstevel@tonic-gate 	int		unit = cid->c_unit;
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate 	switch (cid->c_type) {
1375*7c478bd9Sstevel@tonic-gate 		case SBD_COMP_NONE:
1376*7c478bd9Sstevel@tonic-gate 			devset =  DEVSET(SBD_COMP_CPU, DEVSET_ANYUNIT);
1377*7c478bd9Sstevel@tonic-gate 			devset |= DEVSET(SBD_COMP_MEM, DEVSET_ANYUNIT);
1378*7c478bd9Sstevel@tonic-gate 			devset |= DEVSET(SBD_COMP_IO,  DEVSET_ANYUNIT);
1379*7c478bd9Sstevel@tonic-gate 			break;
1380*7c478bd9Sstevel@tonic-gate 
1381*7c478bd9Sstevel@tonic-gate 		case SBD_COMP_CPU:
1382*7c478bd9Sstevel@tonic-gate 			if ((unit > MAX_CPU_UNITS_PER_BOARD) || (unit < 0)) {
1383*7c478bd9Sstevel@tonic-gate 				PR_ALL("%s: invalid cpu unit# = %d",
1384*7c478bd9Sstevel@tonic-gate 					f, unit);
1385*7c478bd9Sstevel@tonic-gate 				devset = 0;
1386*7c478bd9Sstevel@tonic-gate 			} else
1387*7c478bd9Sstevel@tonic-gate 				/*
1388*7c478bd9Sstevel@tonic-gate 				 * Generate a devset that includes all the
1389*7c478bd9Sstevel@tonic-gate 				 * cores of a CMP device. If this is not a
1390*7c478bd9Sstevel@tonic-gate 				 * CMP, the extra cores will be eliminated
1391*7c478bd9Sstevel@tonic-gate 				 * later since they are not present. This is
1392*7c478bd9Sstevel@tonic-gate 				 * also true for CMP devices that do not have
1393*7c478bd9Sstevel@tonic-gate 				 * all cores active.
1394*7c478bd9Sstevel@tonic-gate 				 */
1395*7c478bd9Sstevel@tonic-gate 				devset = DEVSET(SBD_COMP_CMP, unit);
1396*7c478bd9Sstevel@tonic-gate 
1397*7c478bd9Sstevel@tonic-gate 			break;
1398*7c478bd9Sstevel@tonic-gate 
1399*7c478bd9Sstevel@tonic-gate 		case SBD_COMP_MEM:
1400*7c478bd9Sstevel@tonic-gate 
1401*7c478bd9Sstevel@tonic-gate 			if ((unit > MAX_MEM_UNITS_PER_BOARD) || (unit < 0)) {
1402*7c478bd9Sstevel@tonic-gate #ifdef XXX_jeffco
1403*7c478bd9Sstevel@tonic-gate 				PR_ALL("%s: invalid mem unit# = %d",
1404*7c478bd9Sstevel@tonic-gate 					f, unit);
1405*7c478bd9Sstevel@tonic-gate 				devset = 0;
1406*7c478bd9Sstevel@tonic-gate #endif
1407*7c478bd9Sstevel@tonic-gate 				devset = DEVSET(cid->c_type, 0);
1408*7c478bd9Sstevel@tonic-gate 				PR_ALL("%s: adjusted MEM devset = 0x%x\n",
1409*7c478bd9Sstevel@tonic-gate 					f, devset);
1410*7c478bd9Sstevel@tonic-gate 			} else
1411*7c478bd9Sstevel@tonic-gate 				devset = DEVSET(cid->c_type, unit);
1412*7c478bd9Sstevel@tonic-gate 			break;
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate 		case SBD_COMP_IO:
1415*7c478bd9Sstevel@tonic-gate 			if ((unit > MAX_IO_UNITS_PER_BOARD) || (unit < 0)) {
1416*7c478bd9Sstevel@tonic-gate 				PR_ALL("%s: invalid io unit# = %d",
1417*7c478bd9Sstevel@tonic-gate 					f, unit);
1418*7c478bd9Sstevel@tonic-gate 				devset = 0;
1419*7c478bd9Sstevel@tonic-gate 			} else
1420*7c478bd9Sstevel@tonic-gate 				devset = DEVSET(cid->c_type, unit);
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate 			break;
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate 		default:
1425*7c478bd9Sstevel@tonic-gate 		case SBD_COMP_UNKNOWN:
1426*7c478bd9Sstevel@tonic-gate 			devset = 0;
1427*7c478bd9Sstevel@tonic-gate 			break;
1428*7c478bd9Sstevel@tonic-gate 	}
1429*7c478bd9Sstevel@tonic-gate 
1430*7c478bd9Sstevel@tonic-gate 	return (devset);
1431*7c478bd9Sstevel@tonic-gate }
1432*7c478bd9Sstevel@tonic-gate 
1433*7c478bd9Sstevel@tonic-gate /*
1434*7c478bd9Sstevel@tonic-gate  * Simple mutex for covering handle list ops as it is only
1435*7c478bd9Sstevel@tonic-gate  * used "infrequently". No need to add another mutex to the sbd_board_t.
1436*7c478bd9Sstevel@tonic-gate  */
1437*7c478bd9Sstevel@tonic-gate static kmutex_t sbd_handle_list_mutex;
1438*7c478bd9Sstevel@tonic-gate 
1439*7c478bd9Sstevel@tonic-gate static sbd_handle_t *
1440*7c478bd9Sstevel@tonic-gate sbd_get_handle(dev_t dev, sbd_softstate_t *softsp, intptr_t arg,
1441*7c478bd9Sstevel@tonic-gate 	sbd_init_arg_t *iap)
1442*7c478bd9Sstevel@tonic-gate {
1443*7c478bd9Sstevel@tonic-gate 	sbd_handle_t		*hp;
1444*7c478bd9Sstevel@tonic-gate 	sbderror_t		*ep;
1445*7c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp;
1446*7c478bd9Sstevel@tonic-gate 	sbd_board_t		*sbp = softsp->sbd_boardlist;
1447*7c478bd9Sstevel@tonic-gate 	int			board;
1448*7c478bd9Sstevel@tonic-gate 
1449*7c478bd9Sstevel@tonic-gate 	board = SBDGETSLOT(dev);
1450*7c478bd9Sstevel@tonic-gate 	ASSERT(board < softsp->max_boards);
1451*7c478bd9Sstevel@tonic-gate 	sbp += board;
1452*7c478bd9Sstevel@tonic-gate 
1453*7c478bd9Sstevel@tonic-gate 	/*
1454*7c478bd9Sstevel@tonic-gate 	 * Brand-new handle.
1455*7c478bd9Sstevel@tonic-gate 	 */
1456*7c478bd9Sstevel@tonic-gate 	shp = kmem_zalloc(sizeof (sbd_priv_handle_t), KM_SLEEP);
1457*7c478bd9Sstevel@tonic-gate 	shp->sh_arg = (void *)arg;
1458*7c478bd9Sstevel@tonic-gate 
1459*7c478bd9Sstevel@tonic-gate 	hp = MACHHD2HD(shp);
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate 	ep = &shp->sh_err;
1462*7c478bd9Sstevel@tonic-gate 
1463*7c478bd9Sstevel@tonic-gate 	hp->h_err = ep;
1464*7c478bd9Sstevel@tonic-gate 	hp->h_sbd = (void *) sbp;
1465*7c478bd9Sstevel@tonic-gate 	hp->h_dev = iap->dev;
1466*7c478bd9Sstevel@tonic-gate 	hp->h_cmd = iap->cmd;
1467*7c478bd9Sstevel@tonic-gate 	hp->h_mode = iap->mode;
1468*7c478bd9Sstevel@tonic-gate 	sbd_init_err(ep);
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate 	mutex_enter(&sbd_handle_list_mutex);
1471*7c478bd9Sstevel@tonic-gate 	shp->sh_next = sbp->sb_handle;
1472*7c478bd9Sstevel@tonic-gate 	sbp->sb_handle = shp;
1473*7c478bd9Sstevel@tonic-gate 	mutex_exit(&sbd_handle_list_mutex);
1474*7c478bd9Sstevel@tonic-gate 
1475*7c478bd9Sstevel@tonic-gate 	return (hp);
1476*7c478bd9Sstevel@tonic-gate }
1477*7c478bd9Sstevel@tonic-gate 
1478*7c478bd9Sstevel@tonic-gate void
1479*7c478bd9Sstevel@tonic-gate sbd_init_err(sbderror_t *ep)
1480*7c478bd9Sstevel@tonic-gate {
1481*7c478bd9Sstevel@tonic-gate 	ep->e_errno = 0;
1482*7c478bd9Sstevel@tonic-gate 	ep->e_code = 0;
1483*7c478bd9Sstevel@tonic-gate 	ep->e_rsc[0] = '\0';
1484*7c478bd9Sstevel@tonic-gate }
1485*7c478bd9Sstevel@tonic-gate 
1486*7c478bd9Sstevel@tonic-gate int
1487*7c478bd9Sstevel@tonic-gate sbd_set_err_in_hdl(sbd_handle_t *hp, sbderror_t *ep)
1488*7c478bd9Sstevel@tonic-gate {
1489*7c478bd9Sstevel@tonic-gate 	sbderror_t	*hep = SBD_HD2ERR(hp);
1490*7c478bd9Sstevel@tonic-gate 
1491*7c478bd9Sstevel@tonic-gate 	/*
1492*7c478bd9Sstevel@tonic-gate 	 * If there is an error logged already, don't rewrite it
1493*7c478bd9Sstevel@tonic-gate 	 */
1494*7c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERR(hep) || SBD_GET_ERRNO(hep)) {
1495*7c478bd9Sstevel@tonic-gate 		return (0);
1496*7c478bd9Sstevel@tonic-gate 	}
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERR(ep) || SBD_GET_ERRNO(ep)) {
1499*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(hep, SBD_GET_ERR(ep));
1500*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(hep, SBD_GET_ERRNO(ep));
1501*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(hep, SBD_GET_ERRSTR(ep));
1502*7c478bd9Sstevel@tonic-gate 		return (0);
1503*7c478bd9Sstevel@tonic-gate 	}
1504*7c478bd9Sstevel@tonic-gate 
1505*7c478bd9Sstevel@tonic-gate 	return (-1);
1506*7c478bd9Sstevel@tonic-gate }
1507*7c478bd9Sstevel@tonic-gate 
1508*7c478bd9Sstevel@tonic-gate static void
1509*7c478bd9Sstevel@tonic-gate sbd_release_handle(sbd_handle_t *hp)
1510*7c478bd9Sstevel@tonic-gate {
1511*7c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp, **shpp;
1512*7c478bd9Sstevel@tonic-gate 	sbd_board_t		*sbp;
1513*7c478bd9Sstevel@tonic-gate 	static fn_t		f = "sbd_release_handle";
1514*7c478bd9Sstevel@tonic-gate 
1515*7c478bd9Sstevel@tonic-gate 	if (hp == NULL)
1516*7c478bd9Sstevel@tonic-gate 		return;
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
1519*7c478bd9Sstevel@tonic-gate 
1520*7c478bd9Sstevel@tonic-gate 	shp = HD2MACHHD(hp);
1521*7c478bd9Sstevel@tonic-gate 
1522*7c478bd9Sstevel@tonic-gate 	mutex_enter(&sbd_handle_list_mutex);
1523*7c478bd9Sstevel@tonic-gate 	/*
1524*7c478bd9Sstevel@tonic-gate 	 * Locate the handle in the board's reference list.
1525*7c478bd9Sstevel@tonic-gate 	 */
1526*7c478bd9Sstevel@tonic-gate 	for (shpp = &sbp->sb_handle; (*shpp) && ((*shpp) != shp);
1527*7c478bd9Sstevel@tonic-gate 	    shpp = &((*shpp)->sh_next))
1528*7c478bd9Sstevel@tonic-gate 		/* empty */;
1529*7c478bd9Sstevel@tonic-gate 
1530*7c478bd9Sstevel@tonic-gate 	if (*shpp == NULL) {
1531*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC,
1532*7c478bd9Sstevel@tonic-gate 			"sbd:%s: handle not found in board %d",
1533*7c478bd9Sstevel@tonic-gate 			f, sbp->sb_num);
1534*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1535*7c478bd9Sstevel@tonic-gate 	} else {
1536*7c478bd9Sstevel@tonic-gate 		*shpp = shp->sh_next;
1537*7c478bd9Sstevel@tonic-gate 	}
1538*7c478bd9Sstevel@tonic-gate 	mutex_exit(&sbd_handle_list_mutex);
1539*7c478bd9Sstevel@tonic-gate 
1540*7c478bd9Sstevel@tonic-gate 	if (hp->h_opts.copts != NULL) {
1541*7c478bd9Sstevel@tonic-gate 		FREESTRUCT(hp->h_opts.copts, char, hp->h_opts.size);
1542*7c478bd9Sstevel@tonic-gate 	}
1543*7c478bd9Sstevel@tonic-gate 
1544*7c478bd9Sstevel@tonic-gate 	FREESTRUCT(shp, sbd_priv_handle_t, 1);
1545*7c478bd9Sstevel@tonic-gate }
1546*7c478bd9Sstevel@tonic-gate 
1547*7c478bd9Sstevel@tonic-gate sbdp_handle_t *
1548*7c478bd9Sstevel@tonic-gate sbd_get_sbdp_handle(sbd_board_t *sbp, sbd_handle_t *hp)
1549*7c478bd9Sstevel@tonic-gate {
1550*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t		*hdp;
1551*7c478bd9Sstevel@tonic-gate 
1552*7c478bd9Sstevel@tonic-gate 	hdp = kmem_zalloc(sizeof (sbdp_handle_t), KM_SLEEP);
1553*7c478bd9Sstevel@tonic-gate 	hdp->h_err = kmem_zalloc(sizeof (sbd_error_t), KM_SLEEP);
1554*7c478bd9Sstevel@tonic-gate 	if (sbp == NULL) {
1555*7c478bd9Sstevel@tonic-gate 		hdp->h_board = -1;
1556*7c478bd9Sstevel@tonic-gate 		hdp->h_wnode = -1;
1557*7c478bd9Sstevel@tonic-gate 	} else {
1558*7c478bd9Sstevel@tonic-gate 		hdp->h_board = sbp->sb_num;
1559*7c478bd9Sstevel@tonic-gate 		hdp->h_wnode = sbp->sb_wnode;
1560*7c478bd9Sstevel@tonic-gate 	}
1561*7c478bd9Sstevel@tonic-gate 
1562*7c478bd9Sstevel@tonic-gate 	if (hp == NULL) {
1563*7c478bd9Sstevel@tonic-gate 		hdp->h_flags = 0;
1564*7c478bd9Sstevel@tonic-gate 		hdp->h_opts = NULL;
1565*7c478bd9Sstevel@tonic-gate 	} else {
1566*7c478bd9Sstevel@tonic-gate 		hdp->h_flags = SBD_2_SBDP_FLAGS(hp->h_flags);
1567*7c478bd9Sstevel@tonic-gate 		hdp->h_opts = &hp->h_opts;
1568*7c478bd9Sstevel@tonic-gate 	}
1569*7c478bd9Sstevel@tonic-gate 
1570*7c478bd9Sstevel@tonic-gate 	return (hdp);
1571*7c478bd9Sstevel@tonic-gate }
1572*7c478bd9Sstevel@tonic-gate 
1573*7c478bd9Sstevel@tonic-gate void
1574*7c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(sbdp_handle_t *hdp)
1575*7c478bd9Sstevel@tonic-gate {
1576*7c478bd9Sstevel@tonic-gate 	if (hdp == NULL)
1577*7c478bd9Sstevel@tonic-gate 		return;
1578*7c478bd9Sstevel@tonic-gate 
1579*7c478bd9Sstevel@tonic-gate 	kmem_free(hdp->h_err, sizeof (sbd_error_t));
1580*7c478bd9Sstevel@tonic-gate 	kmem_free(hdp, sizeof (sbdp_handle_t));
1581*7c478bd9Sstevel@tonic-gate }
1582*7c478bd9Sstevel@tonic-gate 
1583*7c478bd9Sstevel@tonic-gate void
1584*7c478bd9Sstevel@tonic-gate sbd_reset_error_sbdph(sbdp_handle_t *hdp)
1585*7c478bd9Sstevel@tonic-gate {
1586*7c478bd9Sstevel@tonic-gate 	if ((hdp != NULL) && (hdp->h_err != NULL)) {
1587*7c478bd9Sstevel@tonic-gate 		bzero(hdp->h_err, sizeof (sbd_error_t));
1588*7c478bd9Sstevel@tonic-gate 	}
1589*7c478bd9Sstevel@tonic-gate }
1590*7c478bd9Sstevel@tonic-gate 
1591*7c478bd9Sstevel@tonic-gate static int
1592*7c478bd9Sstevel@tonic-gate sbd_copyin_ioarg(sbd_handle_t *hp, int mode, int cmd, sbd_cmd_t *cmdp,
1593*7c478bd9Sstevel@tonic-gate 	sbd_ioctl_arg_t *iap)
1594*7c478bd9Sstevel@tonic-gate {
1595*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_copyin_ioarg";
1596*7c478bd9Sstevel@tonic-gate 
1597*7c478bd9Sstevel@tonic-gate 	if (iap == NULL)
1598*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1599*7c478bd9Sstevel@tonic-gate 
1600*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cmdp, sizeof (sbd_cmd_t));
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
1603*7c478bd9Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
1604*7c478bd9Sstevel@tonic-gate 		sbd_cmd32_t	scmd32;
1605*7c478bd9Sstevel@tonic-gate 
1606*7c478bd9Sstevel@tonic-gate 		bzero((caddr_t)&scmd32, sizeof (sbd_cmd32_t));
1607*7c478bd9Sstevel@tonic-gate 
1608*7c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)iap, (void *)&scmd32,
1609*7c478bd9Sstevel@tonic-gate 				sizeof (sbd_cmd32_t), mode)) {
1610*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1611*7c478bd9Sstevel@tonic-gate 				"sbd:%s: (32bit) failed to copyin "
1612*7c478bd9Sstevel@tonic-gate 					"sbdcmd-struct", f);
1613*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1614*7c478bd9Sstevel@tonic-gate 		}
1615*7c478bd9Sstevel@tonic-gate 		cmdp->cmd_cm.c_id.c_type = scmd32.cmd_cm.c_id.c_type;
1616*7c478bd9Sstevel@tonic-gate 		cmdp->cmd_cm.c_id.c_unit = scmd32.cmd_cm.c_id.c_unit;
1617*7c478bd9Sstevel@tonic-gate 		bcopy(&scmd32.cmd_cm.c_id.c_name[0],
1618*7c478bd9Sstevel@tonic-gate 			&cmdp->cmd_cm.c_id.c_name[0], OBP_MAXPROPNAME);
1619*7c478bd9Sstevel@tonic-gate 		cmdp->cmd_cm.c_flags = scmd32.cmd_cm.c_flags;
1620*7c478bd9Sstevel@tonic-gate 		cmdp->cmd_cm.c_len = scmd32.cmd_cm.c_len;
1621*7c478bd9Sstevel@tonic-gate 		cmdp->cmd_cm.c_opts = (caddr_t)scmd32.cmd_cm.c_opts;
1622*7c478bd9Sstevel@tonic-gate 
1623*7c478bd9Sstevel@tonic-gate 		if (cmd == SBD_CMD_PASSTHRU) {
1624*7c478bd9Sstevel@tonic-gate 			PR_BYP("passthru copyin: iap=%p, sz=%d", iap,
1625*7c478bd9Sstevel@tonic-gate 				sizeof (sbd_cmd32_t));
1626*7c478bd9Sstevel@tonic-gate 			PR_BYP("passthru copyin: c_opts=%p, c_len=%d",
1627*7c478bd9Sstevel@tonic-gate 				scmd32.cmd_cm.c_opts,
1628*7c478bd9Sstevel@tonic-gate 				scmd32.cmd_cm.c_len);
1629*7c478bd9Sstevel@tonic-gate 		}
1630*7c478bd9Sstevel@tonic-gate 
1631*7c478bd9Sstevel@tonic-gate 		switch (cmd) {
1632*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_STATUS:
1633*7c478bd9Sstevel@tonic-gate 			cmdp->cmd_stat.s_nbytes = scmd32.cmd_stat.s_nbytes;
1634*7c478bd9Sstevel@tonic-gate 			cmdp->cmd_stat.s_statp =
1635*7c478bd9Sstevel@tonic-gate 				(caddr_t)scmd32.cmd_stat.s_statp;
1636*7c478bd9Sstevel@tonic-gate 			break;
1637*7c478bd9Sstevel@tonic-gate 		default:
1638*7c478bd9Sstevel@tonic-gate 			break;
1639*7c478bd9Sstevel@tonic-gate 
1640*7c478bd9Sstevel@tonic-gate 		}
1641*7c478bd9Sstevel@tonic-gate 	} else
1642*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
1643*7c478bd9Sstevel@tonic-gate 	if (ddi_copyin((void *)iap, (void *)cmdp,
1644*7c478bd9Sstevel@tonic-gate 			sizeof (sbd_cmd_t), mode) != 0) {
1645*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1646*7c478bd9Sstevel@tonic-gate 			"sbd:%s: failed to copyin sbd cmd_t struct", f);
1647*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1648*7c478bd9Sstevel@tonic-gate 	}
1649*7c478bd9Sstevel@tonic-gate 	/*
1650*7c478bd9Sstevel@tonic-gate 	 * A user may set platform specific options so we need to
1651*7c478bd9Sstevel@tonic-gate 	 * copy them in
1652*7c478bd9Sstevel@tonic-gate 	 */
1653*7c478bd9Sstevel@tonic-gate 	if ((cmd != SBD_CMD_STATUS) && ((hp->h_opts.size = cmdp->cmd_cm.c_len)
1654*7c478bd9Sstevel@tonic-gate 	    > 0)) {
1655*7c478bd9Sstevel@tonic-gate 		hp->h_opts.size += 1;	/* For null termination of string. */
1656*7c478bd9Sstevel@tonic-gate 		hp->h_opts.copts = GETSTRUCT(char, hp->h_opts.size);
1657*7c478bd9Sstevel@tonic-gate 		if (ddi_copyin((void *)cmdp->cmd_cm.c_opts,
1658*7c478bd9Sstevel@tonic-gate 		    (void *)hp->h_opts.copts,
1659*7c478bd9Sstevel@tonic-gate 		    cmdp->cmd_cm.c_len, hp->h_mode) != 0) {
1660*7c478bd9Sstevel@tonic-gate 			/* copts is freed in sbd_release_handle(). */
1661*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1662*7c478bd9Sstevel@tonic-gate 			    "sbd:%s: failed to copyin options", f);
1663*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1664*7c478bd9Sstevel@tonic-gate 		}
1665*7c478bd9Sstevel@tonic-gate 	}
1666*7c478bd9Sstevel@tonic-gate 
1667*7c478bd9Sstevel@tonic-gate 	return (0);
1668*7c478bd9Sstevel@tonic-gate }
1669*7c478bd9Sstevel@tonic-gate 
1670*7c478bd9Sstevel@tonic-gate static int
1671*7c478bd9Sstevel@tonic-gate sbd_copyout_ioarg(int mode, int cmd, sbd_cmd_t *scp, sbd_ioctl_arg_t *iap)
1672*7c478bd9Sstevel@tonic-gate {
1673*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_copyout_ioarg";
1674*7c478bd9Sstevel@tonic-gate 
1675*7c478bd9Sstevel@tonic-gate 	if ((iap == NULL) || (scp == NULL))
1676*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1677*7c478bd9Sstevel@tonic-gate 
1678*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
1679*7c478bd9Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
1680*7c478bd9Sstevel@tonic-gate 		sbd_cmd32_t	scmd32;
1681*7c478bd9Sstevel@tonic-gate 
1682*7c478bd9Sstevel@tonic-gate 		scmd32.cmd_cm.c_id.c_type = scp->cmd_cm.c_id.c_type;
1683*7c478bd9Sstevel@tonic-gate 		scmd32.cmd_cm.c_id.c_unit = scp->cmd_cm.c_id.c_unit;
1684*7c478bd9Sstevel@tonic-gate 		bcopy(scp->cmd_cm.c_id.c_name,
1685*7c478bd9Sstevel@tonic-gate 			scmd32.cmd_cm.c_id.c_name, OBP_MAXPROPNAME);
1686*7c478bd9Sstevel@tonic-gate 
1687*7c478bd9Sstevel@tonic-gate 		scmd32.cmd_cm.c_flags = scp->cmd_cm.c_flags;
1688*7c478bd9Sstevel@tonic-gate 
1689*7c478bd9Sstevel@tonic-gate 		switch (cmd) {
1690*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_GETNCM:
1691*7c478bd9Sstevel@tonic-gate 			scmd32.cmd_getncm.g_ncm = scp->cmd_getncm.g_ncm;
1692*7c478bd9Sstevel@tonic-gate 			break;
1693*7c478bd9Sstevel@tonic-gate 		default:
1694*7c478bd9Sstevel@tonic-gate 			break;
1695*7c478bd9Sstevel@tonic-gate 		}
1696*7c478bd9Sstevel@tonic-gate 
1697*7c478bd9Sstevel@tonic-gate 		if (ddi_copyout((void *)&scmd32, (void *)iap,
1698*7c478bd9Sstevel@tonic-gate 				sizeof (sbd_cmd32_t), mode)) {
1699*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1700*7c478bd9Sstevel@tonic-gate 				"sbd:%s: (32bit) failed to copyout "
1701*7c478bd9Sstevel@tonic-gate 					"sbdcmd struct", f);
1702*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1703*7c478bd9Sstevel@tonic-gate 		}
1704*7c478bd9Sstevel@tonic-gate 	} else
1705*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
1706*7c478bd9Sstevel@tonic-gate 	if (ddi_copyout((void *)scp, (void *)iap,
1707*7c478bd9Sstevel@tonic-gate 			sizeof (sbd_cmd_t), mode) != 0) {
1708*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1709*7c478bd9Sstevel@tonic-gate 			"sbd:%s: failed to copyout sbdcmd struct", f);
1710*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1711*7c478bd9Sstevel@tonic-gate 	}
1712*7c478bd9Sstevel@tonic-gate 
1713*7c478bd9Sstevel@tonic-gate 	return (0);
1714*7c478bd9Sstevel@tonic-gate }
1715*7c478bd9Sstevel@tonic-gate 
1716*7c478bd9Sstevel@tonic-gate static int
1717*7c478bd9Sstevel@tonic-gate sbd_copyout_errs(int mode, sbd_ioctl_arg_t *iap, void *arg)
1718*7c478bd9Sstevel@tonic-gate {
1719*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_copyout_errs";
1720*7c478bd9Sstevel@tonic-gate 	sbd_ioctl_arg_t	*uap;
1721*7c478bd9Sstevel@tonic-gate 
1722*7c478bd9Sstevel@tonic-gate 	uap = (sbd_ioctl_arg_t *)arg;
1723*7c478bd9Sstevel@tonic-gate 
1724*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
1725*7c478bd9Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
1726*7c478bd9Sstevel@tonic-gate 		sbd_error32_t err32;
1727*7c478bd9Sstevel@tonic-gate 		sbd_ioctl_arg32_t *uap32;
1728*7c478bd9Sstevel@tonic-gate 
1729*7c478bd9Sstevel@tonic-gate 		uap32 = (sbd_ioctl_arg32_t *)arg;
1730*7c478bd9Sstevel@tonic-gate 
1731*7c478bd9Sstevel@tonic-gate 		err32.e_code = iap->ie_code;
1732*7c478bd9Sstevel@tonic-gate 		(void) strcpy(err32.e_rsc, iap->ie_rsc);
1733*7c478bd9Sstevel@tonic-gate 
1734*7c478bd9Sstevel@tonic-gate 		if (ddi_copyout((void *)&err32, (void *)&uap32->i_err,
1735*7c478bd9Sstevel@tonic-gate 				sizeof (sbd_error32_t), mode)) {
1736*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1737*7c478bd9Sstevel@tonic-gate 				"sbd:%s: failed to copyout ioctl32 errs",
1738*7c478bd9Sstevel@tonic-gate 				f);
1739*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1740*7c478bd9Sstevel@tonic-gate 		}
1741*7c478bd9Sstevel@tonic-gate 	} else
1742*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
1743*7c478bd9Sstevel@tonic-gate 	if (ddi_copyout((void *)&iap->i_err, (void *)&uap->i_err,
1744*7c478bd9Sstevel@tonic-gate 			sizeof (sbd_error_t), mode) != 0) {
1745*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1746*7c478bd9Sstevel@tonic-gate 			"sbd:%s: failed to copyout ioctl errs", f);
1747*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1748*7c478bd9Sstevel@tonic-gate 	}
1749*7c478bd9Sstevel@tonic-gate 
1750*7c478bd9Sstevel@tonic-gate 	return (0);
1751*7c478bd9Sstevel@tonic-gate }
1752*7c478bd9Sstevel@tonic-gate 
1753*7c478bd9Sstevel@tonic-gate /*
1754*7c478bd9Sstevel@tonic-gate  * State transition policy is that if at least one
1755*7c478bd9Sstevel@tonic-gate  * device cannot make the transition, then none of
1756*7c478bd9Sstevel@tonic-gate  * the requested devices are allowed to transition.
1757*7c478bd9Sstevel@tonic-gate  *
1758*7c478bd9Sstevel@tonic-gate  * Returns the state that is in error, if any.
1759*7c478bd9Sstevel@tonic-gate  */
1760*7c478bd9Sstevel@tonic-gate static int
1761*7c478bd9Sstevel@tonic-gate sbd_check_transition(sbd_board_t *sbp, sbd_devset_t *devsetp,
1762*7c478bd9Sstevel@tonic-gate 			struct sbd_state_trans *transp)
1763*7c478bd9Sstevel@tonic-gate {
1764*7c478bd9Sstevel@tonic-gate 	int	s, ut;
1765*7c478bd9Sstevel@tonic-gate 	int	state_err = 0;
1766*7c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
1767*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_check_transition";
1768*7c478bd9Sstevel@tonic-gate 
1769*7c478bd9Sstevel@tonic-gate 	devset = *devsetp;
1770*7c478bd9Sstevel@tonic-gate 
1771*7c478bd9Sstevel@tonic-gate 	if (!devset) {
1772*7c478bd9Sstevel@tonic-gate 		/*
1773*7c478bd9Sstevel@tonic-gate 		 * Transition does not deal with any components.
1774*7c478bd9Sstevel@tonic-gate 		 * This is the case for addboard/deleteboard.
1775*7c478bd9Sstevel@tonic-gate 		 */
1776*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s: no devs: requested devset = 0x%x,"
1777*7c478bd9Sstevel@tonic-gate 			" final devset = 0x%x\n",
1778*7c478bd9Sstevel@tonic-gate 			f, (uint_t)*devsetp, (uint_t)devset);
1779*7c478bd9Sstevel@tonic-gate 
1780*7c478bd9Sstevel@tonic-gate 		return (0);
1781*7c478bd9Sstevel@tonic-gate 	}
1782*7c478bd9Sstevel@tonic-gate 
1783*7c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) {
1784*7c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) {
1785*7c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_MEM, ut) == 0)
1786*7c478bd9Sstevel@tonic-gate 				continue;
1787*7c478bd9Sstevel@tonic-gate 			s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_MEM, ut);
1788*7c478bd9Sstevel@tonic-gate 			if (transp->x_op[s].x_rv) {
1789*7c478bd9Sstevel@tonic-gate 				if (!state_err)
1790*7c478bd9Sstevel@tonic-gate 					state_err = s;
1791*7c478bd9Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_MEM, ut);
1792*7c478bd9Sstevel@tonic-gate 			}
1793*7c478bd9Sstevel@tonic-gate 		}
1794*7c478bd9Sstevel@tonic-gate 	}
1795*7c478bd9Sstevel@tonic-gate 
1796*7c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) {
1797*7c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) {
1798*7c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_CPU, ut) == 0)
1799*7c478bd9Sstevel@tonic-gate 				continue;
1800*7c478bd9Sstevel@tonic-gate 			s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_CPU, ut);
1801*7c478bd9Sstevel@tonic-gate 			if (transp->x_op[s].x_rv) {
1802*7c478bd9Sstevel@tonic-gate 				if (!state_err)
1803*7c478bd9Sstevel@tonic-gate 					state_err = s;
1804*7c478bd9Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_CPU, ut);
1805*7c478bd9Sstevel@tonic-gate 			}
1806*7c478bd9Sstevel@tonic-gate 		}
1807*7c478bd9Sstevel@tonic-gate 	}
1808*7c478bd9Sstevel@tonic-gate 
1809*7c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) {
1810*7c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) {
1811*7c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_IO, ut) == 0)
1812*7c478bd9Sstevel@tonic-gate 				continue;
1813*7c478bd9Sstevel@tonic-gate 			s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_IO, ut);
1814*7c478bd9Sstevel@tonic-gate 			if (transp->x_op[s].x_rv) {
1815*7c478bd9Sstevel@tonic-gate 				if (!state_err)
1816*7c478bd9Sstevel@tonic-gate 					state_err = s;
1817*7c478bd9Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_IO, ut);
1818*7c478bd9Sstevel@tonic-gate 			}
1819*7c478bd9Sstevel@tonic-gate 		}
1820*7c478bd9Sstevel@tonic-gate 	}
1821*7c478bd9Sstevel@tonic-gate 
1822*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s: requested devset = 0x%x, final devset = 0x%x\n",
1823*7c478bd9Sstevel@tonic-gate 		f, (uint_t)*devsetp, (uint_t)devset);
1824*7c478bd9Sstevel@tonic-gate 
1825*7c478bd9Sstevel@tonic-gate 	*devsetp = devset;
1826*7c478bd9Sstevel@tonic-gate 	/*
1827*7c478bd9Sstevel@tonic-gate 	 * If there are some remaining components for which
1828*7c478bd9Sstevel@tonic-gate 	 * this state transition is valid, then allow them
1829*7c478bd9Sstevel@tonic-gate 	 * through, otherwise if none are left then return
1830*7c478bd9Sstevel@tonic-gate 	 * the state error.
1831*7c478bd9Sstevel@tonic-gate 	 */
1832*7c478bd9Sstevel@tonic-gate 	return (devset ? 0 : state_err);
1833*7c478bd9Sstevel@tonic-gate }
1834*7c478bd9Sstevel@tonic-gate 
1835*7c478bd9Sstevel@tonic-gate /*
1836*7c478bd9Sstevel@tonic-gate  * pre-op entry point must SET_ERRNO(), if needed.
1837*7c478bd9Sstevel@tonic-gate  * Return value of non-zero indicates failure.
1838*7c478bd9Sstevel@tonic-gate  */
1839*7c478bd9Sstevel@tonic-gate static int
1840*7c478bd9Sstevel@tonic-gate sbd_pre_op(sbd_handle_t *hp)
1841*7c478bd9Sstevel@tonic-gate {
1842*7c478bd9Sstevel@tonic-gate 	int		rv = 0, t;
1843*7c478bd9Sstevel@tonic-gate 	int		cmd, serr = 0;
1844*7c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
1845*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
1846*7c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp = HD2MACHHD(hp);
1847*7c478bd9Sstevel@tonic-gate 	sbderror_t	*ep = SBD_HD2ERR(hp);
1848*7c478bd9Sstevel@tonic-gate 	sbd_cmd_t	*cmdp;
1849*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_pre_op";
1850*7c478bd9Sstevel@tonic-gate 
1851*7c478bd9Sstevel@tonic-gate 	cmd = hp->h_cmd;
1852*7c478bd9Sstevel@tonic-gate 	devset = shp->sh_devset;
1853*7c478bd9Sstevel@tonic-gate 
1854*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
1855*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONNECT:
1856*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_DISCONNECT:
1857*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_UNCONFIGURE:
1858*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONFIGURE:
1859*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_ASSIGN:
1860*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_UNASSIGN:
1861*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_POWERON:
1862*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_POWEROFF:
1863*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_TEST:
1864*7c478bd9Sstevel@tonic-gate 		/* ioctls allowed if caller has write permission */
1865*7c478bd9Sstevel@tonic-gate 		if (!(hp->h_mode & FWRITE)) {
1866*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, EPERM);
1867*7c478bd9Sstevel@tonic-gate 			return (-1);
1868*7c478bd9Sstevel@tonic-gate 		}
1869*7c478bd9Sstevel@tonic-gate 
1870*7c478bd9Sstevel@tonic-gate 		default:
1871*7c478bd9Sstevel@tonic-gate 		break;
1872*7c478bd9Sstevel@tonic-gate 	}
1873*7c478bd9Sstevel@tonic-gate 
1874*7c478bd9Sstevel@tonic-gate 	hp->h_iap = GETSTRUCT(sbd_ioctl_arg_t, 1);
1875*7c478bd9Sstevel@tonic-gate 	rv = sbd_copyin_ioarg(hp, hp->h_mode, cmd,
1876*7c478bd9Sstevel@tonic-gate 		(sbd_cmd_t *)hp->h_iap, shp->sh_arg);
1877*7c478bd9Sstevel@tonic-gate 	if (rv) {
1878*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(ep, rv);
1879*7c478bd9Sstevel@tonic-gate 		FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1);
1880*7c478bd9Sstevel@tonic-gate 		hp->h_iap = NULL;
1881*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: copyin fail", f);
1882*7c478bd9Sstevel@tonic-gate 		return (-1);
1883*7c478bd9Sstevel@tonic-gate 	} else {
1884*7c478bd9Sstevel@tonic-gate 		cmdp =  (sbd_cmd_t *)hp->h_iap;
1885*7c478bd9Sstevel@tonic-gate 		if (cmdp->cmd_cm.c_id.c_name[0] != '\0') {
1886*7c478bd9Sstevel@tonic-gate 
1887*7c478bd9Sstevel@tonic-gate 			cmdp->cmd_cm.c_id.c_type = SBD_COMP(sbd_name_to_idx(
1888*7c478bd9Sstevel@tonic-gate 				cmdp->cmd_cm.c_id.c_name));
1889*7c478bd9Sstevel@tonic-gate 			if (cmdp->cmd_cm.c_id.c_type == SBD_COMP_MEM) {
1890*7c478bd9Sstevel@tonic-gate 				if (cmdp->cmd_cm.c_id.c_unit == -1)
1891*7c478bd9Sstevel@tonic-gate 					cmdp->cmd_cm.c_id.c_unit = 0;
1892*7c478bd9Sstevel@tonic-gate 			}
1893*7c478bd9Sstevel@tonic-gate 		}
1894*7c478bd9Sstevel@tonic-gate 		devset = shp->sh_orig_devset = shp->sh_devset =
1895*7c478bd9Sstevel@tonic-gate 		    sbd_dev2devset(&cmdp->cmd_cm.c_id);
1896*7c478bd9Sstevel@tonic-gate 		if (devset == 0) {
1897*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, EINVAL);
1898*7c478bd9Sstevel@tonic-gate 			FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1);
1899*7c478bd9Sstevel@tonic-gate 			hp->h_iap = NULL;
1900*7c478bd9Sstevel@tonic-gate 			return (-1);
1901*7c478bd9Sstevel@tonic-gate 		}
1902*7c478bd9Sstevel@tonic-gate 	}
1903*7c478bd9Sstevel@tonic-gate 
1904*7c478bd9Sstevel@tonic-gate 	/*
1905*7c478bd9Sstevel@tonic-gate 	 * Always turn on these bits ala Sunfire DR.
1906*7c478bd9Sstevel@tonic-gate 	 */
1907*7c478bd9Sstevel@tonic-gate 	hp->h_flags |= SBD_FLAG_DEVI_FORCE;
1908*7c478bd9Sstevel@tonic-gate 
1909*7c478bd9Sstevel@tonic-gate 	if (cmdp->cmd_cm.c_flags & SBD_FLAG_FORCE)
1910*7c478bd9Sstevel@tonic-gate 		hp->h_flags |= SBD_IOCTL_FLAG_FORCE;
1911*7c478bd9Sstevel@tonic-gate 
1912*7c478bd9Sstevel@tonic-gate 	/*
1913*7c478bd9Sstevel@tonic-gate 	 * Check for valid state transitions.
1914*7c478bd9Sstevel@tonic-gate 	 */
1915*7c478bd9Sstevel@tonic-gate 	if (!serr && ((t = CMD2INDEX(cmd)) != -1)) {
1916*7c478bd9Sstevel@tonic-gate 		struct sbd_state_trans	*transp;
1917*7c478bd9Sstevel@tonic-gate 		int			state_err;
1918*7c478bd9Sstevel@tonic-gate 
1919*7c478bd9Sstevel@tonic-gate 		transp = &sbd_state_transition[t];
1920*7c478bd9Sstevel@tonic-gate 		ASSERT(transp->x_cmd == cmd);
1921*7c478bd9Sstevel@tonic-gate 
1922*7c478bd9Sstevel@tonic-gate 		state_err = sbd_check_transition(sbp, &devset, transp);
1923*7c478bd9Sstevel@tonic-gate 
1924*7c478bd9Sstevel@tonic-gate 		if (state_err < 0) {
1925*7c478bd9Sstevel@tonic-gate 			/*
1926*7c478bd9Sstevel@tonic-gate 			 * Invalidate device.
1927*7c478bd9Sstevel@tonic-gate 			 */
1928*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, ENOTTY);
1929*7c478bd9Sstevel@tonic-gate 			serr = -1;
1930*7c478bd9Sstevel@tonic-gate 			PR_ALL("%s: invalid devset (0x%x)\n",
1931*7c478bd9Sstevel@tonic-gate 				f, (uint_t)devset);
1932*7c478bd9Sstevel@tonic-gate 		} else if (state_err != 0) {
1933*7c478bd9Sstevel@tonic-gate 			/*
1934*7c478bd9Sstevel@tonic-gate 			 * State transition is not a valid one.
1935*7c478bd9Sstevel@tonic-gate 			 */
1936*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, transp->x_op[state_err].x_err);
1937*7c478bd9Sstevel@tonic-gate 			serr = transp->x_op[state_err].x_rv;
1938*7c478bd9Sstevel@tonic-gate 			PR_ALL("%s: invalid state %s(%d) for cmd %s(%d)\n",
1939*7c478bd9Sstevel@tonic-gate 				f, sbd_state_str[state_err], state_err,
1940*7c478bd9Sstevel@tonic-gate 				SBD_CMD_STR(cmd), cmd);
1941*7c478bd9Sstevel@tonic-gate 		}
1942*7c478bd9Sstevel@tonic-gate 		if (serr && SBD_GET_ERRNO(ep) != 0) {
1943*7c478bd9Sstevel@tonic-gate 			/*
1944*7c478bd9Sstevel@tonic-gate 			 * A state transition error occurred.
1945*7c478bd9Sstevel@tonic-gate 			 */
1946*7c478bd9Sstevel@tonic-gate 			if (serr < 0) {
1947*7c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(ep, ESBD_INVAL);
1948*7c478bd9Sstevel@tonic-gate 			} else {
1949*7c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(ep, ESBD_STATE);
1950*7c478bd9Sstevel@tonic-gate 			}
1951*7c478bd9Sstevel@tonic-gate 			PR_ALL("%s: invalid state transition\n", f);
1952*7c478bd9Sstevel@tonic-gate 		} else {
1953*7c478bd9Sstevel@tonic-gate 			shp->sh_devset = devset;
1954*7c478bd9Sstevel@tonic-gate 		}
1955*7c478bd9Sstevel@tonic-gate 	}
1956*7c478bd9Sstevel@tonic-gate 
1957*7c478bd9Sstevel@tonic-gate 	if (serr && !rv && hp->h_iap) {
1958*7c478bd9Sstevel@tonic-gate 
1959*7c478bd9Sstevel@tonic-gate 		/*
1960*7c478bd9Sstevel@tonic-gate 		 * There was a state error.  We successfully copied
1961*7c478bd9Sstevel@tonic-gate 		 * in the ioctl argument, so let's fill in the
1962*7c478bd9Sstevel@tonic-gate 		 * error and copy it back out.
1963*7c478bd9Sstevel@tonic-gate 		 */
1964*7c478bd9Sstevel@tonic-gate 
1965*7c478bd9Sstevel@tonic-gate 		if (SBD_GET_ERR(ep) && SBD_GET_ERRNO(ep) == 0)
1966*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(ep, EIO);
1967*7c478bd9Sstevel@tonic-gate 
1968*7c478bd9Sstevel@tonic-gate 		SBD_SET_IOCTL_ERR(&hp->h_iap->i_err,
1969*7c478bd9Sstevel@tonic-gate 			ep->e_code,
1970*7c478bd9Sstevel@tonic-gate 			ep->e_rsc);
1971*7c478bd9Sstevel@tonic-gate 		(void) sbd_copyout_errs(hp->h_mode, hp->h_iap, shp->sh_arg);
1972*7c478bd9Sstevel@tonic-gate 		FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1);
1973*7c478bd9Sstevel@tonic-gate 		hp->h_iap = NULL;
1974*7c478bd9Sstevel@tonic-gate 		rv = -1;
1975*7c478bd9Sstevel@tonic-gate 	}
1976*7c478bd9Sstevel@tonic-gate 
1977*7c478bd9Sstevel@tonic-gate 	return (rv);
1978*7c478bd9Sstevel@tonic-gate }
1979*7c478bd9Sstevel@tonic-gate 
1980*7c478bd9Sstevel@tonic-gate static void
1981*7c478bd9Sstevel@tonic-gate sbd_post_op(sbd_handle_t *hp)
1982*7c478bd9Sstevel@tonic-gate {
1983*7c478bd9Sstevel@tonic-gate 	int		cmd;
1984*7c478bd9Sstevel@tonic-gate 	sbderror_t	*ep = SBD_HD2ERR(hp);
1985*7c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp = HD2MACHHD(hp);
1986*7c478bd9Sstevel@tonic-gate 	sbd_board_t    *sbp = SBDH2BD(hp->h_sbd);
1987*7c478bd9Sstevel@tonic-gate 
1988*7c478bd9Sstevel@tonic-gate 	cmd = hp->h_cmd;
1989*7c478bd9Sstevel@tonic-gate 
1990*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
1991*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONFIGURE:
1992*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_UNCONFIGURE:
1993*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_CONNECT:
1994*7c478bd9Sstevel@tonic-gate 		case SBD_CMD_DISCONNECT:
1995*7c478bd9Sstevel@tonic-gate 			sbp->sb_time = gethrestime_sec();
1996*7c478bd9Sstevel@tonic-gate 			break;
1997*7c478bd9Sstevel@tonic-gate 
1998*7c478bd9Sstevel@tonic-gate 		default:
1999*7c478bd9Sstevel@tonic-gate 			break;
2000*7c478bd9Sstevel@tonic-gate 	}
2001*7c478bd9Sstevel@tonic-gate 
2002*7c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERR(ep) && SBD_GET_ERRNO(ep) == 0) {
2003*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(ep, EIO);
2004*7c478bd9Sstevel@tonic-gate 	}
2005*7c478bd9Sstevel@tonic-gate 
2006*7c478bd9Sstevel@tonic-gate 	if (shp->sh_arg != NULL) {
2007*7c478bd9Sstevel@tonic-gate 
2008*7c478bd9Sstevel@tonic-gate 		if (SBD_GET_ERR(ep) != ESBD_NOERROR) {
2009*7c478bd9Sstevel@tonic-gate 
2010*7c478bd9Sstevel@tonic-gate 			SBD_SET_IOCTL_ERR(&hp->h_iap->i_err,
2011*7c478bd9Sstevel@tonic-gate 				ep->e_code,
2012*7c478bd9Sstevel@tonic-gate 				ep->e_rsc);
2013*7c478bd9Sstevel@tonic-gate 
2014*7c478bd9Sstevel@tonic-gate 			(void) sbd_copyout_errs(hp->h_mode, hp->h_iap,
2015*7c478bd9Sstevel@tonic-gate 					shp->sh_arg);
2016*7c478bd9Sstevel@tonic-gate 		}
2017*7c478bd9Sstevel@tonic-gate 
2018*7c478bd9Sstevel@tonic-gate 		if (hp->h_iap != NULL) {
2019*7c478bd9Sstevel@tonic-gate 			FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1);
2020*7c478bd9Sstevel@tonic-gate 			hp->h_iap = NULL;
2021*7c478bd9Sstevel@tonic-gate 		}
2022*7c478bd9Sstevel@tonic-gate 	}
2023*7c478bd9Sstevel@tonic-gate }
2024*7c478bd9Sstevel@tonic-gate 
2025*7c478bd9Sstevel@tonic-gate static int
2026*7c478bd9Sstevel@tonic-gate sbd_probe_board(sbd_handle_t *hp)
2027*7c478bd9Sstevel@tonic-gate {
2028*7c478bd9Sstevel@tonic-gate 	int		rv;
2029*7c478bd9Sstevel@tonic-gate 	sbd_board_t    *sbp;
2030*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2031*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_probe_board";
2032*7c478bd9Sstevel@tonic-gate 
2033*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
2034*7c478bd9Sstevel@tonic-gate 
2035*7c478bd9Sstevel@tonic-gate 	ASSERT(sbp != NULL);
2036*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s for board %d", f, sbp->sb_num);
2037*7c478bd9Sstevel@tonic-gate 
2038*7c478bd9Sstevel@tonic-gate 
2039*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2040*7c478bd9Sstevel@tonic-gate 
2041*7c478bd9Sstevel@tonic-gate 	if ((rv = sbdp_connect_board(hdp)) != 0) {
2042*7c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
2043*7c478bd9Sstevel@tonic-gate 
2044*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
2045*7c478bd9Sstevel@tonic-gate 	}
2046*7c478bd9Sstevel@tonic-gate 
2047*7c478bd9Sstevel@tonic-gate 	/*
2048*7c478bd9Sstevel@tonic-gate 	 * We need to force a recache after the connect.  The cached
2049*7c478bd9Sstevel@tonic-gate 	 * info may be incorrect
2050*7c478bd9Sstevel@tonic-gate 	 */
2051*7c478bd9Sstevel@tonic-gate 	mutex_enter(&sbp->sb_flags_mutex);
2052*7c478bd9Sstevel@tonic-gate 	sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED;
2053*7c478bd9Sstevel@tonic-gate 	mutex_exit(&sbp->sb_flags_mutex);
2054*7c478bd9Sstevel@tonic-gate 
2055*7c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_PROBE_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2056*7c478bd9Sstevel@tonic-gate 		ESGT_PROBE, NULL);
2057*7c478bd9Sstevel@tonic-gate 
2058*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2059*7c478bd9Sstevel@tonic-gate 
2060*7c478bd9Sstevel@tonic-gate 	return (rv);
2061*7c478bd9Sstevel@tonic-gate }
2062*7c478bd9Sstevel@tonic-gate 
2063*7c478bd9Sstevel@tonic-gate static int
2064*7c478bd9Sstevel@tonic-gate sbd_deprobe_board(sbd_handle_t *hp)
2065*7c478bd9Sstevel@tonic-gate {
2066*7c478bd9Sstevel@tonic-gate 	int		rv;
2067*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2068*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
2069*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_deprobe_board";
2070*7c478bd9Sstevel@tonic-gate 
2071*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
2072*7c478bd9Sstevel@tonic-gate 
2073*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
2074*7c478bd9Sstevel@tonic-gate 
2075*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2076*7c478bd9Sstevel@tonic-gate 
2077*7c478bd9Sstevel@tonic-gate 	if ((rv = sbdp_disconnect_board(hdp)) != 0) {
2078*7c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
2079*7c478bd9Sstevel@tonic-gate 
2080*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
2081*7c478bd9Sstevel@tonic-gate 	}
2082*7c478bd9Sstevel@tonic-gate 
2083*7c478bd9Sstevel@tonic-gate 	mutex_enter(&sbp->sb_flags_mutex);
2084*7c478bd9Sstevel@tonic-gate 	sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED;
2085*7c478bd9Sstevel@tonic-gate 	mutex_exit(&sbp->sb_flags_mutex);
2086*7c478bd9Sstevel@tonic-gate 
2087*7c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_DEPROBE_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2088*7c478bd9Sstevel@tonic-gate 		ESGT_DEPROBE, NULL);
2089*7c478bd9Sstevel@tonic-gate 
2090*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2091*7c478bd9Sstevel@tonic-gate 	return (rv);
2092*7c478bd9Sstevel@tonic-gate }
2093*7c478bd9Sstevel@tonic-gate 
2094*7c478bd9Sstevel@tonic-gate /*
2095*7c478bd9Sstevel@tonic-gate  * Check if a CPU node is part of a CMP.
2096*7c478bd9Sstevel@tonic-gate  */
2097*7c478bd9Sstevel@tonic-gate int
2098*7c478bd9Sstevel@tonic-gate sbd_is_cmp_child(dev_info_t *dip)
2099*7c478bd9Sstevel@tonic-gate {
2100*7c478bd9Sstevel@tonic-gate 	dev_info_t *pdip;
2101*7c478bd9Sstevel@tonic-gate 
2102*7c478bd9Sstevel@tonic-gate 	if (strcmp(ddi_node_name(dip), "cpu") != 0) {
2103*7c478bd9Sstevel@tonic-gate 		return (0);
2104*7c478bd9Sstevel@tonic-gate 	}
2105*7c478bd9Sstevel@tonic-gate 
2106*7c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(dip);
2107*7c478bd9Sstevel@tonic-gate 
2108*7c478bd9Sstevel@tonic-gate 	ASSERT(pdip);
2109*7c478bd9Sstevel@tonic-gate 
2110*7c478bd9Sstevel@tonic-gate 	if (strcmp(ddi_node_name(pdip), "cmp") == 0) {
2111*7c478bd9Sstevel@tonic-gate 		return (1);
2112*7c478bd9Sstevel@tonic-gate 	}
2113*7c478bd9Sstevel@tonic-gate 
2114*7c478bd9Sstevel@tonic-gate 	return (0);
2115*7c478bd9Sstevel@tonic-gate }
2116*7c478bd9Sstevel@tonic-gate 
2117*7c478bd9Sstevel@tonic-gate /*
2118*7c478bd9Sstevel@tonic-gate  * Returns the nodetype if dip is a top dip on the board of
2119*7c478bd9Sstevel@tonic-gate  * interest or SBD_COMP_UNKNOWN otherwise
2120*7c478bd9Sstevel@tonic-gate  */
2121*7c478bd9Sstevel@tonic-gate static sbd_comp_type_t
2122*7c478bd9Sstevel@tonic-gate get_node_type(sbd_board_t *sbp, dev_info_t *dip, int *unitp)
2123*7c478bd9Sstevel@tonic-gate {
2124*7c478bd9Sstevel@tonic-gate 	int		idx, unit;
2125*7c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp;
2126*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2127*7c478bd9Sstevel@tonic-gate 	char		otype[OBP_MAXDRVNAME];
2128*7c478bd9Sstevel@tonic-gate 	int		otypelen;
2129*7c478bd9Sstevel@tonic-gate 
2130*7c478bd9Sstevel@tonic-gate 	ASSERT(sbp);
2131*7c478bd9Sstevel@tonic-gate 
2132*7c478bd9Sstevel@tonic-gate 	if (unitp)
2133*7c478bd9Sstevel@tonic-gate 		*unitp = -1;
2134*7c478bd9Sstevel@tonic-gate 
2135*7c478bd9Sstevel@tonic-gate 	hp = MACHBD2HD(sbp);
2136*7c478bd9Sstevel@tonic-gate 
2137*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2138*7c478bd9Sstevel@tonic-gate 	if (sbdp_get_board_num(hdp, dip) != sbp->sb_num) {
2139*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
2140*7c478bd9Sstevel@tonic-gate 		return (SBD_COMP_UNKNOWN);
2141*7c478bd9Sstevel@tonic-gate 	}
2142*7c478bd9Sstevel@tonic-gate 
2143*7c478bd9Sstevel@tonic-gate 	/*
2144*7c478bd9Sstevel@tonic-gate 	 * sbdp_get_unit_num will return (-1) for cmp as there
2145*7c478bd9Sstevel@tonic-gate 	 * is no "device_type" property associated with cmp.
2146*7c478bd9Sstevel@tonic-gate 	 * Therefore we will just skip getting unit number for
2147*7c478bd9Sstevel@tonic-gate 	 * cmp.  Callers of this function need to check the
2148*7c478bd9Sstevel@tonic-gate 	 * value set in unitp before using it to dereference
2149*7c478bd9Sstevel@tonic-gate 	 * an array.
2150*7c478bd9Sstevel@tonic-gate 	 */
2151*7c478bd9Sstevel@tonic-gate 	if (strcmp(ddi_node_name(dip), "cmp") == 0) {
2152*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
2153*7c478bd9Sstevel@tonic-gate 		return (SBD_COMP_CMP);
2154*7c478bd9Sstevel@tonic-gate 	}
2155*7c478bd9Sstevel@tonic-gate 
2156*7c478bd9Sstevel@tonic-gate 	otypelen = sizeof (otype);
2157*7c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2158*7c478bd9Sstevel@tonic-gate 	    OBP_DEVICETYPE,  (caddr_t)otype, &otypelen)) {
2159*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
2160*7c478bd9Sstevel@tonic-gate 		return (SBD_COMP_UNKNOWN);
2161*7c478bd9Sstevel@tonic-gate 	}
2162*7c478bd9Sstevel@tonic-gate 
2163*7c478bd9Sstevel@tonic-gate 	idx = sbd_otype_to_idx(otype);
2164*7c478bd9Sstevel@tonic-gate 
2165*7c478bd9Sstevel@tonic-gate 	if (SBD_COMP(idx) == SBD_COMP_UNKNOWN) {
2166*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
2167*7c478bd9Sstevel@tonic-gate 		return (SBD_COMP_UNKNOWN);
2168*7c478bd9Sstevel@tonic-gate 	}
2169*7c478bd9Sstevel@tonic-gate 
2170*7c478bd9Sstevel@tonic-gate 	unit = sbdp_get_unit_num(hdp, dip);
2171*7c478bd9Sstevel@tonic-gate 	if (unit == -1) {
2172*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
2173*7c478bd9Sstevel@tonic-gate 			"get_node_type: %s unit fail %p", otype, (void *)dip);
2174*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
2175*7c478bd9Sstevel@tonic-gate 		return (SBD_COMP_UNKNOWN);
2176*7c478bd9Sstevel@tonic-gate 	}
2177*7c478bd9Sstevel@tonic-gate 
2178*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2179*7c478bd9Sstevel@tonic-gate 
2180*7c478bd9Sstevel@tonic-gate 	if (unitp)
2181*7c478bd9Sstevel@tonic-gate 		*unitp = unit;
2182*7c478bd9Sstevel@tonic-gate 
2183*7c478bd9Sstevel@tonic-gate 	return (SBD_COMP(idx));
2184*7c478bd9Sstevel@tonic-gate }
2185*7c478bd9Sstevel@tonic-gate 
2186*7c478bd9Sstevel@tonic-gate typedef struct {
2187*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
2188*7c478bd9Sstevel@tonic-gate 	int		nmc;
2189*7c478bd9Sstevel@tonic-gate 	int		hold;
2190*7c478bd9Sstevel@tonic-gate } walk_tree_t;
2191*7c478bd9Sstevel@tonic-gate 
2192*7c478bd9Sstevel@tonic-gate static int
2193*7c478bd9Sstevel@tonic-gate sbd_setup_devlists(dev_info_t *dip, void *arg)
2194*7c478bd9Sstevel@tonic-gate {
2195*7c478bd9Sstevel@tonic-gate 	walk_tree_t	*wp;
2196*7c478bd9Sstevel@tonic-gate 	dev_info_t	**devlist = NULL;
2197*7c478bd9Sstevel@tonic-gate 	char		*pathname = NULL;
2198*7c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
2199*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_setup_devlists";
2200*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
2201*7c478bd9Sstevel@tonic-gate 	int		unit;
2202*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t nodetype;
2203*7c478bd9Sstevel@tonic-gate 
2204*7c478bd9Sstevel@tonic-gate 	ASSERT(dip);
2205*7c478bd9Sstevel@tonic-gate 
2206*7c478bd9Sstevel@tonic-gate 	wp = (walk_tree_t *)arg;
2207*7c478bd9Sstevel@tonic-gate 
2208*7c478bd9Sstevel@tonic-gate 	if (wp == NULL) {
2209*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s:bad arg\n", f);
2210*7c478bd9Sstevel@tonic-gate 		return (DDI_WALK_TERMINATE);
2211*7c478bd9Sstevel@tonic-gate 	}
2212*7c478bd9Sstevel@tonic-gate 
2213*7c478bd9Sstevel@tonic-gate 	sbp = wp->sbp;
2214*7c478bd9Sstevel@tonic-gate 
2215*7c478bd9Sstevel@tonic-gate 	nodetype = get_node_type(sbp, dip, &unit);
2216*7c478bd9Sstevel@tonic-gate 
2217*7c478bd9Sstevel@tonic-gate 	switch (nodetype) {
2218*7c478bd9Sstevel@tonic-gate 
2219*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
2220*7c478bd9Sstevel@tonic-gate 		pathname = sbp->sb_cpupath[unit];
2221*7c478bd9Sstevel@tonic-gate 		break;
2222*7c478bd9Sstevel@tonic-gate 
2223*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
2224*7c478bd9Sstevel@tonic-gate 		pathname = sbp->sb_mempath[unit];
2225*7c478bd9Sstevel@tonic-gate 		break;
2226*7c478bd9Sstevel@tonic-gate 
2227*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
2228*7c478bd9Sstevel@tonic-gate 		pathname = sbp->sb_iopath[unit];
2229*7c478bd9Sstevel@tonic-gate 		break;
2230*7c478bd9Sstevel@tonic-gate 
2231*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_CMP:
2232*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_UNKNOWN:
2233*7c478bd9Sstevel@tonic-gate 		/*
2234*7c478bd9Sstevel@tonic-gate 		 * This dip is not of interest to us
2235*7c478bd9Sstevel@tonic-gate 		 */
2236*7c478bd9Sstevel@tonic-gate 		return (DDI_WALK_CONTINUE);
2237*7c478bd9Sstevel@tonic-gate 
2238*7c478bd9Sstevel@tonic-gate 	default:
2239*7c478bd9Sstevel@tonic-gate 		ASSERT(0);
2240*7c478bd9Sstevel@tonic-gate 		return (DDI_WALK_CONTINUE);
2241*7c478bd9Sstevel@tonic-gate 	}
2242*7c478bd9Sstevel@tonic-gate 
2243*7c478bd9Sstevel@tonic-gate 	/*
2244*7c478bd9Sstevel@tonic-gate 	 * dip's parent is being held busy by ddi_walk_devs(),
2245*7c478bd9Sstevel@tonic-gate 	 * so dip doesn't have to be held while calling ddi_pathname()
2246*7c478bd9Sstevel@tonic-gate 	 */
2247*7c478bd9Sstevel@tonic-gate 	if (pathname) {
2248*7c478bd9Sstevel@tonic-gate 		(void) ddi_pathname(dip, pathname);
2249*7c478bd9Sstevel@tonic-gate 	}
2250*7c478bd9Sstevel@tonic-gate 
2251*7c478bd9Sstevel@tonic-gate 	devlist = sbp->sb_devlist[NIX(nodetype)];
2252*7c478bd9Sstevel@tonic-gate 
2253*7c478bd9Sstevel@tonic-gate 	/*
2254*7c478bd9Sstevel@tonic-gate 	 * The branch rooted at dip should already be held,
2255*7c478bd9Sstevel@tonic-gate 	 * unless we are dealing with a core of a CMP.
2256*7c478bd9Sstevel@tonic-gate 	 */
2257*7c478bd9Sstevel@tonic-gate 	ASSERT(sbd_is_cmp_child(dip) || e_ddi_branch_held(dip));
2258*7c478bd9Sstevel@tonic-gate 	devlist[unit] = dip;
2259*7c478bd9Sstevel@tonic-gate 
2260*7c478bd9Sstevel@tonic-gate 	/*
2261*7c478bd9Sstevel@tonic-gate 	 * This test is required if multiple devices are considered
2262*7c478bd9Sstevel@tonic-gate 	 * as one. This is the case for memory-controller nodes.
2263*7c478bd9Sstevel@tonic-gate 	 */
2264*7c478bd9Sstevel@tonic-gate 	if (!SBD_DEV_IS_PRESENT(sbp, nodetype, unit)) {
2265*7c478bd9Sstevel@tonic-gate 		sbp->sb_ndev++;
2266*7c478bd9Sstevel@tonic-gate 		SBD_DEV_SET_PRESENT(sbp, nodetype, unit);
2267*7c478bd9Sstevel@tonic-gate 	}
2268*7c478bd9Sstevel@tonic-gate 
2269*7c478bd9Sstevel@tonic-gate 	if (nodetype == SBD_COMP_MEM) {
2270*7c478bd9Sstevel@tonic-gate 		mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
2271*7c478bd9Sstevel@tonic-gate 		ASSERT(wp->nmc < SBD_NUM_MC_PER_BOARD);
2272*7c478bd9Sstevel@tonic-gate 		mp->sbm_dip[wp->nmc++] = dip;
2273*7c478bd9Sstevel@tonic-gate 	}
2274*7c478bd9Sstevel@tonic-gate 
2275*7c478bd9Sstevel@tonic-gate 	return (DDI_WALK_CONTINUE);
2276*7c478bd9Sstevel@tonic-gate }
2277*7c478bd9Sstevel@tonic-gate 
2278*7c478bd9Sstevel@tonic-gate /*
2279*7c478bd9Sstevel@tonic-gate  * This routine is used to construct the memory devlist.
2280*7c478bd9Sstevel@tonic-gate  * In Starcat and Serengeti platforms, a system board can contain up to
2281*7c478bd9Sstevel@tonic-gate  * four memory controllers (MC).  The MCs have been programmed by POST for
2282*7c478bd9Sstevel@tonic-gate  * optimum memory interleaving amongst their peers on the same board.
2283*7c478bd9Sstevel@tonic-gate  * This DR driver does not support deinterleaving.  Therefore, the smallest
2284*7c478bd9Sstevel@tonic-gate  * unit of memory that can be manipulated by this driver is all of the
2285*7c478bd9Sstevel@tonic-gate  * memory on a board.  Because of this restriction, a board's memory devlist
2286*7c478bd9Sstevel@tonic-gate  * is populated with only one of the four (possible) MC dnodes on that board.
2287*7c478bd9Sstevel@tonic-gate  * Care must be taken to ensure that the selected MC dnode represents the
2288*7c478bd9Sstevel@tonic-gate  * lowest physical address to which memory on the board will respond to.
2289*7c478bd9Sstevel@tonic-gate  * This is required in order to preserve the semantics of
2290*7c478bd9Sstevel@tonic-gate  * sbdp_get_base_physaddr() when applied to a MC dnode stored in the
2291*7c478bd9Sstevel@tonic-gate  * memory devlist.
2292*7c478bd9Sstevel@tonic-gate  */
2293*7c478bd9Sstevel@tonic-gate static void
2294*7c478bd9Sstevel@tonic-gate sbd_init_mem_devlists(sbd_board_t *sbp)
2295*7c478bd9Sstevel@tonic-gate {
2296*7c478bd9Sstevel@tonic-gate 	dev_info_t	**devlist;
2297*7c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
2298*7c478bd9Sstevel@tonic-gate 	dev_info_t	*mc_dip;
2299*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2300*7c478bd9Sstevel@tonic-gate 	uint64_t	mc_pa, lowest_pa;
2301*7c478bd9Sstevel@tonic-gate 	int		i;
2302*7c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp = MACHBD2HD(sbp);
2303*7c478bd9Sstevel@tonic-gate 
2304*7c478bd9Sstevel@tonic-gate 	devlist = sbp->sb_devlist[NIX(SBD_COMP_MEM)];
2305*7c478bd9Sstevel@tonic-gate 
2306*7c478bd9Sstevel@tonic-gate 	mp = SBD_GET_BOARD_MEMUNIT(sbp, 0);
2307*7c478bd9Sstevel@tonic-gate 
2308*7c478bd9Sstevel@tonic-gate 	mc_dip = mp->sbm_dip[0];
2309*7c478bd9Sstevel@tonic-gate 	if (mc_dip == NULL)
2310*7c478bd9Sstevel@tonic-gate 		return;		/* No MC dips found for this board */
2311*7c478bd9Sstevel@tonic-gate 
2312*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2313*7c478bd9Sstevel@tonic-gate 
2314*7c478bd9Sstevel@tonic-gate 	if (sbdphw_get_base_physaddr(hdp, mc_dip, &mc_pa)) {
2315*7c478bd9Sstevel@tonic-gate 		/* TODO: log complaint about dnode */
2316*7c478bd9Sstevel@tonic-gate 
2317*7c478bd9Sstevel@tonic-gate pretend_no_mem:
2318*7c478bd9Sstevel@tonic-gate 		/*
2319*7c478bd9Sstevel@tonic-gate 		 * We are here because sbdphw_get_base_physaddr() failed.
2320*7c478bd9Sstevel@tonic-gate 		 * Although it is very unlikely to happen, it did.  Lucky us.
2321*7c478bd9Sstevel@tonic-gate 		 * Since we can no longer examine _all_ of the MCs on this
2322*7c478bd9Sstevel@tonic-gate 		 * board to determine which one is programmed to the lowest
2323*7c478bd9Sstevel@tonic-gate 		 * physical address, we cannot involve any of the MCs on
2324*7c478bd9Sstevel@tonic-gate 		 * this board in DR operations.  To ensure this, we pretend
2325*7c478bd9Sstevel@tonic-gate 		 * that this board does not contain any memory.
2326*7c478bd9Sstevel@tonic-gate 		 *
2327*7c478bd9Sstevel@tonic-gate 		 * Paranoia: clear the dev_present mask.
2328*7c478bd9Sstevel@tonic-gate 		 */
2329*7c478bd9Sstevel@tonic-gate 		if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, 0)) {
2330*7c478bd9Sstevel@tonic-gate 			ASSERT(sbp->sb_ndev != 0);
2331*7c478bd9Sstevel@tonic-gate 			SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, 0);
2332*7c478bd9Sstevel@tonic-gate 			sbp->sb_ndev--;
2333*7c478bd9Sstevel@tonic-gate 		}
2334*7c478bd9Sstevel@tonic-gate 
2335*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
2336*7c478bd9Sstevel@tonic-gate 			mp->sbm_dip[i] = NULL;
2337*7c478bd9Sstevel@tonic-gate 		}
2338*7c478bd9Sstevel@tonic-gate 
2339*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
2340*7c478bd9Sstevel@tonic-gate 		return;
2341*7c478bd9Sstevel@tonic-gate 	}
2342*7c478bd9Sstevel@tonic-gate 
2343*7c478bd9Sstevel@tonic-gate 	/* assume this one will win. */
2344*7c478bd9Sstevel@tonic-gate 	devlist[0] = mc_dip;
2345*7c478bd9Sstevel@tonic-gate 	mp->sbm_cm.sbdev_dip = mc_dip;
2346*7c478bd9Sstevel@tonic-gate 	lowest_pa = mc_pa;
2347*7c478bd9Sstevel@tonic-gate 
2348*7c478bd9Sstevel@tonic-gate 	/*
2349*7c478bd9Sstevel@tonic-gate 	 * We know the base physical address of one of the MC devices.  Now
2350*7c478bd9Sstevel@tonic-gate 	 * we will enumerate through all of the remaining MC devices on
2351*7c478bd9Sstevel@tonic-gate 	 * the board to find which of them is programmed to the lowest
2352*7c478bd9Sstevel@tonic-gate 	 * physical address.
2353*7c478bd9Sstevel@tonic-gate 	 */
2354*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < SBD_NUM_MC_PER_BOARD; i++) {
2355*7c478bd9Sstevel@tonic-gate 		mc_dip = mp->sbm_dip[i];
2356*7c478bd9Sstevel@tonic-gate 		if (mc_dip == NULL) {
2357*7c478bd9Sstevel@tonic-gate 			break;
2358*7c478bd9Sstevel@tonic-gate 		}
2359*7c478bd9Sstevel@tonic-gate 
2360*7c478bd9Sstevel@tonic-gate 		if (sbdphw_get_base_physaddr(hdp, mc_dip, &mc_pa)) {
2361*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "No mem on board %d unit %d",
2362*7c478bd9Sstevel@tonic-gate 				sbp->sb_num, i);
2363*7c478bd9Sstevel@tonic-gate 			break;
2364*7c478bd9Sstevel@tonic-gate 		}
2365*7c478bd9Sstevel@tonic-gate 		if (mc_pa < lowest_pa) {
2366*7c478bd9Sstevel@tonic-gate 			mp->sbm_cm.sbdev_dip = mc_dip;
2367*7c478bd9Sstevel@tonic-gate 			devlist[0] = mc_dip;
2368*7c478bd9Sstevel@tonic-gate 			lowest_pa = mc_pa;
2369*7c478bd9Sstevel@tonic-gate 		}
2370*7c478bd9Sstevel@tonic-gate 	}
2371*7c478bd9Sstevel@tonic-gate 
2372*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2373*7c478bd9Sstevel@tonic-gate }
2374*7c478bd9Sstevel@tonic-gate 
2375*7c478bd9Sstevel@tonic-gate static int
2376*7c478bd9Sstevel@tonic-gate sbd_name_to_idx(char *name)
2377*7c478bd9Sstevel@tonic-gate {
2378*7c478bd9Sstevel@tonic-gate 	int idx;
2379*7c478bd9Sstevel@tonic-gate 
2380*7c478bd9Sstevel@tonic-gate 	for (idx = 0; SBD_COMP(idx) != SBD_COMP_UNKNOWN; idx++) {
2381*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, SBD_DEVNAME(idx)) == 0) {
2382*7c478bd9Sstevel@tonic-gate 			break;
2383*7c478bd9Sstevel@tonic-gate 		}
2384*7c478bd9Sstevel@tonic-gate 	}
2385*7c478bd9Sstevel@tonic-gate 
2386*7c478bd9Sstevel@tonic-gate 	return (idx);
2387*7c478bd9Sstevel@tonic-gate }
2388*7c478bd9Sstevel@tonic-gate 
2389*7c478bd9Sstevel@tonic-gate static int
2390*7c478bd9Sstevel@tonic-gate sbd_otype_to_idx(char *otype)
2391*7c478bd9Sstevel@tonic-gate {
2392*7c478bd9Sstevel@tonic-gate 	int idx;
2393*7c478bd9Sstevel@tonic-gate 
2394*7c478bd9Sstevel@tonic-gate 	for (idx = 0; SBD_COMP(idx) != SBD_COMP_UNKNOWN; idx++) {
2395*7c478bd9Sstevel@tonic-gate 
2396*7c478bd9Sstevel@tonic-gate 		if (strcmp(otype, SBD_OTYPE(idx)) == 0) {
2397*7c478bd9Sstevel@tonic-gate 			break;
2398*7c478bd9Sstevel@tonic-gate 		}
2399*7c478bd9Sstevel@tonic-gate 	}
2400*7c478bd9Sstevel@tonic-gate 
2401*7c478bd9Sstevel@tonic-gate 	return (idx);
2402*7c478bd9Sstevel@tonic-gate }
2403*7c478bd9Sstevel@tonic-gate 
2404*7c478bd9Sstevel@tonic-gate static int
2405*7c478bd9Sstevel@tonic-gate sbd_init_devlists(sbd_board_t *sbp)
2406*7c478bd9Sstevel@tonic-gate {
2407*7c478bd9Sstevel@tonic-gate 	int		i;
2408*7c478bd9Sstevel@tonic-gate 	sbd_dev_unit_t	*dp;
2409*7c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
2410*7c478bd9Sstevel@tonic-gate 	walk_tree_t	*wp, walk = {0};
2411*7c478bd9Sstevel@tonic-gate 	dev_info_t	*pdip;
2412*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_init_devlists";
2413*7c478bd9Sstevel@tonic-gate 
2414*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s (board = %d)...\n", f, sbp->sb_num);
2415*7c478bd9Sstevel@tonic-gate 
2416*7c478bd9Sstevel@tonic-gate 	wp = &walk;
2417*7c478bd9Sstevel@tonic-gate 
2418*7c478bd9Sstevel@tonic-gate 	SBD_DEVS_DISCONNECT(sbp, (uint_t)-1);
2419*7c478bd9Sstevel@tonic-gate 
2420*7c478bd9Sstevel@tonic-gate 	/*
2421*7c478bd9Sstevel@tonic-gate 	 * Clear out old entries, if any.
2422*7c478bd9Sstevel@tonic-gate 	 */
2423*7c478bd9Sstevel@tonic-gate 
2424*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
2425*7c478bd9Sstevel@tonic-gate 		sbp->sb_devlist[NIX(SBD_COMP_MEM)][i] = NULL;
2426*7c478bd9Sstevel@tonic-gate 		dp = (sbd_dev_unit_t *)SBD_GET_BOARD_MEMUNIT(sbp, i);
2427*7c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_sbp = sbp;
2428*7c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_unum = i;
2429*7c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_type = SBD_COMP_MEM;
2430*7c478bd9Sstevel@tonic-gate 	}
2431*7c478bd9Sstevel@tonic-gate 
2432*7c478bd9Sstevel@tonic-gate 	mp = SBD_GET_BOARD_MEMUNIT(sbp, 0);
2433*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
2434*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
2435*7c478bd9Sstevel@tonic-gate 		mp->sbm_dip[i] = NULL;
2436*7c478bd9Sstevel@tonic-gate 	}
2437*7c478bd9Sstevel@tonic-gate 
2438*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
2439*7c478bd9Sstevel@tonic-gate 		sbp->sb_devlist[NIX(SBD_COMP_CPU)][i] = NULL;
2440*7c478bd9Sstevel@tonic-gate 		dp = (sbd_dev_unit_t *)SBD_GET_BOARD_CPUUNIT(sbp, i);
2441*7c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_sbp = sbp;
2442*7c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_unum = i;
2443*7c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_type = SBD_COMP_CPU;
2444*7c478bd9Sstevel@tonic-gate 	}
2445*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
2446*7c478bd9Sstevel@tonic-gate 		sbp->sb_devlist[NIX(SBD_COMP_IO)][i] = NULL;
2447*7c478bd9Sstevel@tonic-gate 		dp = (sbd_dev_unit_t *)SBD_GET_BOARD_IOUNIT(sbp, i);
2448*7c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_sbp = sbp;
2449*7c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_unum = i;
2450*7c478bd9Sstevel@tonic-gate 		dp->u_common.sbdev_type = SBD_COMP_IO;
2451*7c478bd9Sstevel@tonic-gate 	}
2452*7c478bd9Sstevel@tonic-gate 
2453*7c478bd9Sstevel@tonic-gate 	wp->sbp = sbp;
2454*7c478bd9Sstevel@tonic-gate 	wp->nmc = 0;
2455*7c478bd9Sstevel@tonic-gate 	sbp->sb_ndev = 0;
2456*7c478bd9Sstevel@tonic-gate 
2457*7c478bd9Sstevel@tonic-gate 	/*
2458*7c478bd9Sstevel@tonic-gate 	 * ddi_walk_devs() requires that topdip's parent be held.
2459*7c478bd9Sstevel@tonic-gate 	 */
2460*7c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(sbp->sb_topdip);
2461*7c478bd9Sstevel@tonic-gate 	if (pdip) {
2462*7c478bd9Sstevel@tonic-gate 		ndi_hold_devi(pdip);
2463*7c478bd9Sstevel@tonic-gate 		ndi_devi_enter(pdip, &i);
2464*7c478bd9Sstevel@tonic-gate 	}
2465*7c478bd9Sstevel@tonic-gate 	ddi_walk_devs(sbp->sb_topdip, sbd_setup_devlists, (void *) wp);
2466*7c478bd9Sstevel@tonic-gate 	if (pdip) {
2467*7c478bd9Sstevel@tonic-gate 		ndi_devi_exit(pdip, i);
2468*7c478bd9Sstevel@tonic-gate 		ndi_rele_devi(pdip);
2469*7c478bd9Sstevel@tonic-gate 	}
2470*7c478bd9Sstevel@tonic-gate 
2471*7c478bd9Sstevel@tonic-gate 	/*
2472*7c478bd9Sstevel@tonic-gate 	 * There is no point checking all the components if there
2473*7c478bd9Sstevel@tonic-gate 	 * are no devices.
2474*7c478bd9Sstevel@tonic-gate 	 */
2475*7c478bd9Sstevel@tonic-gate 	if (sbp->sb_ndev == 0) {
2476*7c478bd9Sstevel@tonic-gate 		sbp->sb_memaccess_ok = 0;
2477*7c478bd9Sstevel@tonic-gate 		return (sbp->sb_ndev);
2478*7c478bd9Sstevel@tonic-gate 	}
2479*7c478bd9Sstevel@tonic-gate 
2480*7c478bd9Sstevel@tonic-gate 	/*
2481*7c478bd9Sstevel@tonic-gate 	 * Initialize cpu sections before calling sbd_init_mem_devlists
2482*7c478bd9Sstevel@tonic-gate 	 * which will access the mmus.
2483*7c478bd9Sstevel@tonic-gate 	 */
2484*7c478bd9Sstevel@tonic-gate 	sbp->sb_memaccess_ok = 1;
2485*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
2486*7c478bd9Sstevel@tonic-gate 		if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i)) {
2487*7c478bd9Sstevel@tonic-gate 			sbd_init_cpu_unit(sbp, i);
2488*7c478bd9Sstevel@tonic-gate 			if (sbd_connect_cpu(sbp, i)) {
2489*7c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(HD2MACHERR(MACHBD2HD(sbp)),
2490*7c478bd9Sstevel@tonic-gate 					ESBD_CPUSTART);
2491*7c478bd9Sstevel@tonic-gate 			}
2492*7c478bd9Sstevel@tonic-gate 
2493*7c478bd9Sstevel@tonic-gate 		}
2494*7c478bd9Sstevel@tonic-gate 	}
2495*7c478bd9Sstevel@tonic-gate 
2496*7c478bd9Sstevel@tonic-gate 	if (sbp->sb_memaccess_ok) {
2497*7c478bd9Sstevel@tonic-gate 		sbd_init_mem_devlists(sbp);
2498*7c478bd9Sstevel@tonic-gate 	} else {
2499*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "unable to access memory on board %d",
2500*7c478bd9Sstevel@tonic-gate 		    sbp->sb_num);
2501*7c478bd9Sstevel@tonic-gate 	}
2502*7c478bd9Sstevel@tonic-gate 
2503*7c478bd9Sstevel@tonic-gate 	return (sbp->sb_ndev);
2504*7c478bd9Sstevel@tonic-gate }
2505*7c478bd9Sstevel@tonic-gate 
2506*7c478bd9Sstevel@tonic-gate static void
2507*7c478bd9Sstevel@tonic-gate sbd_init_cpu_unit(sbd_board_t *sbp, int unit)
2508*7c478bd9Sstevel@tonic-gate {
2509*7c478bd9Sstevel@tonic-gate 	sbd_istate_t	new_state;
2510*7c478bd9Sstevel@tonic-gate 	sbd_cpu_unit_t	*cp;
2511*7c478bd9Sstevel@tonic-gate 	int		cpuid;
2512*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
2513*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2514*7c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp = MACHBD2HD(sbp);
2515*7c478bd9Sstevel@tonic-gate 	extern kmutex_t	cpu_lock;
2516*7c478bd9Sstevel@tonic-gate 
2517*7c478bd9Sstevel@tonic-gate 	if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_CPU, unit)) {
2518*7c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_CONFIGURED;
2519*7c478bd9Sstevel@tonic-gate 	} else if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, unit)) {
2520*7c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_CONNECTED;
2521*7c478bd9Sstevel@tonic-gate 	} else {
2522*7c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_EMPTY;
2523*7c478bd9Sstevel@tonic-gate 	}
2524*7c478bd9Sstevel@tonic-gate 
2525*7c478bd9Sstevel@tonic-gate 	dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][unit];
2526*7c478bd9Sstevel@tonic-gate 
2527*7c478bd9Sstevel@tonic-gate 	cp = SBD_GET_BOARD_CPUUNIT(sbp, unit);
2528*7c478bd9Sstevel@tonic-gate 
2529*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2530*7c478bd9Sstevel@tonic-gate 
2531*7c478bd9Sstevel@tonic-gate 	cpuid = sbdp_get_cpuid(hdp, dip);
2532*7c478bd9Sstevel@tonic-gate 
2533*7c478bd9Sstevel@tonic-gate 	cp->sbc_cpu_id = cpuid;
2534*7c478bd9Sstevel@tonic-gate 
2535*7c478bd9Sstevel@tonic-gate 	if (&sbdp_cpu_get_impl)
2536*7c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_impl = sbdp_cpu_get_impl(hdp, dip);
2537*7c478bd9Sstevel@tonic-gate 	else
2538*7c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_impl = -1;
2539*7c478bd9Sstevel@tonic-gate 
2540*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
2541*7c478bd9Sstevel@tonic-gate 	if ((cpuid >= 0) && cpu[cpuid])
2542*7c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_flags = cpu[cpuid]->cpu_flags;
2543*7c478bd9Sstevel@tonic-gate 	else
2544*7c478bd9Sstevel@tonic-gate 		cp->sbc_cpu_flags = CPU_OFFLINE | CPU_POWEROFF;
2545*7c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
2546*7c478bd9Sstevel@tonic-gate 
2547*7c478bd9Sstevel@tonic-gate 	sbd_cpu_set_prop(cp, dip);
2548*7c478bd9Sstevel@tonic-gate 
2549*7c478bd9Sstevel@tonic-gate 	cp->sbc_cm.sbdev_cond = sbd_get_comp_cond(dip);
2550*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2551*7c478bd9Sstevel@tonic-gate 
2552*7c478bd9Sstevel@tonic-gate 	/*
2553*7c478bd9Sstevel@tonic-gate 	 * Any changes to the cpu should be performed above
2554*7c478bd9Sstevel@tonic-gate 	 * this call to ensure the cpu is fully initialized
2555*7c478bd9Sstevel@tonic-gate 	 * before transitioning to the new state.
2556*7c478bd9Sstevel@tonic-gate 	 */
2557*7c478bd9Sstevel@tonic-gate 	SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, unit, new_state);
2558*7c478bd9Sstevel@tonic-gate }
2559*7c478bd9Sstevel@tonic-gate 
2560*7c478bd9Sstevel@tonic-gate /*
2561*7c478bd9Sstevel@tonic-gate  * Only do work if called to operate on an entire board
2562*7c478bd9Sstevel@tonic-gate  * which doesn't already have components present.
2563*7c478bd9Sstevel@tonic-gate  */
2564*7c478bd9Sstevel@tonic-gate static void
2565*7c478bd9Sstevel@tonic-gate sbd_connect(sbd_handle_t *hp)
2566*7c478bd9Sstevel@tonic-gate {
2567*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
2568*7c478bd9Sstevel@tonic-gate 	sbderror_t	*ep;
2569*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_connect";
2570*7c478bd9Sstevel@tonic-gate 
2571*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
2572*7c478bd9Sstevel@tonic-gate 
2573*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s board %d\n", f, sbp->sb_num);
2574*7c478bd9Sstevel@tonic-gate 
2575*7c478bd9Sstevel@tonic-gate 	ep = HD2MACHERR(hp);
2576*7c478bd9Sstevel@tonic-gate 
2577*7c478bd9Sstevel@tonic-gate 	if (SBD_DEVS_PRESENT(sbp)) {
2578*7c478bd9Sstevel@tonic-gate 		/*
2579*7c478bd9Sstevel@tonic-gate 		 * Board already has devices present.
2580*7c478bd9Sstevel@tonic-gate 		 */
2581*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s: devices already present (0x%x)\n",
2582*7c478bd9Sstevel@tonic-gate 			f, SBD_DEVS_PRESENT(sbp));
2583*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(ep, EINVAL);
2584*7c478bd9Sstevel@tonic-gate 		return;
2585*7c478bd9Sstevel@tonic-gate 	}
2586*7c478bd9Sstevel@tonic-gate 
2587*7c478bd9Sstevel@tonic-gate 	if (sbd_init_devlists(sbp) == 0) {
2588*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: no devices present on board %d",
2589*7c478bd9Sstevel@tonic-gate 			f, sbp->sb_num);
2590*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_NODEV);
2591*7c478bd9Sstevel@tonic-gate 		return;
2592*7c478bd9Sstevel@tonic-gate 	} else {
2593*7c478bd9Sstevel@tonic-gate 		int	i;
2594*7c478bd9Sstevel@tonic-gate 
2595*7c478bd9Sstevel@tonic-gate 		/*
2596*7c478bd9Sstevel@tonic-gate 		 * Initialize mem-unit section of board structure.
2597*7c478bd9Sstevel@tonic-gate 		 */
2598*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++)
2599*7c478bd9Sstevel@tonic-gate 			if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i))
2600*7c478bd9Sstevel@tonic-gate 				sbd_init_mem_unit(sbp, i, SBD_HD2ERR(hp));
2601*7c478bd9Sstevel@tonic-gate 
2602*7c478bd9Sstevel@tonic-gate 		/*
2603*7c478bd9Sstevel@tonic-gate 		 * Initialize sb_io sections.
2604*7c478bd9Sstevel@tonic-gate 		 */
2605*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++)
2606*7c478bd9Sstevel@tonic-gate 			if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_IO, i))
2607*7c478bd9Sstevel@tonic-gate 				sbd_init_io_unit(sbp, i);
2608*7c478bd9Sstevel@tonic-gate 
2609*7c478bd9Sstevel@tonic-gate 		SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONNECTED);
2610*7c478bd9Sstevel@tonic-gate 		sbp->sb_rstate = SBD_STAT_CONNECTED;
2611*7c478bd9Sstevel@tonic-gate 		sbp->sb_ostate = SBD_STAT_UNCONFIGURED;
2612*7c478bd9Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&sbp->sb_time);
2613*7c478bd9Sstevel@tonic-gate 		SBD_INJECT_ERR(SBD_CONNECT_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2614*7c478bd9Sstevel@tonic-gate 			ESBD_INTERNAL, NULL);
2615*7c478bd9Sstevel@tonic-gate 	}
2616*7c478bd9Sstevel@tonic-gate }
2617*7c478bd9Sstevel@tonic-gate 
2618*7c478bd9Sstevel@tonic-gate static int
2619*7c478bd9Sstevel@tonic-gate sbd_disconnect(sbd_handle_t *hp)
2620*7c478bd9Sstevel@tonic-gate {
2621*7c478bd9Sstevel@tonic-gate 	int		i;
2622*7c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
2623*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
2624*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_disconnect it";
2625*7c478bd9Sstevel@tonic-gate 
2626*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s ...\n", f);
2627*7c478bd9Sstevel@tonic-gate 
2628*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
2629*7c478bd9Sstevel@tonic-gate 
2630*7c478bd9Sstevel@tonic-gate 	/*
2631*7c478bd9Sstevel@tonic-gate 	 * Only devices which are present, but
2632*7c478bd9Sstevel@tonic-gate 	 * unattached can be disconnected.
2633*7c478bd9Sstevel@tonic-gate 	 */
2634*7c478bd9Sstevel@tonic-gate 	devset = HD2MACHHD(hp)->sh_devset & SBD_DEVS_PRESENT(sbp) &
2635*7c478bd9Sstevel@tonic-gate 			SBD_DEVS_UNATTACHED(sbp);
2636*7c478bd9Sstevel@tonic-gate 
2637*7c478bd9Sstevel@tonic-gate 	ASSERT((SBD_DEVS_ATTACHED(sbp) & devset) == 0);
2638*7c478bd9Sstevel@tonic-gate 
2639*7c478bd9Sstevel@tonic-gate 	/*
2640*7c478bd9Sstevel@tonic-gate 	 * Update per-device state transitions.
2641*7c478bd9Sstevel@tonic-gate 	 */
2642*7c478bd9Sstevel@tonic-gate 
2643*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++)
2644*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) {
2645*7c478bd9Sstevel@tonic-gate 			if (sbd_disconnect_mem(hp, i) == 0) {
2646*7c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i,
2647*7c478bd9Sstevel@tonic-gate 							SBD_STATE_EMPTY);
2648*7c478bd9Sstevel@tonic-gate 				SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, i);
2649*7c478bd9Sstevel@tonic-gate 			}
2650*7c478bd9Sstevel@tonic-gate 		}
2651*7c478bd9Sstevel@tonic-gate 
2652*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++)
2653*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_CPU, i)) {
2654*7c478bd9Sstevel@tonic-gate 			if (sbd_disconnect_cpu(hp, i) == 0) {
2655*7c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i,
2656*7c478bd9Sstevel@tonic-gate 							SBD_STATE_EMPTY);
2657*7c478bd9Sstevel@tonic-gate 				SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_CPU, i);
2658*7c478bd9Sstevel@tonic-gate 			}
2659*7c478bd9Sstevel@tonic-gate 		}
2660*7c478bd9Sstevel@tonic-gate 
2661*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++)
2662*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_IO, i)) {
2663*7c478bd9Sstevel@tonic-gate 			if (sbd_disconnect_io(hp, i) == 0) {
2664*7c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, i,
2665*7c478bd9Sstevel@tonic-gate 							SBD_STATE_EMPTY);
2666*7c478bd9Sstevel@tonic-gate 				SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_IO, i);
2667*7c478bd9Sstevel@tonic-gate 			}
2668*7c478bd9Sstevel@tonic-gate 		}
2669*7c478bd9Sstevel@tonic-gate 
2670*7c478bd9Sstevel@tonic-gate 	/*
2671*7c478bd9Sstevel@tonic-gate 	 * Once all the components on a board have been disconnect
2672*7c478bd9Sstevel@tonic-gate 	 * the board's state can transition to disconnected and
2673*7c478bd9Sstevel@tonic-gate 	 * we can allow the deprobe to take place.
2674*7c478bd9Sstevel@tonic-gate 	 */
2675*7c478bd9Sstevel@tonic-gate 	if (SBD_DEVS_PRESENT(sbp) == 0) {
2676*7c478bd9Sstevel@tonic-gate 		SBD_BOARD_TRANSITION(sbp, SBD_STATE_OCCUPIED);
2677*7c478bd9Sstevel@tonic-gate 		sbp->sb_rstate = SBD_STAT_DISCONNECTED;
2678*7c478bd9Sstevel@tonic-gate 		sbp->sb_ostate = SBD_STAT_UNCONFIGURED;
2679*7c478bd9Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&sbp->sb_time);
2680*7c478bd9Sstevel@tonic-gate 		SBD_INJECT_ERR(SBD_DISCONNECT_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2681*7c478bd9Sstevel@tonic-gate 			ESBD_INTERNAL, NULL);
2682*7c478bd9Sstevel@tonic-gate 		return (0);
2683*7c478bd9Sstevel@tonic-gate 	} else {
2684*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: could not disconnect devices on board %d",
2685*7c478bd9Sstevel@tonic-gate 			f, sbp->sb_num);
2686*7c478bd9Sstevel@tonic-gate 		return (-1);
2687*7c478bd9Sstevel@tonic-gate 	}
2688*7c478bd9Sstevel@tonic-gate }
2689*7c478bd9Sstevel@tonic-gate 
2690*7c478bd9Sstevel@tonic-gate static void
2691*7c478bd9Sstevel@tonic-gate sbd_test_board(sbd_handle_t *hp)
2692*7c478bd9Sstevel@tonic-gate {
2693*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
2694*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2695*7c478bd9Sstevel@tonic-gate 
2696*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
2697*7c478bd9Sstevel@tonic-gate 
2698*7c478bd9Sstevel@tonic-gate 	PR_ALL("sbd_test_board: board %d\n", sbp->sb_num);
2699*7c478bd9Sstevel@tonic-gate 
2700*7c478bd9Sstevel@tonic-gate 
2701*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2702*7c478bd9Sstevel@tonic-gate 
2703*7c478bd9Sstevel@tonic-gate 	if (sbdp_test_board(hdp, &hp->h_opts) != 0) {
2704*7c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
2705*7c478bd9Sstevel@tonic-gate 
2706*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
2707*7c478bd9Sstevel@tonic-gate 	}
2708*7c478bd9Sstevel@tonic-gate 
2709*7c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_TEST_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2710*7c478bd9Sstevel@tonic-gate 		ESBD_INTERNAL, NULL);
2711*7c478bd9Sstevel@tonic-gate 
2712*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2713*7c478bd9Sstevel@tonic-gate }
2714*7c478bd9Sstevel@tonic-gate 
2715*7c478bd9Sstevel@tonic-gate static void
2716*7c478bd9Sstevel@tonic-gate sbd_assign_board(sbd_handle_t *hp)
2717*7c478bd9Sstevel@tonic-gate {
2718*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
2719*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2720*7c478bd9Sstevel@tonic-gate 
2721*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
2722*7c478bd9Sstevel@tonic-gate 
2723*7c478bd9Sstevel@tonic-gate 	PR_ALL("sbd_assign_board: board %d\n", sbp->sb_num);
2724*7c478bd9Sstevel@tonic-gate 
2725*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2726*7c478bd9Sstevel@tonic-gate 
2727*7c478bd9Sstevel@tonic-gate 	if (sbdp_assign_board(hdp) != 0) {
2728*7c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
2729*7c478bd9Sstevel@tonic-gate 
2730*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
2731*7c478bd9Sstevel@tonic-gate 	}
2732*7c478bd9Sstevel@tonic-gate 
2733*7c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_ASSIGN_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2734*7c478bd9Sstevel@tonic-gate 		ESBD_INTERNAL, NULL);
2735*7c478bd9Sstevel@tonic-gate 
2736*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2737*7c478bd9Sstevel@tonic-gate }
2738*7c478bd9Sstevel@tonic-gate 
2739*7c478bd9Sstevel@tonic-gate static void
2740*7c478bd9Sstevel@tonic-gate sbd_unassign_board(sbd_handle_t *hp)
2741*7c478bd9Sstevel@tonic-gate {
2742*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
2743*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2744*7c478bd9Sstevel@tonic-gate 
2745*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
2746*7c478bd9Sstevel@tonic-gate 
2747*7c478bd9Sstevel@tonic-gate 	PR_ALL("sbd_unassign_board: board %d\n", sbp->sb_num);
2748*7c478bd9Sstevel@tonic-gate 
2749*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2750*7c478bd9Sstevel@tonic-gate 
2751*7c478bd9Sstevel@tonic-gate 	if (sbdp_unassign_board(hdp) != 0) {
2752*7c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
2753*7c478bd9Sstevel@tonic-gate 
2754*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
2755*7c478bd9Sstevel@tonic-gate 	}
2756*7c478bd9Sstevel@tonic-gate 
2757*7c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_ASSIGN_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2758*7c478bd9Sstevel@tonic-gate 		ESBD_INTERNAL, NULL);
2759*7c478bd9Sstevel@tonic-gate 
2760*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2761*7c478bd9Sstevel@tonic-gate }
2762*7c478bd9Sstevel@tonic-gate 
2763*7c478bd9Sstevel@tonic-gate static void
2764*7c478bd9Sstevel@tonic-gate sbd_poweron_board(sbd_handle_t *hp)
2765*7c478bd9Sstevel@tonic-gate {
2766*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
2767*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2768*7c478bd9Sstevel@tonic-gate 
2769*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
2770*7c478bd9Sstevel@tonic-gate 
2771*7c478bd9Sstevel@tonic-gate 	PR_ALL("sbd_poweron_board: %d\n", sbp->sb_num);
2772*7c478bd9Sstevel@tonic-gate 
2773*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2774*7c478bd9Sstevel@tonic-gate 
2775*7c478bd9Sstevel@tonic-gate 	if (sbdp_poweron_board(hdp) != 0) {
2776*7c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
2777*7c478bd9Sstevel@tonic-gate 
2778*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
2779*7c478bd9Sstevel@tonic-gate 	}
2780*7c478bd9Sstevel@tonic-gate 
2781*7c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_POWERON_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2782*7c478bd9Sstevel@tonic-gate 		ESBD_INTERNAL, NULL);
2783*7c478bd9Sstevel@tonic-gate 
2784*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2785*7c478bd9Sstevel@tonic-gate }
2786*7c478bd9Sstevel@tonic-gate 
2787*7c478bd9Sstevel@tonic-gate static void
2788*7c478bd9Sstevel@tonic-gate sbd_poweroff_board(sbd_handle_t *hp)
2789*7c478bd9Sstevel@tonic-gate {
2790*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
2791*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2792*7c478bd9Sstevel@tonic-gate 
2793*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
2794*7c478bd9Sstevel@tonic-gate 
2795*7c478bd9Sstevel@tonic-gate 	PR_ALL("sbd_poweroff_board: %d\n", sbp->sb_num);
2796*7c478bd9Sstevel@tonic-gate 
2797*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2798*7c478bd9Sstevel@tonic-gate 
2799*7c478bd9Sstevel@tonic-gate 	if (sbdp_poweroff_board(hdp) != 0) {
2800*7c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
2801*7c478bd9Sstevel@tonic-gate 
2802*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
2803*7c478bd9Sstevel@tonic-gate 	}
2804*7c478bd9Sstevel@tonic-gate 
2805*7c478bd9Sstevel@tonic-gate 	SBD_INJECT_ERR(SBD_POWEROFF_BOARD_PSEUDO_ERR, hp->h_err, EIO,
2806*7c478bd9Sstevel@tonic-gate 		ESBD_INTERNAL, NULL);
2807*7c478bd9Sstevel@tonic-gate 
2808*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2809*7c478bd9Sstevel@tonic-gate }
2810*7c478bd9Sstevel@tonic-gate 
2811*7c478bd9Sstevel@tonic-gate 
2812*7c478bd9Sstevel@tonic-gate /*
2813*7c478bd9Sstevel@tonic-gate  * Return a list of the dip's of devices that are
2814*7c478bd9Sstevel@tonic-gate  * either present and attached, or present only but
2815*7c478bd9Sstevel@tonic-gate  * not yet attached for the given board.
2816*7c478bd9Sstevel@tonic-gate  */
2817*7c478bd9Sstevel@tonic-gate sbd_devlist_t *
2818*7c478bd9Sstevel@tonic-gate sbd_get_devlist(sbd_handle_t *hp, sbd_board_t *sbp, sbd_comp_type_t nodetype,
2819*7c478bd9Sstevel@tonic-gate 		int max_units, uint_t uset, int *count, int present_only)
2820*7c478bd9Sstevel@tonic-gate {
2821*7c478bd9Sstevel@tonic-gate 	int		i, ix;
2822*7c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*ret_devlist;
2823*7c478bd9Sstevel@tonic-gate 	dev_info_t	**devlist;
2824*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2825*7c478bd9Sstevel@tonic-gate 
2826*7c478bd9Sstevel@tonic-gate 	*count = 0;
2827*7c478bd9Sstevel@tonic-gate 	ret_devlist = GETSTRUCT(sbd_devlist_t, max_units);
2828*7c478bd9Sstevel@tonic-gate 	devlist = sbp->sb_devlist[NIX(nodetype)];
2829*7c478bd9Sstevel@tonic-gate 	/*
2830*7c478bd9Sstevel@tonic-gate 	 * Turn into binary value since we're going
2831*7c478bd9Sstevel@tonic-gate 	 * to be using XOR for a comparison.
2832*7c478bd9Sstevel@tonic-gate 	 * if (present_only) then
2833*7c478bd9Sstevel@tonic-gate 	 *	dev must be PRESENT, but NOT ATTACHED.
2834*7c478bd9Sstevel@tonic-gate 	 * else
2835*7c478bd9Sstevel@tonic-gate 	 *	dev must be PRESENT AND ATTACHED.
2836*7c478bd9Sstevel@tonic-gate 	 * endif
2837*7c478bd9Sstevel@tonic-gate 	 */
2838*7c478bd9Sstevel@tonic-gate 	if (present_only)
2839*7c478bd9Sstevel@tonic-gate 		present_only = 1;
2840*7c478bd9Sstevel@tonic-gate 
2841*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2842*7c478bd9Sstevel@tonic-gate 
2843*7c478bd9Sstevel@tonic-gate 	for (i = ix = 0; (i < max_units) && uset; i++) {
2844*7c478bd9Sstevel@tonic-gate 		int	ut, is_present, is_attached;
2845*7c478bd9Sstevel@tonic-gate 		dev_info_t *dip;
2846*7c478bd9Sstevel@tonic-gate 		sbderror_t *ep = SBD_HD2ERR(hp);
2847*7c478bd9Sstevel@tonic-gate 		int	nunits, distance, j;
2848*7c478bd9Sstevel@tonic-gate 
2849*7c478bd9Sstevel@tonic-gate 		/*
2850*7c478bd9Sstevel@tonic-gate 		 * For CMPs, we would like to perform DR operation on
2851*7c478bd9Sstevel@tonic-gate 		 * all the cores before moving onto the next chip.
2852*7c478bd9Sstevel@tonic-gate 		 * Therefore, when constructing the devlist, we process
2853*7c478bd9Sstevel@tonic-gate 		 * all the cores together.
2854*7c478bd9Sstevel@tonic-gate 		 */
2855*7c478bd9Sstevel@tonic-gate 		if (nodetype == SBD_COMP_CPU) {
2856*7c478bd9Sstevel@tonic-gate 			/*
2857*7c478bd9Sstevel@tonic-gate 			 * Number of units to process in the inner loop
2858*7c478bd9Sstevel@tonic-gate 			 */
2859*7c478bd9Sstevel@tonic-gate 			nunits = MAX_CORES_PER_CMP;
2860*7c478bd9Sstevel@tonic-gate 			/*
2861*7c478bd9Sstevel@tonic-gate 			 * The distance between the units in the
2862*7c478bd9Sstevel@tonic-gate 			 * board's sb_devlist structure.
2863*7c478bd9Sstevel@tonic-gate 			 */
2864*7c478bd9Sstevel@tonic-gate 			distance = MAX_CMP_UNITS_PER_BOARD;
2865*7c478bd9Sstevel@tonic-gate 		} else {
2866*7c478bd9Sstevel@tonic-gate 			nunits = 1;
2867*7c478bd9Sstevel@tonic-gate 			distance = 0;
2868*7c478bd9Sstevel@tonic-gate 		}
2869*7c478bd9Sstevel@tonic-gate 
2870*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < nunits; j++) {
2871*7c478bd9Sstevel@tonic-gate 			if ((dip = devlist[i + j * distance]) == NULL)
2872*7c478bd9Sstevel@tonic-gate 				continue;
2873*7c478bd9Sstevel@tonic-gate 
2874*7c478bd9Sstevel@tonic-gate 			ut = sbdp_get_unit_num(hdp, dip);
2875*7c478bd9Sstevel@tonic-gate 
2876*7c478bd9Sstevel@tonic-gate 			if (ut == -1) {
2877*7c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, ep);
2878*7c478bd9Sstevel@tonic-gate 				PR_ALL("sbd_get_devlist bad unit %d"
2879*7c478bd9Sstevel@tonic-gate 				    " code %d errno %d",
2880*7c478bd9Sstevel@tonic-gate 				    i, ep->e_code, ep->e_errno);
2881*7c478bd9Sstevel@tonic-gate 			}
2882*7c478bd9Sstevel@tonic-gate 
2883*7c478bd9Sstevel@tonic-gate 			if ((uset & (1 << ut)) == 0)
2884*7c478bd9Sstevel@tonic-gate 				continue;
2885*7c478bd9Sstevel@tonic-gate 			uset &= ~(1 << ut);
2886*7c478bd9Sstevel@tonic-gate 			is_present = SBD_DEV_IS_PRESENT(sbp, nodetype, ut) ?
2887*7c478bd9Sstevel@tonic-gate 			    1 : 0;
2888*7c478bd9Sstevel@tonic-gate 			is_attached = SBD_DEV_IS_ATTACHED(sbp, nodetype, ut) ?
2889*7c478bd9Sstevel@tonic-gate 			    1 : 0;
2890*7c478bd9Sstevel@tonic-gate 
2891*7c478bd9Sstevel@tonic-gate 			if (is_present && (present_only ^ is_attached)) {
2892*7c478bd9Sstevel@tonic-gate 				ret_devlist[ix].dv_dip = dip;
2893*7c478bd9Sstevel@tonic-gate 				sbd_init_err(&ret_devlist[ix].dv_error);
2894*7c478bd9Sstevel@tonic-gate 				ix++;
2895*7c478bd9Sstevel@tonic-gate 			}
2896*7c478bd9Sstevel@tonic-gate 		}
2897*7c478bd9Sstevel@tonic-gate 	}
2898*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2899*7c478bd9Sstevel@tonic-gate 
2900*7c478bd9Sstevel@tonic-gate 	if ((*count = ix) == 0) {
2901*7c478bd9Sstevel@tonic-gate 		FREESTRUCT(ret_devlist, sbd_devlist_t, max_units);
2902*7c478bd9Sstevel@tonic-gate 		ret_devlist = NULL;
2903*7c478bd9Sstevel@tonic-gate 	}
2904*7c478bd9Sstevel@tonic-gate 
2905*7c478bd9Sstevel@tonic-gate 	return (ret_devlist);
2906*7c478bd9Sstevel@tonic-gate }
2907*7c478bd9Sstevel@tonic-gate 
2908*7c478bd9Sstevel@tonic-gate static sbd_devlist_t *
2909*7c478bd9Sstevel@tonic-gate sbd_get_attach_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass)
2910*7c478bd9Sstevel@tonic-gate {
2911*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
2912*7c478bd9Sstevel@tonic-gate 	uint_t		uset;
2913*7c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
2914*7c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*attach_devlist;
2915*7c478bd9Sstevel@tonic-gate 	static int	next_pass = 1;
2916*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_get_attach_devlist";
2917*7c478bd9Sstevel@tonic-gate 
2918*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s (pass = %d)...\n", f, pass);
2919*7c478bd9Sstevel@tonic-gate 
2920*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
2921*7c478bd9Sstevel@tonic-gate 	devset = HD2MACHHD(hp)->sh_devset;
2922*7c478bd9Sstevel@tonic-gate 
2923*7c478bd9Sstevel@tonic-gate 	*devnump = 0;
2924*7c478bd9Sstevel@tonic-gate 	attach_devlist = NULL;
2925*7c478bd9Sstevel@tonic-gate 
2926*7c478bd9Sstevel@tonic-gate 	/*
2927*7c478bd9Sstevel@tonic-gate 	 * We switch on next_pass for the cases where a board
2928*7c478bd9Sstevel@tonic-gate 	 * does not contain a particular type of component.
2929*7c478bd9Sstevel@tonic-gate 	 * In these situations we don't want to return NULL
2930*7c478bd9Sstevel@tonic-gate 	 * prematurely.  We need to check other devices and
2931*7c478bd9Sstevel@tonic-gate 	 * we don't want to check the same type multiple times.
2932*7c478bd9Sstevel@tonic-gate 	 * For example, if there were no cpus, then on pass 1
2933*7c478bd9Sstevel@tonic-gate 	 * we would drop through and return the memory nodes.
2934*7c478bd9Sstevel@tonic-gate 	 * However, on pass 2 we would switch back to the memory
2935*7c478bd9Sstevel@tonic-gate 	 * nodes thereby returning them twice!  Using next_pass
2936*7c478bd9Sstevel@tonic-gate 	 * forces us down to the end (or next item).
2937*7c478bd9Sstevel@tonic-gate 	 */
2938*7c478bd9Sstevel@tonic-gate 	if (pass == 1)
2939*7c478bd9Sstevel@tonic-gate 		next_pass = 1;
2940*7c478bd9Sstevel@tonic-gate 
2941*7c478bd9Sstevel@tonic-gate 	switch (next_pass) {
2942*7c478bd9Sstevel@tonic-gate 	case 1:
2943*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) {
2944*7c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU);
2945*7c478bd9Sstevel@tonic-gate 
2946*7c478bd9Sstevel@tonic-gate 			attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_CPU,
2947*7c478bd9Sstevel@tonic-gate 						MAX_CPU_UNITS_PER_BOARD,
2948*7c478bd9Sstevel@tonic-gate 						uset, devnump, 1);
2949*7c478bd9Sstevel@tonic-gate 
2950*7c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT);
2951*7c478bd9Sstevel@tonic-gate 			if (!devset || attach_devlist) {
2952*7c478bd9Sstevel@tonic-gate 				next_pass = 2;
2953*7c478bd9Sstevel@tonic-gate 				return (attach_devlist);
2954*7c478bd9Sstevel@tonic-gate 			}
2955*7c478bd9Sstevel@tonic-gate 			/*
2956*7c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
2957*7c478bd9Sstevel@tonic-gate 			 * board, but there aren't any cpus, then just
2958*7c478bd9Sstevel@tonic-gate 			 * fall through to check for the next component.
2959*7c478bd9Sstevel@tonic-gate 			 */
2960*7c478bd9Sstevel@tonic-gate 		}
2961*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
2962*7c478bd9Sstevel@tonic-gate 
2963*7c478bd9Sstevel@tonic-gate 	case 2:
2964*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) {
2965*7c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM);
2966*7c478bd9Sstevel@tonic-gate 
2967*7c478bd9Sstevel@tonic-gate 			attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_MEM,
2968*7c478bd9Sstevel@tonic-gate 						MAX_MEM_UNITS_PER_BOARD,
2969*7c478bd9Sstevel@tonic-gate 						uset, devnump, 1);
2970*7c478bd9Sstevel@tonic-gate 
2971*7c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT);
2972*7c478bd9Sstevel@tonic-gate 			if (!devset || attach_devlist) {
2973*7c478bd9Sstevel@tonic-gate 				next_pass = 3;
2974*7c478bd9Sstevel@tonic-gate 				return (attach_devlist);
2975*7c478bd9Sstevel@tonic-gate 			}
2976*7c478bd9Sstevel@tonic-gate 			/*
2977*7c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
2978*7c478bd9Sstevel@tonic-gate 			 * board, but there isn't any memory, then
2979*7c478bd9Sstevel@tonic-gate 			 * just fall through to next component.
2980*7c478bd9Sstevel@tonic-gate 			 */
2981*7c478bd9Sstevel@tonic-gate 		}
2982*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
2983*7c478bd9Sstevel@tonic-gate 
2984*7c478bd9Sstevel@tonic-gate 
2985*7c478bd9Sstevel@tonic-gate 	case 3:
2986*7c478bd9Sstevel@tonic-gate 		next_pass = -1;
2987*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) {
2988*7c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO);
2989*7c478bd9Sstevel@tonic-gate 
2990*7c478bd9Sstevel@tonic-gate 			attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_IO,
2991*7c478bd9Sstevel@tonic-gate 						MAX_IO_UNITS_PER_BOARD,
2992*7c478bd9Sstevel@tonic-gate 						uset, devnump, 1);
2993*7c478bd9Sstevel@tonic-gate 
2994*7c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT);
2995*7c478bd9Sstevel@tonic-gate 			if (!devset || attach_devlist) {
2996*7c478bd9Sstevel@tonic-gate 				next_pass = 4;
2997*7c478bd9Sstevel@tonic-gate 				return (attach_devlist);
2998*7c478bd9Sstevel@tonic-gate 			}
2999*7c478bd9Sstevel@tonic-gate 		}
3000*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
3001*7c478bd9Sstevel@tonic-gate 
3002*7c478bd9Sstevel@tonic-gate 	default:
3003*7c478bd9Sstevel@tonic-gate 		*devnump = 0;
3004*7c478bd9Sstevel@tonic-gate 		return (NULL);
3005*7c478bd9Sstevel@tonic-gate 	}
3006*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3007*7c478bd9Sstevel@tonic-gate }
3008*7c478bd9Sstevel@tonic-gate 
3009*7c478bd9Sstevel@tonic-gate static int
3010*7c478bd9Sstevel@tonic-gate sbd_pre_attach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist,
3011*7c478bd9Sstevel@tonic-gate 	int32_t devnum)
3012*7c478bd9Sstevel@tonic-gate {
3013*7c478bd9Sstevel@tonic-gate 	int		max_units = 0, rv = 0;
3014*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
3015*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_pre_attach_devlist";
3016*7c478bd9Sstevel@tonic-gate 
3017*7c478bd9Sstevel@tonic-gate 	/*
3018*7c478bd9Sstevel@tonic-gate 	 * In this driver, all entries in a devlist[] are
3019*7c478bd9Sstevel@tonic-gate 	 * of the same nodetype.
3020*7c478bd9Sstevel@tonic-gate 	 */
3021*7c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
3022*7c478bd9Sstevel@tonic-gate 
3023*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3024*7c478bd9Sstevel@tonic-gate 		f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
3025*7c478bd9Sstevel@tonic-gate 
3026*7c478bd9Sstevel@tonic-gate 	switch (nodetype) {
3027*7c478bd9Sstevel@tonic-gate 
3028*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
3029*7c478bd9Sstevel@tonic-gate 		max_units = MAX_MEM_UNITS_PER_BOARD;
3030*7c478bd9Sstevel@tonic-gate 		rv = sbd_pre_attach_mem(hp, devlist, devnum);
3031*7c478bd9Sstevel@tonic-gate 		break;
3032*7c478bd9Sstevel@tonic-gate 
3033*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
3034*7c478bd9Sstevel@tonic-gate 		max_units = MAX_CPU_UNITS_PER_BOARD;
3035*7c478bd9Sstevel@tonic-gate 		rv = sbd_pre_attach_cpu(hp, devlist, devnum);
3036*7c478bd9Sstevel@tonic-gate 		break;
3037*7c478bd9Sstevel@tonic-gate 
3038*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
3039*7c478bd9Sstevel@tonic-gate 		max_units = MAX_IO_UNITS_PER_BOARD;
3040*7c478bd9Sstevel@tonic-gate 		break;
3041*7c478bd9Sstevel@tonic-gate 
3042*7c478bd9Sstevel@tonic-gate 	default:
3043*7c478bd9Sstevel@tonic-gate 		rv = -1;
3044*7c478bd9Sstevel@tonic-gate 		break;
3045*7c478bd9Sstevel@tonic-gate 	}
3046*7c478bd9Sstevel@tonic-gate 
3047*7c478bd9Sstevel@tonic-gate 	if (rv && max_units) {
3048*7c478bd9Sstevel@tonic-gate 		int	i;
3049*7c478bd9Sstevel@tonic-gate 		/*
3050*7c478bd9Sstevel@tonic-gate 		 * Need to clean up devlist
3051*7c478bd9Sstevel@tonic-gate 		 * if pre-op is going to fail.
3052*7c478bd9Sstevel@tonic-gate 		 */
3053*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_units; i++) {
3054*7c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERRSTR(&devlist[i].dv_error)) {
3055*7c478bd9Sstevel@tonic-gate 				SBD_FREE_ERR(&devlist[i].dv_error);
3056*7c478bd9Sstevel@tonic-gate 			} else {
3057*7c478bd9Sstevel@tonic-gate 				break;
3058*7c478bd9Sstevel@tonic-gate 			}
3059*7c478bd9Sstevel@tonic-gate 		}
3060*7c478bd9Sstevel@tonic-gate 		FREESTRUCT(devlist, sbd_devlist_t, max_units);
3061*7c478bd9Sstevel@tonic-gate 	}
3062*7c478bd9Sstevel@tonic-gate 
3063*7c478bd9Sstevel@tonic-gate 	/*
3064*7c478bd9Sstevel@tonic-gate 	 * If an error occurred, return "continue"
3065*7c478bd9Sstevel@tonic-gate 	 * indication so that we can continue attaching
3066*7c478bd9Sstevel@tonic-gate 	 * as much as possible.
3067*7c478bd9Sstevel@tonic-gate 	 */
3068*7c478bd9Sstevel@tonic-gate 	return (rv ? -1 : 0);
3069*7c478bd9Sstevel@tonic-gate }
3070*7c478bd9Sstevel@tonic-gate 
3071*7c478bd9Sstevel@tonic-gate static int
3072*7c478bd9Sstevel@tonic-gate sbd_post_attach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist,
3073*7c478bd9Sstevel@tonic-gate 			int32_t devnum)
3074*7c478bd9Sstevel@tonic-gate {
3075*7c478bd9Sstevel@tonic-gate 	int		i, max_units = 0, rv = 0;
3076*7c478bd9Sstevel@tonic-gate 	sbd_devset_t	devs_unattached, devs_present;
3077*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
3078*7c478bd9Sstevel@tonic-gate 	sbd_board_t 	*sbp = SBDH2BD(hp->h_sbd);
3079*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
3080*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_post_attach_devlist";
3081*7c478bd9Sstevel@tonic-gate 
3082*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
3083*7c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
3084*7c478bd9Sstevel@tonic-gate 
3085*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3086*7c478bd9Sstevel@tonic-gate 		f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
3087*7c478bd9Sstevel@tonic-gate 
3088*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
3089*7c478bd9Sstevel@tonic-gate 
3090*7c478bd9Sstevel@tonic-gate 	/*
3091*7c478bd9Sstevel@tonic-gate 	 * Need to free up devlist[] created earlier in
3092*7c478bd9Sstevel@tonic-gate 	 * sbd_get_attach_devlist().
3093*7c478bd9Sstevel@tonic-gate 	 */
3094*7c478bd9Sstevel@tonic-gate 	switch (nodetype) {
3095*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
3096*7c478bd9Sstevel@tonic-gate 		max_units = MAX_CPU_UNITS_PER_BOARD;
3097*7c478bd9Sstevel@tonic-gate 		rv = sbd_post_attach_cpu(hp, devlist, devnum);
3098*7c478bd9Sstevel@tonic-gate 		break;
3099*7c478bd9Sstevel@tonic-gate 
3100*7c478bd9Sstevel@tonic-gate 
3101*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
3102*7c478bd9Sstevel@tonic-gate 		max_units = MAX_MEM_UNITS_PER_BOARD;
3103*7c478bd9Sstevel@tonic-gate 
3104*7c478bd9Sstevel@tonic-gate 		rv = sbd_post_attach_mem(hp, devlist, devnum);
3105*7c478bd9Sstevel@tonic-gate 		break;
3106*7c478bd9Sstevel@tonic-gate 
3107*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
3108*7c478bd9Sstevel@tonic-gate 		max_units = MAX_IO_UNITS_PER_BOARD;
3109*7c478bd9Sstevel@tonic-gate 		break;
3110*7c478bd9Sstevel@tonic-gate 
3111*7c478bd9Sstevel@tonic-gate 	default:
3112*7c478bd9Sstevel@tonic-gate 		rv = -1;
3113*7c478bd9Sstevel@tonic-gate 		break;
3114*7c478bd9Sstevel@tonic-gate 	}
3115*7c478bd9Sstevel@tonic-gate 
3116*7c478bd9Sstevel@tonic-gate 
3117*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
3118*7c478bd9Sstevel@tonic-gate 		int		unit;
3119*7c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
3120*7c478bd9Sstevel@tonic-gate 		sbderror_t	*ep;
3121*7c478bd9Sstevel@tonic-gate 
3122*7c478bd9Sstevel@tonic-gate 		ep = &devlist[i].dv_error;
3123*7c478bd9Sstevel@tonic-gate 
3124*7c478bd9Sstevel@tonic-gate 		if (sbd_set_err_in_hdl(hp, ep) == 0)
3125*7c478bd9Sstevel@tonic-gate 			continue;
3126*7c478bd9Sstevel@tonic-gate 
3127*7c478bd9Sstevel@tonic-gate 		dip = devlist[i].dv_dip;
3128*7c478bd9Sstevel@tonic-gate 		nodetype = sbd_get_devtype(hp, dip);
3129*7c478bd9Sstevel@tonic-gate 		unit = sbdp_get_unit_num(hdp, dip);
3130*7c478bd9Sstevel@tonic-gate 
3131*7c478bd9Sstevel@tonic-gate 		if (unit == -1) {
3132*7c478bd9Sstevel@tonic-gate 			SBD_GET_PERR(hdp->h_err, ep);
3133*7c478bd9Sstevel@tonic-gate 			continue;
3134*7c478bd9Sstevel@tonic-gate 		}
3135*7c478bd9Sstevel@tonic-gate 
3136*7c478bd9Sstevel@tonic-gate 		unit = sbd_check_unit_attached(sbp, dip, unit, nodetype, ep);
3137*7c478bd9Sstevel@tonic-gate 
3138*7c478bd9Sstevel@tonic-gate 		if (unit == -1) {
3139*7c478bd9Sstevel@tonic-gate 			PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not attached\n",
3140*7c478bd9Sstevel@tonic-gate 				f, sbd_ct_str[(int)nodetype], sbp->sb_num, i);
3141*7c478bd9Sstevel@tonic-gate 			continue;
3142*7c478bd9Sstevel@tonic-gate 		}
3143*7c478bd9Sstevel@tonic-gate 
3144*7c478bd9Sstevel@tonic-gate 		SBD_DEV_SET_ATTACHED(sbp, nodetype, unit);
3145*7c478bd9Sstevel@tonic-gate 		SBD_DEVICE_TRANSITION(sbp, nodetype, unit,
3146*7c478bd9Sstevel@tonic-gate 						SBD_STATE_CONFIGURED);
3147*7c478bd9Sstevel@tonic-gate 	}
3148*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
3149*7c478bd9Sstevel@tonic-gate 
3150*7c478bd9Sstevel@tonic-gate 	if (rv) {
3151*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s: errno %d, ecode %d during attach\n",
3152*7c478bd9Sstevel@tonic-gate 			f, SBD_GET_ERRNO(SBD_HD2ERR(hp)),
3153*7c478bd9Sstevel@tonic-gate 			SBD_GET_ERR(HD2MACHERR(hp)));
3154*7c478bd9Sstevel@tonic-gate 	}
3155*7c478bd9Sstevel@tonic-gate 
3156*7c478bd9Sstevel@tonic-gate 	devs_present = SBD_DEVS_PRESENT(sbp);
3157*7c478bd9Sstevel@tonic-gate 	devs_unattached = SBD_DEVS_UNATTACHED(sbp);
3158*7c478bd9Sstevel@tonic-gate 
3159*7c478bd9Sstevel@tonic-gate 	switch (SBD_BOARD_STATE(sbp)) {
3160*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONNECTED:
3161*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNCONFIGURED:
3162*7c478bd9Sstevel@tonic-gate 		ASSERT(devs_present);
3163*7c478bd9Sstevel@tonic-gate 
3164*7c478bd9Sstevel@tonic-gate 		if (devs_unattached == 0) {
3165*7c478bd9Sstevel@tonic-gate 			/*
3166*7c478bd9Sstevel@tonic-gate 			 * All devices finally attached.
3167*7c478bd9Sstevel@tonic-gate 			 */
3168*7c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED);
3169*7c478bd9Sstevel@tonic-gate 			sbp->sb_rstate = SBD_STAT_CONNECTED;
3170*7c478bd9Sstevel@tonic-gate 			sbp->sb_ostate = SBD_STAT_CONFIGURED;
3171*7c478bd9Sstevel@tonic-gate 		} else if (devs_present != devs_unattached) {
3172*7c478bd9Sstevel@tonic-gate 			/*
3173*7c478bd9Sstevel@tonic-gate 			 * Only some devices are fully attached.
3174*7c478bd9Sstevel@tonic-gate 			 */
3175*7c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL);
3176*7c478bd9Sstevel@tonic-gate 			sbp->sb_rstate = SBD_STAT_CONNECTED;
3177*7c478bd9Sstevel@tonic-gate 			sbp->sb_ostate = SBD_STAT_UNCONFIGURED;
3178*7c478bd9Sstevel@tonic-gate 		}
3179*7c478bd9Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&sbp->sb_time);
3180*7c478bd9Sstevel@tonic-gate 		break;
3181*7c478bd9Sstevel@tonic-gate 
3182*7c478bd9Sstevel@tonic-gate 	case SBD_STATE_PARTIAL:
3183*7c478bd9Sstevel@tonic-gate 		ASSERT(devs_present);
3184*7c478bd9Sstevel@tonic-gate 		/*
3185*7c478bd9Sstevel@tonic-gate 		 * All devices finally attached.
3186*7c478bd9Sstevel@tonic-gate 		 */
3187*7c478bd9Sstevel@tonic-gate 		if (devs_unattached == 0) {
3188*7c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED);
3189*7c478bd9Sstevel@tonic-gate 			sbp->sb_rstate = SBD_STAT_CONNECTED;
3190*7c478bd9Sstevel@tonic-gate 			sbp->sb_ostate = SBD_STAT_CONFIGURED;
3191*7c478bd9Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&sbp->sb_time);
3192*7c478bd9Sstevel@tonic-gate 		}
3193*7c478bd9Sstevel@tonic-gate 		break;
3194*7c478bd9Sstevel@tonic-gate 
3195*7c478bd9Sstevel@tonic-gate 	default:
3196*7c478bd9Sstevel@tonic-gate 		break;
3197*7c478bd9Sstevel@tonic-gate 	}
3198*7c478bd9Sstevel@tonic-gate 
3199*7c478bd9Sstevel@tonic-gate 	if (max_units && devlist) {
3200*7c478bd9Sstevel@tonic-gate 		int	i;
3201*7c478bd9Sstevel@tonic-gate 
3202*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_units; i++) {
3203*7c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERRSTR(&devlist[i].dv_error)) {
3204*7c478bd9Sstevel@tonic-gate 				SBD_FREE_ERR(&devlist[i].dv_error);
3205*7c478bd9Sstevel@tonic-gate 			} else {
3206*7c478bd9Sstevel@tonic-gate 				break;
3207*7c478bd9Sstevel@tonic-gate 			}
3208*7c478bd9Sstevel@tonic-gate 		}
3209*7c478bd9Sstevel@tonic-gate 		FREESTRUCT(devlist, sbd_devlist_t, max_units);
3210*7c478bd9Sstevel@tonic-gate 	}
3211*7c478bd9Sstevel@tonic-gate 
3212*7c478bd9Sstevel@tonic-gate 	/*
3213*7c478bd9Sstevel@tonic-gate 	 * Our policy is to attach all components that are
3214*7c478bd9Sstevel@tonic-gate 	 * possible, thus we always return "success" on the
3215*7c478bd9Sstevel@tonic-gate 	 * pre and post operations.
3216*7c478bd9Sstevel@tonic-gate 	 */
3217*7c478bd9Sstevel@tonic-gate 	return (0);
3218*7c478bd9Sstevel@tonic-gate }
3219*7c478bd9Sstevel@tonic-gate 
3220*7c478bd9Sstevel@tonic-gate /*
3221*7c478bd9Sstevel@tonic-gate  * We only need to "release" cpu and memory devices.
3222*7c478bd9Sstevel@tonic-gate  */
3223*7c478bd9Sstevel@tonic-gate static sbd_devlist_t *
3224*7c478bd9Sstevel@tonic-gate sbd_get_release_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass)
3225*7c478bd9Sstevel@tonic-gate {
3226*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
3227*7c478bd9Sstevel@tonic-gate 	uint_t		uset;
3228*7c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
3229*7c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*release_devlist;
3230*7c478bd9Sstevel@tonic-gate 	static int	next_pass = 1;
3231*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_get_release_devlist";
3232*7c478bd9Sstevel@tonic-gate 
3233*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s (pass = %d)...\n", f, pass);
3234*7c478bd9Sstevel@tonic-gate 
3235*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
3236*7c478bd9Sstevel@tonic-gate 	devset = HD2MACHHD(hp)->sh_devset;
3237*7c478bd9Sstevel@tonic-gate 
3238*7c478bd9Sstevel@tonic-gate 	*devnump = 0;
3239*7c478bd9Sstevel@tonic-gate 	release_devlist = NULL;
3240*7c478bd9Sstevel@tonic-gate 
3241*7c478bd9Sstevel@tonic-gate 	/*
3242*7c478bd9Sstevel@tonic-gate 	 * We switch on next_pass for the cases where a board
3243*7c478bd9Sstevel@tonic-gate 	 * does not contain a particular type of component.
3244*7c478bd9Sstevel@tonic-gate 	 * In these situations we don't want to return NULL
3245*7c478bd9Sstevel@tonic-gate 	 * prematurely.  We need to check other devices and
3246*7c478bd9Sstevel@tonic-gate 	 * we don't want to check the same type multiple times.
3247*7c478bd9Sstevel@tonic-gate 	 * For example, if there were no cpus, then on pass 1
3248*7c478bd9Sstevel@tonic-gate 	 * we would drop through and return the memory nodes.
3249*7c478bd9Sstevel@tonic-gate 	 * However, on pass 2 we would switch back to the memory
3250*7c478bd9Sstevel@tonic-gate 	 * nodes thereby returning them twice!  Using next_pass
3251*7c478bd9Sstevel@tonic-gate 	 * forces us down to the end (or next item).
3252*7c478bd9Sstevel@tonic-gate 	 */
3253*7c478bd9Sstevel@tonic-gate 	if (pass == 1)
3254*7c478bd9Sstevel@tonic-gate 		next_pass = 1;
3255*7c478bd9Sstevel@tonic-gate 
3256*7c478bd9Sstevel@tonic-gate 	switch (next_pass) {
3257*7c478bd9Sstevel@tonic-gate 	case 1:
3258*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) {
3259*7c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM);
3260*7c478bd9Sstevel@tonic-gate 
3261*7c478bd9Sstevel@tonic-gate 			release_devlist = sbd_get_devlist(hp, sbp,
3262*7c478bd9Sstevel@tonic-gate 						SBD_COMP_MEM,
3263*7c478bd9Sstevel@tonic-gate 						MAX_MEM_UNITS_PER_BOARD,
3264*7c478bd9Sstevel@tonic-gate 						uset, devnump, 0);
3265*7c478bd9Sstevel@tonic-gate 
3266*7c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT);
3267*7c478bd9Sstevel@tonic-gate 			if (!devset || release_devlist) {
3268*7c478bd9Sstevel@tonic-gate 				next_pass = 2;
3269*7c478bd9Sstevel@tonic-gate 				return (release_devlist);
3270*7c478bd9Sstevel@tonic-gate 			}
3271*7c478bd9Sstevel@tonic-gate 			/*
3272*7c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
3273*7c478bd9Sstevel@tonic-gate 			 * board, but there isn't any memory, then
3274*7c478bd9Sstevel@tonic-gate 			 * just fall through to next component.
3275*7c478bd9Sstevel@tonic-gate 			 */
3276*7c478bd9Sstevel@tonic-gate 		}
3277*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
3278*7c478bd9Sstevel@tonic-gate 
3279*7c478bd9Sstevel@tonic-gate 
3280*7c478bd9Sstevel@tonic-gate 	case 2:
3281*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) {
3282*7c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU);
3283*7c478bd9Sstevel@tonic-gate 
3284*7c478bd9Sstevel@tonic-gate 			release_devlist = sbd_get_devlist(hp, sbp,
3285*7c478bd9Sstevel@tonic-gate 						SBD_COMP_CPU,
3286*7c478bd9Sstevel@tonic-gate 						MAX_CPU_UNITS_PER_BOARD,
3287*7c478bd9Sstevel@tonic-gate 						uset, devnump, 0);
3288*7c478bd9Sstevel@tonic-gate 
3289*7c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT);
3290*7c478bd9Sstevel@tonic-gate 			if (!devset || release_devlist) {
3291*7c478bd9Sstevel@tonic-gate 				next_pass = 3;
3292*7c478bd9Sstevel@tonic-gate 				return (release_devlist);
3293*7c478bd9Sstevel@tonic-gate 			}
3294*7c478bd9Sstevel@tonic-gate 			/*
3295*7c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
3296*7c478bd9Sstevel@tonic-gate 			 * board, but there aren't any cpus, then just
3297*7c478bd9Sstevel@tonic-gate 			 * fall through to check for the next component.
3298*7c478bd9Sstevel@tonic-gate 			 */
3299*7c478bd9Sstevel@tonic-gate 		}
3300*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
3301*7c478bd9Sstevel@tonic-gate 
3302*7c478bd9Sstevel@tonic-gate 
3303*7c478bd9Sstevel@tonic-gate 	case 3:
3304*7c478bd9Sstevel@tonic-gate 		next_pass = -1;
3305*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) {
3306*7c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO);
3307*7c478bd9Sstevel@tonic-gate 
3308*7c478bd9Sstevel@tonic-gate 			release_devlist = sbd_get_devlist(hp, sbp,
3309*7c478bd9Sstevel@tonic-gate 						SBD_COMP_IO,
3310*7c478bd9Sstevel@tonic-gate 						MAX_IO_UNITS_PER_BOARD,
3311*7c478bd9Sstevel@tonic-gate 						uset, devnump, 0);
3312*7c478bd9Sstevel@tonic-gate 
3313*7c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT);
3314*7c478bd9Sstevel@tonic-gate 			if (!devset || release_devlist) {
3315*7c478bd9Sstevel@tonic-gate 				next_pass = 4;
3316*7c478bd9Sstevel@tonic-gate 				return (release_devlist);
3317*7c478bd9Sstevel@tonic-gate 			}
3318*7c478bd9Sstevel@tonic-gate 		}
3319*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
3320*7c478bd9Sstevel@tonic-gate 
3321*7c478bd9Sstevel@tonic-gate 	default:
3322*7c478bd9Sstevel@tonic-gate 		*devnump = 0;
3323*7c478bd9Sstevel@tonic-gate 		return (NULL);
3324*7c478bd9Sstevel@tonic-gate 	}
3325*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3326*7c478bd9Sstevel@tonic-gate }
3327*7c478bd9Sstevel@tonic-gate 
3328*7c478bd9Sstevel@tonic-gate static int
3329*7c478bd9Sstevel@tonic-gate sbd_pre_release_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist,
3330*7c478bd9Sstevel@tonic-gate 			int32_t devnum)
3331*7c478bd9Sstevel@tonic-gate {
3332*7c478bd9Sstevel@tonic-gate 	int		max_units = 0, rv = 0;
3333*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
3334*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_pre_release_devlist";
3335*7c478bd9Sstevel@tonic-gate 
3336*7c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
3337*7c478bd9Sstevel@tonic-gate 
3338*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3339*7c478bd9Sstevel@tonic-gate 		f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
3340*7c478bd9Sstevel@tonic-gate 
3341*7c478bd9Sstevel@tonic-gate 	switch (nodetype) {
3342*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU: {
3343*7c478bd9Sstevel@tonic-gate 		int			i, mem_present = 0;
3344*7c478bd9Sstevel@tonic-gate 		sbd_board_t		*sbp = SBDH2BD(hp->h_sbd);
3345*7c478bd9Sstevel@tonic-gate 		sbd_devset_t		devset;
3346*7c478bd9Sstevel@tonic-gate 		sbd_priv_handle_t	*shp = HD2MACHHD(hp);
3347*7c478bd9Sstevel@tonic-gate 
3348*7c478bd9Sstevel@tonic-gate 		max_units = MAX_CPU_UNITS_PER_BOARD;
3349*7c478bd9Sstevel@tonic-gate 
3350*7c478bd9Sstevel@tonic-gate 		devset = shp->sh_orig_devset;
3351*7c478bd9Sstevel@tonic-gate 
3352*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
3353*7c478bd9Sstevel@tonic-gate 			/*
3354*7c478bd9Sstevel@tonic-gate 			 * if client also requested to unconfigure memory
3355*7c478bd9Sstevel@tonic-gate 			 * the we allow the operation. Therefore
3356*7c478bd9Sstevel@tonic-gate 			 * we need to warranty that memory gets unconfig
3357*7c478bd9Sstevel@tonic-gate 			 * before cpus
3358*7c478bd9Sstevel@tonic-gate 			 */
3359*7c478bd9Sstevel@tonic-gate 
3360*7c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) {
3361*7c478bd9Sstevel@tonic-gate 				continue;
3362*7c478bd9Sstevel@tonic-gate 			}
3363*7c478bd9Sstevel@tonic-gate 			if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_MEM, i)) {
3364*7c478bd9Sstevel@tonic-gate 				mem_present = 1;
3365*7c478bd9Sstevel@tonic-gate 				break;
3366*7c478bd9Sstevel@tonic-gate 			}
3367*7c478bd9Sstevel@tonic-gate 		}
3368*7c478bd9Sstevel@tonic-gate 		if (mem_present) {
3369*7c478bd9Sstevel@tonic-gate 			sbderror_t	*ep = SBD_HD2ERR(hp);
3370*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(ep, ESBD_MEMONLINE);
3371*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERRSTR(ep, sbp->sb_mempath[i]);
3372*7c478bd9Sstevel@tonic-gate 			rv = -1;
3373*7c478bd9Sstevel@tonic-gate 		} else {
3374*7c478bd9Sstevel@tonic-gate 			rv = sbd_pre_release_cpu(hp, devlist, devnum);
3375*7c478bd9Sstevel@tonic-gate 		}
3376*7c478bd9Sstevel@tonic-gate 
3377*7c478bd9Sstevel@tonic-gate 		break;
3378*7c478bd9Sstevel@tonic-gate 
3379*7c478bd9Sstevel@tonic-gate 	}
3380*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
3381*7c478bd9Sstevel@tonic-gate 		max_units = MAX_MEM_UNITS_PER_BOARD;
3382*7c478bd9Sstevel@tonic-gate 		rv = sbd_pre_release_mem(hp, devlist, devnum);
3383*7c478bd9Sstevel@tonic-gate 		break;
3384*7c478bd9Sstevel@tonic-gate 
3385*7c478bd9Sstevel@tonic-gate 
3386*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
3387*7c478bd9Sstevel@tonic-gate 		max_units = MAX_IO_UNITS_PER_BOARD;
3388*7c478bd9Sstevel@tonic-gate 		rv = sbd_pre_release_io(hp, devlist, devnum);
3389*7c478bd9Sstevel@tonic-gate 		break;
3390*7c478bd9Sstevel@tonic-gate 
3391*7c478bd9Sstevel@tonic-gate 	default:
3392*7c478bd9Sstevel@tonic-gate 		rv = -1;
3393*7c478bd9Sstevel@tonic-gate 		break;
3394*7c478bd9Sstevel@tonic-gate 	}
3395*7c478bd9Sstevel@tonic-gate 
3396*7c478bd9Sstevel@tonic-gate 	if (rv && max_units) {
3397*7c478bd9Sstevel@tonic-gate 		int	i;
3398*7c478bd9Sstevel@tonic-gate 
3399*7c478bd9Sstevel@tonic-gate 		/*
3400*7c478bd9Sstevel@tonic-gate 		 * the individual pre_release component routines should
3401*7c478bd9Sstevel@tonic-gate 		 * have set the error in the handle.  No need to set it
3402*7c478bd9Sstevel@tonic-gate 		 * here
3403*7c478bd9Sstevel@tonic-gate 		 *
3404*7c478bd9Sstevel@tonic-gate 		 * Need to clean up dynamically allocated devlist
3405*7c478bd9Sstevel@tonic-gate 		 * if pre-op is going to fail.
3406*7c478bd9Sstevel@tonic-gate 		 */
3407*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_units; i++) {
3408*7c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERRSTR(&devlist[i].dv_error)) {
3409*7c478bd9Sstevel@tonic-gate 				SBD_FREE_ERR(&devlist[i].dv_error);
3410*7c478bd9Sstevel@tonic-gate 			} else {
3411*7c478bd9Sstevel@tonic-gate 				break;
3412*7c478bd9Sstevel@tonic-gate 			}
3413*7c478bd9Sstevel@tonic-gate 		}
3414*7c478bd9Sstevel@tonic-gate 		FREESTRUCT(devlist, sbd_devlist_t, max_units);
3415*7c478bd9Sstevel@tonic-gate 	}
3416*7c478bd9Sstevel@tonic-gate 
3417*7c478bd9Sstevel@tonic-gate 	return (rv ? -1 : 0);
3418*7c478bd9Sstevel@tonic-gate }
3419*7c478bd9Sstevel@tonic-gate 
3420*7c478bd9Sstevel@tonic-gate static int
3421*7c478bd9Sstevel@tonic-gate sbd_post_release_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist,
3422*7c478bd9Sstevel@tonic-gate 			int32_t devnum)
3423*7c478bd9Sstevel@tonic-gate {
3424*7c478bd9Sstevel@tonic-gate 	int		i, max_units = 0;
3425*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
3426*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
3427*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
3428*7c478bd9Sstevel@tonic-gate 	sbd_error_t	*spe;
3429*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_post_release_devlist";
3430*7c478bd9Sstevel@tonic-gate 
3431*7c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
3432*7c478bd9Sstevel@tonic-gate 	ASSERT(nodetype >= SBD_COMP_CPU && nodetype <= SBD_COMP_IO);
3433*7c478bd9Sstevel@tonic-gate 
3434*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3435*7c478bd9Sstevel@tonic-gate 		f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
3436*7c478bd9Sstevel@tonic-gate 
3437*7c478bd9Sstevel@tonic-gate 	/*
3438*7c478bd9Sstevel@tonic-gate 	 * Need to free up devlist[] created earlier in
3439*7c478bd9Sstevel@tonic-gate 	 * sbd_get_release_devlist().
3440*7c478bd9Sstevel@tonic-gate 	 */
3441*7c478bd9Sstevel@tonic-gate 	switch (nodetype) {
3442*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
3443*7c478bd9Sstevel@tonic-gate 		max_units = MAX_CPU_UNITS_PER_BOARD;
3444*7c478bd9Sstevel@tonic-gate 		break;
3445*7c478bd9Sstevel@tonic-gate 
3446*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
3447*7c478bd9Sstevel@tonic-gate 		max_units = MAX_MEM_UNITS_PER_BOARD;
3448*7c478bd9Sstevel@tonic-gate 		break;
3449*7c478bd9Sstevel@tonic-gate 
3450*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
3451*7c478bd9Sstevel@tonic-gate 		/*
3452*7c478bd9Sstevel@tonic-gate 		 *  Need to check if specific I/O is referenced and
3453*7c478bd9Sstevel@tonic-gate 		 *  fail post-op.
3454*7c478bd9Sstevel@tonic-gate 		 */
3455*7c478bd9Sstevel@tonic-gate 
3456*7c478bd9Sstevel@tonic-gate 		if (sbd_check_io_refs(hp, devlist, devnum) > 0) {
3457*7c478bd9Sstevel@tonic-gate 				PR_IO("%s: error - I/O devices ref'd\n", f);
3458*7c478bd9Sstevel@tonic-gate 		}
3459*7c478bd9Sstevel@tonic-gate 
3460*7c478bd9Sstevel@tonic-gate 		max_units = MAX_IO_UNITS_PER_BOARD;
3461*7c478bd9Sstevel@tonic-gate 		break;
3462*7c478bd9Sstevel@tonic-gate 
3463*7c478bd9Sstevel@tonic-gate 	default:
3464*7c478bd9Sstevel@tonic-gate 		{
3465*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: invalid nodetype (%d)",
3466*7c478bd9Sstevel@tonic-gate 				f, (int)nodetype);
3467*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(HD2MACHERR(hp), ESBD_INVAL);
3468*7c478bd9Sstevel@tonic-gate 		}
3469*7c478bd9Sstevel@tonic-gate 		break;
3470*7c478bd9Sstevel@tonic-gate 	}
3471*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
3472*7c478bd9Sstevel@tonic-gate 	spe = hdp->h_err;
3473*7c478bd9Sstevel@tonic-gate 
3474*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
3475*7c478bd9Sstevel@tonic-gate 		int		unit;
3476*7c478bd9Sstevel@tonic-gate 		sbderror_t	*ep;
3477*7c478bd9Sstevel@tonic-gate 
3478*7c478bd9Sstevel@tonic-gate 		ep = &devlist[i].dv_error;
3479*7c478bd9Sstevel@tonic-gate 
3480*7c478bd9Sstevel@tonic-gate 		if (sbd_set_err_in_hdl(hp, ep) == 0) {
3481*7c478bd9Sstevel@tonic-gate 			continue;
3482*7c478bd9Sstevel@tonic-gate 		}
3483*7c478bd9Sstevel@tonic-gate 
3484*7c478bd9Sstevel@tonic-gate 		unit = sbdp_get_unit_num(hdp, devlist[i].dv_dip);
3485*7c478bd9Sstevel@tonic-gate 		if (unit == -1) {
3486*7c478bd9Sstevel@tonic-gate 			SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
3487*7c478bd9Sstevel@tonic-gate 			PR_ALL("%s bad unit num: %d code %d",
3488*7c478bd9Sstevel@tonic-gate 			    f, unit, spe->e_code);
3489*7c478bd9Sstevel@tonic-gate 			continue;
3490*7c478bd9Sstevel@tonic-gate 		}
3491*7c478bd9Sstevel@tonic-gate 	}
3492*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
3493*7c478bd9Sstevel@tonic-gate 
3494*7c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERRNO(SBD_HD2ERR(hp))) {
3495*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s: errno %d, ecode %d during release\n",
3496*7c478bd9Sstevel@tonic-gate 			f, SBD_GET_ERRNO(SBD_HD2ERR(hp)),
3497*7c478bd9Sstevel@tonic-gate 			SBD_GET_ERR(SBD_HD2ERR(hp)));
3498*7c478bd9Sstevel@tonic-gate 	}
3499*7c478bd9Sstevel@tonic-gate 
3500*7c478bd9Sstevel@tonic-gate 	if (max_units && devlist) {
3501*7c478bd9Sstevel@tonic-gate 		int	i;
3502*7c478bd9Sstevel@tonic-gate 
3503*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_units; i++) {
3504*7c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERRSTR(&devlist[i].dv_error)) {
3505*7c478bd9Sstevel@tonic-gate 				SBD_FREE_ERR(&devlist[i].dv_error);
3506*7c478bd9Sstevel@tonic-gate 			} else {
3507*7c478bd9Sstevel@tonic-gate 				break;
3508*7c478bd9Sstevel@tonic-gate 			}
3509*7c478bd9Sstevel@tonic-gate 		}
3510*7c478bd9Sstevel@tonic-gate 		FREESTRUCT(devlist, sbd_devlist_t, max_units);
3511*7c478bd9Sstevel@tonic-gate 	}
3512*7c478bd9Sstevel@tonic-gate 
3513*7c478bd9Sstevel@tonic-gate 	return (SBD_GET_ERRNO(SBD_HD2ERR(hp)) ? -1 : 0);
3514*7c478bd9Sstevel@tonic-gate }
3515*7c478bd9Sstevel@tonic-gate 
3516*7c478bd9Sstevel@tonic-gate static void
3517*7c478bd9Sstevel@tonic-gate sbd_release_dev_done(sbd_board_t *sbp, sbd_comp_type_t nodetype, int unit)
3518*7c478bd9Sstevel@tonic-gate {
3519*7c478bd9Sstevel@tonic-gate 	SBD_DEV_SET_UNREFERENCED(sbp, nodetype, unit);
3520*7c478bd9Sstevel@tonic-gate 	SBD_DEVICE_TRANSITION(sbp, nodetype, unit, SBD_STATE_UNREFERENCED);
3521*7c478bd9Sstevel@tonic-gate }
3522*7c478bd9Sstevel@tonic-gate 
3523*7c478bd9Sstevel@tonic-gate static void
3524*7c478bd9Sstevel@tonic-gate sbd_release_done(sbd_handle_t *hp, sbd_comp_type_t nodetype, dev_info_t *dip)
3525*7c478bd9Sstevel@tonic-gate {
3526*7c478bd9Sstevel@tonic-gate 	int		unit;
3527*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
3528*7c478bd9Sstevel@tonic-gate 	sbderror_t	*ep;
3529*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_release_done";
3530*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
3531*7c478bd9Sstevel@tonic-gate 
3532*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
3533*7c478bd9Sstevel@tonic-gate 
3534*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
3535*7c478bd9Sstevel@tonic-gate 	ep = SBD_HD2ERR(hp);
3536*7c478bd9Sstevel@tonic-gate 
3537*7c478bd9Sstevel@tonic-gate 	if ((unit = sbdp_get_unit_num(hdp, dip)) < 0) {
3538*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
3539*7c478bd9Sstevel@tonic-gate 			"sbd:%s: unable to get unit for dip (0x%p)",
3540*7c478bd9Sstevel@tonic-gate 			f, (void *)dip);
3541*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
3542*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
3543*7c478bd9Sstevel@tonic-gate 		return;
3544*7c478bd9Sstevel@tonic-gate 	}
3545*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
3546*7c478bd9Sstevel@tonic-gate 
3547*7c478bd9Sstevel@tonic-gate 	/*
3548*7c478bd9Sstevel@tonic-gate 	 * Transfer the device which just completed its release
3549*7c478bd9Sstevel@tonic-gate 	 * to the UNREFERENCED state.
3550*7c478bd9Sstevel@tonic-gate 	 */
3551*7c478bd9Sstevel@tonic-gate 	switch (nodetype) {
3552*7c478bd9Sstevel@tonic-gate 
3553*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
3554*7c478bd9Sstevel@tonic-gate 		sbd_release_mem_done((void *)hp, unit);
3555*7c478bd9Sstevel@tonic-gate 		break;
3556*7c478bd9Sstevel@tonic-gate 
3557*7c478bd9Sstevel@tonic-gate 	default:
3558*7c478bd9Sstevel@tonic-gate 		sbd_release_dev_done(sbp, nodetype, unit);
3559*7c478bd9Sstevel@tonic-gate 		break;
3560*7c478bd9Sstevel@tonic-gate 	}
3561*7c478bd9Sstevel@tonic-gate 
3562*7c478bd9Sstevel@tonic-gate 	/*
3563*7c478bd9Sstevel@tonic-gate 	 * If the entire board was released and all components
3564*7c478bd9Sstevel@tonic-gate 	 * unreferenced then transfer it to the UNREFERENCED state.
3565*7c478bd9Sstevel@tonic-gate 	 */
3566*7c478bd9Sstevel@tonic-gate 	if (SBD_DEVS_RELEASED(sbp) == SBD_DEVS_UNREFERENCED(sbp)) {
3567*7c478bd9Sstevel@tonic-gate 		SBD_BOARD_TRANSITION(sbp, SBD_STATE_UNREFERENCED);
3568*7c478bd9Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&sbp->sb_time);
3569*7c478bd9Sstevel@tonic-gate 	}
3570*7c478bd9Sstevel@tonic-gate }
3571*7c478bd9Sstevel@tonic-gate 
3572*7c478bd9Sstevel@tonic-gate static sbd_devlist_t *
3573*7c478bd9Sstevel@tonic-gate sbd_get_detach_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass)
3574*7c478bd9Sstevel@tonic-gate {
3575*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
3576*7c478bd9Sstevel@tonic-gate 	uint_t		uset;
3577*7c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
3578*7c478bd9Sstevel@tonic-gate 	sbd_devlist_t	*detach_devlist;
3579*7c478bd9Sstevel@tonic-gate 	static int	next_pass = 1;
3580*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_get_detach_devlist";
3581*7c478bd9Sstevel@tonic-gate 
3582*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s (pass = %d)...\n", f, pass);
3583*7c478bd9Sstevel@tonic-gate 
3584*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
3585*7c478bd9Sstevel@tonic-gate 	devset = HD2MACHHD(hp)->sh_devset;
3586*7c478bd9Sstevel@tonic-gate 
3587*7c478bd9Sstevel@tonic-gate 	*devnump = 0;
3588*7c478bd9Sstevel@tonic-gate 	detach_devlist = NULL;
3589*7c478bd9Sstevel@tonic-gate 
3590*7c478bd9Sstevel@tonic-gate 	/*
3591*7c478bd9Sstevel@tonic-gate 	 * We switch on next_pass for the cases where a board
3592*7c478bd9Sstevel@tonic-gate 	 * does not contain a particular type of component.
3593*7c478bd9Sstevel@tonic-gate 	 * In these situations we don't want to return NULL
3594*7c478bd9Sstevel@tonic-gate 	 * prematurely.  We need to check other devices and
3595*7c478bd9Sstevel@tonic-gate 	 * we don't want to check the same type multiple times.
3596*7c478bd9Sstevel@tonic-gate 	 * For example, if there were no cpus, then on pass 1
3597*7c478bd9Sstevel@tonic-gate 	 * we would drop through and return the memory nodes.
3598*7c478bd9Sstevel@tonic-gate 	 * However, on pass 2 we would switch back to the memory
3599*7c478bd9Sstevel@tonic-gate 	 * nodes thereby returning them twice!  Using next_pass
3600*7c478bd9Sstevel@tonic-gate 	 * forces us down to the end (or next item).
3601*7c478bd9Sstevel@tonic-gate 	 */
3602*7c478bd9Sstevel@tonic-gate 	if (pass == 1)
3603*7c478bd9Sstevel@tonic-gate 		next_pass = 1;
3604*7c478bd9Sstevel@tonic-gate 
3605*7c478bd9Sstevel@tonic-gate 	switch (next_pass) {
3606*7c478bd9Sstevel@tonic-gate 	case 1:
3607*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) {
3608*7c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM);
3609*7c478bd9Sstevel@tonic-gate 
3610*7c478bd9Sstevel@tonic-gate 			detach_devlist = sbd_get_devlist(hp, sbp,
3611*7c478bd9Sstevel@tonic-gate 						SBD_COMP_MEM,
3612*7c478bd9Sstevel@tonic-gate 						MAX_MEM_UNITS_PER_BOARD,
3613*7c478bd9Sstevel@tonic-gate 						uset, devnump, 0);
3614*7c478bd9Sstevel@tonic-gate 
3615*7c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT);
3616*7c478bd9Sstevel@tonic-gate 			if (!devset || detach_devlist) {
3617*7c478bd9Sstevel@tonic-gate 				next_pass = 2;
3618*7c478bd9Sstevel@tonic-gate 				return (detach_devlist);
3619*7c478bd9Sstevel@tonic-gate 			}
3620*7c478bd9Sstevel@tonic-gate 			/*
3621*7c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
3622*7c478bd9Sstevel@tonic-gate 			 * board, but there isn't any memory, then
3623*7c478bd9Sstevel@tonic-gate 			 * just fall through to next component.
3624*7c478bd9Sstevel@tonic-gate 			 */
3625*7c478bd9Sstevel@tonic-gate 		}
3626*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
3627*7c478bd9Sstevel@tonic-gate 
3628*7c478bd9Sstevel@tonic-gate 	case 2:
3629*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) {
3630*7c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU);
3631*7c478bd9Sstevel@tonic-gate 
3632*7c478bd9Sstevel@tonic-gate 			detach_devlist = sbd_get_devlist(hp, sbp,
3633*7c478bd9Sstevel@tonic-gate 						SBD_COMP_CPU,
3634*7c478bd9Sstevel@tonic-gate 						MAX_CPU_UNITS_PER_BOARD,
3635*7c478bd9Sstevel@tonic-gate 						uset, devnump, 0);
3636*7c478bd9Sstevel@tonic-gate 
3637*7c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT);
3638*7c478bd9Sstevel@tonic-gate 			if (!devset || detach_devlist) {
3639*7c478bd9Sstevel@tonic-gate 				next_pass = 2;
3640*7c478bd9Sstevel@tonic-gate 				return (detach_devlist);
3641*7c478bd9Sstevel@tonic-gate 			}
3642*7c478bd9Sstevel@tonic-gate 			/*
3643*7c478bd9Sstevel@tonic-gate 			 * If the caller is interested in the entire
3644*7c478bd9Sstevel@tonic-gate 			 * board, but there aren't any cpus, then just
3645*7c478bd9Sstevel@tonic-gate 			 * fall through to check for the next component.
3646*7c478bd9Sstevel@tonic-gate 			 */
3647*7c478bd9Sstevel@tonic-gate 		}
3648*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
3649*7c478bd9Sstevel@tonic-gate 
3650*7c478bd9Sstevel@tonic-gate 	case 3:
3651*7c478bd9Sstevel@tonic-gate 		next_pass = -1;
3652*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) {
3653*7c478bd9Sstevel@tonic-gate 			uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO);
3654*7c478bd9Sstevel@tonic-gate 
3655*7c478bd9Sstevel@tonic-gate 			detach_devlist = sbd_get_devlist(hp, sbp,
3656*7c478bd9Sstevel@tonic-gate 						SBD_COMP_IO,
3657*7c478bd9Sstevel@tonic-gate 						MAX_IO_UNITS_PER_BOARD,
3658*7c478bd9Sstevel@tonic-gate 						uset, devnump, 0);
3659*7c478bd9Sstevel@tonic-gate 
3660*7c478bd9Sstevel@tonic-gate 			DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT);
3661*7c478bd9Sstevel@tonic-gate 			if (!devset || detach_devlist) {
3662*7c478bd9Sstevel@tonic-gate 				next_pass = 4;
3663*7c478bd9Sstevel@tonic-gate 				return (detach_devlist);
3664*7c478bd9Sstevel@tonic-gate 			}
3665*7c478bd9Sstevel@tonic-gate 		}
3666*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
3667*7c478bd9Sstevel@tonic-gate 
3668*7c478bd9Sstevel@tonic-gate 	default:
3669*7c478bd9Sstevel@tonic-gate 		*devnump = 0;
3670*7c478bd9Sstevel@tonic-gate 		return (NULL);
3671*7c478bd9Sstevel@tonic-gate 	}
3672*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3673*7c478bd9Sstevel@tonic-gate }
3674*7c478bd9Sstevel@tonic-gate 
3675*7c478bd9Sstevel@tonic-gate static int
3676*7c478bd9Sstevel@tonic-gate sbd_pre_detach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist,
3677*7c478bd9Sstevel@tonic-gate 	int32_t devnum)
3678*7c478bd9Sstevel@tonic-gate {
3679*7c478bd9Sstevel@tonic-gate 	int		rv = 0;
3680*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
3681*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_pre_detach_devlist";
3682*7c478bd9Sstevel@tonic-gate 
3683*7c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
3684*7c478bd9Sstevel@tonic-gate 
3685*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3686*7c478bd9Sstevel@tonic-gate 		f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
3687*7c478bd9Sstevel@tonic-gate 
3688*7c478bd9Sstevel@tonic-gate 	switch (nodetype) {
3689*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
3690*7c478bd9Sstevel@tonic-gate 		rv = sbd_pre_detach_cpu(hp, devlist, devnum);
3691*7c478bd9Sstevel@tonic-gate 		break;
3692*7c478bd9Sstevel@tonic-gate 
3693*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
3694*7c478bd9Sstevel@tonic-gate 		rv = sbd_pre_detach_mem(hp, devlist, devnum);
3695*7c478bd9Sstevel@tonic-gate 		break;
3696*7c478bd9Sstevel@tonic-gate 
3697*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
3698*7c478bd9Sstevel@tonic-gate 		rv = sbd_pre_detach_io(hp, devlist, devnum);
3699*7c478bd9Sstevel@tonic-gate 		break;
3700*7c478bd9Sstevel@tonic-gate 
3701*7c478bd9Sstevel@tonic-gate 	default:
3702*7c478bd9Sstevel@tonic-gate 		rv = -1;
3703*7c478bd9Sstevel@tonic-gate 		break;
3704*7c478bd9Sstevel@tonic-gate 	}
3705*7c478bd9Sstevel@tonic-gate 
3706*7c478bd9Sstevel@tonic-gate 	/*
3707*7c478bd9Sstevel@tonic-gate 	 * We want to continue attempting to detach
3708*7c478bd9Sstevel@tonic-gate 	 * other components.
3709*7c478bd9Sstevel@tonic-gate 	 */
3710*7c478bd9Sstevel@tonic-gate 	return (rv);
3711*7c478bd9Sstevel@tonic-gate }
3712*7c478bd9Sstevel@tonic-gate 
3713*7c478bd9Sstevel@tonic-gate static int
3714*7c478bd9Sstevel@tonic-gate sbd_post_detach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist,
3715*7c478bd9Sstevel@tonic-gate 			int32_t devnum)
3716*7c478bd9Sstevel@tonic-gate {
3717*7c478bd9Sstevel@tonic-gate 	int		i, max_units = 0, rv = 0;
3718*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t	nodetype;
3719*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
3720*7c478bd9Sstevel@tonic-gate 	sbd_istate_t	bstate;
3721*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_post_detach_devlist";
3722*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
3723*7c478bd9Sstevel@tonic-gate 
3724*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
3725*7c478bd9Sstevel@tonic-gate 	nodetype = sbd_get_devtype(hp, devlist->dv_dip);
3726*7c478bd9Sstevel@tonic-gate 
3727*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
3728*7c478bd9Sstevel@tonic-gate 
3729*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s (nt = %s(%d), num = %d)...\n",
3730*7c478bd9Sstevel@tonic-gate 		f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum);
3731*7c478bd9Sstevel@tonic-gate 
3732*7c478bd9Sstevel@tonic-gate 	/*
3733*7c478bd9Sstevel@tonic-gate 	 * Need to free up devlist[] created earlier in
3734*7c478bd9Sstevel@tonic-gate 	 * sbd_get_detach_devlist().
3735*7c478bd9Sstevel@tonic-gate 	 */
3736*7c478bd9Sstevel@tonic-gate 	switch (nodetype) {
3737*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
3738*7c478bd9Sstevel@tonic-gate 		max_units = MAX_CPU_UNITS_PER_BOARD;
3739*7c478bd9Sstevel@tonic-gate 		rv = sbd_post_detach_cpu(hp, devlist, devnum);
3740*7c478bd9Sstevel@tonic-gate 		break;
3741*7c478bd9Sstevel@tonic-gate 
3742*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
3743*7c478bd9Sstevel@tonic-gate 		max_units = MAX_MEM_UNITS_PER_BOARD;
3744*7c478bd9Sstevel@tonic-gate 		rv = sbd_post_detach_mem(hp, devlist, devnum);
3745*7c478bd9Sstevel@tonic-gate 		break;
3746*7c478bd9Sstevel@tonic-gate 
3747*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
3748*7c478bd9Sstevel@tonic-gate 		max_units = MAX_IO_UNITS_PER_BOARD;
3749*7c478bd9Sstevel@tonic-gate 		rv = sbd_post_detach_io(hp, devlist, devnum);
3750*7c478bd9Sstevel@tonic-gate 		break;
3751*7c478bd9Sstevel@tonic-gate 
3752*7c478bd9Sstevel@tonic-gate 	default:
3753*7c478bd9Sstevel@tonic-gate 		rv = -1;
3754*7c478bd9Sstevel@tonic-gate 		break;
3755*7c478bd9Sstevel@tonic-gate 	}
3756*7c478bd9Sstevel@tonic-gate 
3757*7c478bd9Sstevel@tonic-gate 
3758*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
3759*7c478bd9Sstevel@tonic-gate 		int		unit;
3760*7c478bd9Sstevel@tonic-gate 		sbderror_t	*ep;
3761*7c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
3762*7c478bd9Sstevel@tonic-gate 
3763*7c478bd9Sstevel@tonic-gate 		ep = &devlist[i].dv_error;
3764*7c478bd9Sstevel@tonic-gate 
3765*7c478bd9Sstevel@tonic-gate 		if (sbd_set_err_in_hdl(hp, ep) == 0)
3766*7c478bd9Sstevel@tonic-gate 			continue;
3767*7c478bd9Sstevel@tonic-gate 
3768*7c478bd9Sstevel@tonic-gate 		dip = devlist[i].dv_dip;
3769*7c478bd9Sstevel@tonic-gate 		unit = sbdp_get_unit_num(hdp, dip);
3770*7c478bd9Sstevel@tonic-gate 		if (unit == -1) {
3771*7c478bd9Sstevel@tonic-gate 			if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
3772*7c478bd9Sstevel@tonic-gate 				continue;
3773*7c478bd9Sstevel@tonic-gate 			else {
3774*7c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, ep);
3775*7c478bd9Sstevel@tonic-gate 				break;
3776*7c478bd9Sstevel@tonic-gate 			}
3777*7c478bd9Sstevel@tonic-gate 		}
3778*7c478bd9Sstevel@tonic-gate 		nodetype = sbd_get_devtype(hp, dip);
3779*7c478bd9Sstevel@tonic-gate 
3780*7c478bd9Sstevel@tonic-gate 		if (sbd_check_unit_attached(sbp, dip, unit, nodetype,
3781*7c478bd9Sstevel@tonic-gate 		    ep) >= 0) {
3782*7c478bd9Sstevel@tonic-gate 			/*
3783*7c478bd9Sstevel@tonic-gate 			 * Device is still attached probably due
3784*7c478bd9Sstevel@tonic-gate 			 * to an error.  Need to keep track of it.
3785*7c478bd9Sstevel@tonic-gate 			 */
3786*7c478bd9Sstevel@tonic-gate 			PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not detached\n",
3787*7c478bd9Sstevel@tonic-gate 				f, sbd_ct_str[(int)nodetype], sbp->sb_num,
3788*7c478bd9Sstevel@tonic-gate 				unit);
3789*7c478bd9Sstevel@tonic-gate 			continue;
3790*7c478bd9Sstevel@tonic-gate 		}
3791*7c478bd9Sstevel@tonic-gate 
3792*7c478bd9Sstevel@tonic-gate 		SBD_DEV_CLR_ATTACHED(sbp, nodetype, unit);
3793*7c478bd9Sstevel@tonic-gate 		SBD_DEV_CLR_RELEASED(sbp, nodetype, unit);
3794*7c478bd9Sstevel@tonic-gate 		SBD_DEV_CLR_UNREFERENCED(sbp, nodetype, unit);
3795*7c478bd9Sstevel@tonic-gate 		SBD_DEVICE_TRANSITION(sbp, nodetype, unit,
3796*7c478bd9Sstevel@tonic-gate 						SBD_STATE_UNCONFIGURED);
3797*7c478bd9Sstevel@tonic-gate 	}
3798*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
3799*7c478bd9Sstevel@tonic-gate 
3800*7c478bd9Sstevel@tonic-gate 	bstate = SBD_BOARD_STATE(sbp);
3801*7c478bd9Sstevel@tonic-gate 	if (bstate != SBD_STATE_UNCONFIGURED) {
3802*7c478bd9Sstevel@tonic-gate 		if (SBD_DEVS_PRESENT(sbp) == SBD_DEVS_UNATTACHED(sbp)) {
3803*7c478bd9Sstevel@tonic-gate 			/*
3804*7c478bd9Sstevel@tonic-gate 			 * All devices are finally detached.
3805*7c478bd9Sstevel@tonic-gate 			 */
3806*7c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_UNCONFIGURED);
3807*7c478bd9Sstevel@tonic-gate 		} else if ((SBD_BOARD_STATE(sbp) != SBD_STATE_PARTIAL) &&
3808*7c478bd9Sstevel@tonic-gate 				SBD_DEVS_ATTACHED(sbp)) {
3809*7c478bd9Sstevel@tonic-gate 			/*
3810*7c478bd9Sstevel@tonic-gate 			 * Some devices remain attached.
3811*7c478bd9Sstevel@tonic-gate 			 */
3812*7c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL);
3813*7c478bd9Sstevel@tonic-gate 		}
3814*7c478bd9Sstevel@tonic-gate 	}
3815*7c478bd9Sstevel@tonic-gate 
3816*7c478bd9Sstevel@tonic-gate 	if (rv) {
3817*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s: errno %d, ecode %d during detach\n",
3818*7c478bd9Sstevel@tonic-gate 			f, SBD_GET_ERRNO(SBD_HD2ERR(hp)),
3819*7c478bd9Sstevel@tonic-gate 			SBD_GET_ERR(HD2MACHERR(hp)));
3820*7c478bd9Sstevel@tonic-gate 	}
3821*7c478bd9Sstevel@tonic-gate 
3822*7c478bd9Sstevel@tonic-gate 	if (max_units && devlist) {
3823*7c478bd9Sstevel@tonic-gate 		int	i;
3824*7c478bd9Sstevel@tonic-gate 
3825*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_units; i++) {
3826*7c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERRSTR(&devlist[i].dv_error)) {
3827*7c478bd9Sstevel@tonic-gate 				SBD_FREE_ERR(&devlist[i].dv_error);
3828*7c478bd9Sstevel@tonic-gate 			} else {
3829*7c478bd9Sstevel@tonic-gate 				break;
3830*7c478bd9Sstevel@tonic-gate 			}
3831*7c478bd9Sstevel@tonic-gate 		}
3832*7c478bd9Sstevel@tonic-gate 		FREESTRUCT(devlist, sbd_devlist_t, max_units);
3833*7c478bd9Sstevel@tonic-gate 	}
3834*7c478bd9Sstevel@tonic-gate 
3835*7c478bd9Sstevel@tonic-gate 	return (SBD_GET_ERRNO(SBD_HD2ERR(hp)) ? -1 : 0);
3836*7c478bd9Sstevel@tonic-gate }
3837*7c478bd9Sstevel@tonic-gate 
3838*7c478bd9Sstevel@tonic-gate /*
3839*7c478bd9Sstevel@tonic-gate  * Return the unit number of the respective dip if
3840*7c478bd9Sstevel@tonic-gate  * it's found to be attached.
3841*7c478bd9Sstevel@tonic-gate  */
3842*7c478bd9Sstevel@tonic-gate static int
3843*7c478bd9Sstevel@tonic-gate sbd_check_unit_attached(sbd_board_t *sbp, dev_info_t *dip, int unit,
3844*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t nodetype, sbderror_t *ep)
3845*7c478bd9Sstevel@tonic-gate {
3846*7c478bd9Sstevel@tonic-gate 	int		rv = -1;
3847*7c478bd9Sstevel@tonic-gate 	processorid_t	cpuid;
3848*7c478bd9Sstevel@tonic-gate 	uint64_t	basepa, endpa;
3849*7c478bd9Sstevel@tonic-gate 	struct memlist	*ml;
3850*7c478bd9Sstevel@tonic-gate 	extern struct memlist	*phys_install;
3851*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
3852*7c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp = MACHBD2HD(sbp);
3853*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_check_unit_attached";
3854*7c478bd9Sstevel@tonic-gate 
3855*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
3856*7c478bd9Sstevel@tonic-gate 
3857*7c478bd9Sstevel@tonic-gate 	switch (nodetype) {
3858*7c478bd9Sstevel@tonic-gate 
3859*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_CPU:
3860*7c478bd9Sstevel@tonic-gate 		cpuid = sbdp_get_cpuid(hdp, dip);
3861*7c478bd9Sstevel@tonic-gate 		if (cpuid < 0) {
3862*7c478bd9Sstevel@tonic-gate 			break;
3863*7c478bd9Sstevel@tonic-gate 		}
3864*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
3865*7c478bd9Sstevel@tonic-gate 		if (cpu_get(cpuid) != NULL)
3866*7c478bd9Sstevel@tonic-gate 			rv = unit;
3867*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
3868*7c478bd9Sstevel@tonic-gate 		break;
3869*7c478bd9Sstevel@tonic-gate 
3870*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_MEM:
3871*7c478bd9Sstevel@tonic-gate 		if (sbdphw_get_base_physaddr(hdp, dip, &basepa)) {
3872*7c478bd9Sstevel@tonic-gate 			break;
3873*7c478bd9Sstevel@tonic-gate 		}
3874*7c478bd9Sstevel@tonic-gate 		if (sbdp_get_mem_alignment(hdp, dip, &endpa)) {
3875*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s sbdp_get_mem_alignment fail", f);
3876*7c478bd9Sstevel@tonic-gate 			break;
3877*7c478bd9Sstevel@tonic-gate 		}
3878*7c478bd9Sstevel@tonic-gate 
3879*7c478bd9Sstevel@tonic-gate 		basepa &= ~(endpa - 1);
3880*7c478bd9Sstevel@tonic-gate 		endpa += basepa;
3881*7c478bd9Sstevel@tonic-gate 		/*
3882*7c478bd9Sstevel@tonic-gate 		 * Check if base address is in phys_install.
3883*7c478bd9Sstevel@tonic-gate 		 */
3884*7c478bd9Sstevel@tonic-gate 		memlist_read_lock();
3885*7c478bd9Sstevel@tonic-gate 		for (ml = phys_install; ml; ml = ml->next)
3886*7c478bd9Sstevel@tonic-gate 			if ((endpa <= ml->address) ||
3887*7c478bd9Sstevel@tonic-gate 					(basepa >= (ml->address + ml->size)))
3888*7c478bd9Sstevel@tonic-gate 				continue;
3889*7c478bd9Sstevel@tonic-gate 			else
3890*7c478bd9Sstevel@tonic-gate 				break;
3891*7c478bd9Sstevel@tonic-gate 		memlist_read_unlock();
3892*7c478bd9Sstevel@tonic-gate 		if (ml != NULL)
3893*7c478bd9Sstevel@tonic-gate 			rv = unit;
3894*7c478bd9Sstevel@tonic-gate 		break;
3895*7c478bd9Sstevel@tonic-gate 
3896*7c478bd9Sstevel@tonic-gate 	case SBD_COMP_IO:
3897*7c478bd9Sstevel@tonic-gate 	{
3898*7c478bd9Sstevel@tonic-gate 		dev_info_t	*tdip, *pdip;
3899*7c478bd9Sstevel@tonic-gate 
3900*7c478bd9Sstevel@tonic-gate 		tdip = dip;
3901*7c478bd9Sstevel@tonic-gate 
3902*7c478bd9Sstevel@tonic-gate 		/*
3903*7c478bd9Sstevel@tonic-gate 		 * ddi_walk_devs() requires that topdip's parent be held.
3904*7c478bd9Sstevel@tonic-gate 		 */
3905*7c478bd9Sstevel@tonic-gate 		pdip = ddi_get_parent(sbp->sb_topdip);
3906*7c478bd9Sstevel@tonic-gate 		if (pdip) {
3907*7c478bd9Sstevel@tonic-gate 			ndi_hold_devi(pdip);
3908*7c478bd9Sstevel@tonic-gate 			ndi_devi_enter(pdip, &rv);
3909*7c478bd9Sstevel@tonic-gate 		}
3910*7c478bd9Sstevel@tonic-gate 		ddi_walk_devs(sbp->sb_topdip, sbd_check_io_attached,
3911*7c478bd9Sstevel@tonic-gate 			(void *)&tdip);
3912*7c478bd9Sstevel@tonic-gate 		if (pdip) {
3913*7c478bd9Sstevel@tonic-gate 			ndi_devi_exit(pdip, rv);
3914*7c478bd9Sstevel@tonic-gate 			ndi_rele_devi(pdip);
3915*7c478bd9Sstevel@tonic-gate 		}
3916*7c478bd9Sstevel@tonic-gate 
3917*7c478bd9Sstevel@tonic-gate 		if (tdip == NULL)
3918*7c478bd9Sstevel@tonic-gate 			rv = unit;
3919*7c478bd9Sstevel@tonic-gate 		else
3920*7c478bd9Sstevel@tonic-gate 			rv = -1;
3921*7c478bd9Sstevel@tonic-gate 		break;
3922*7c478bd9Sstevel@tonic-gate 	}
3923*7c478bd9Sstevel@tonic-gate 
3924*7c478bd9Sstevel@tonic-gate 	default:
3925*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s: unexpected nodetype(%d) for dip 0x%p\n",
3926*7c478bd9Sstevel@tonic-gate 			f, nodetype, (void *)dip);
3927*7c478bd9Sstevel@tonic-gate 		rv = -1;
3928*7c478bd9Sstevel@tonic-gate 		break;
3929*7c478bd9Sstevel@tonic-gate 	}
3930*7c478bd9Sstevel@tonic-gate 
3931*7c478bd9Sstevel@tonic-gate 	/*
3932*7c478bd9Sstevel@tonic-gate 	 * Save the error that sbdp sent us and report it
3933*7c478bd9Sstevel@tonic-gate 	 */
3934*7c478bd9Sstevel@tonic-gate 	if (rv == -1)
3935*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
3936*7c478bd9Sstevel@tonic-gate 
3937*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
3938*7c478bd9Sstevel@tonic-gate 
3939*7c478bd9Sstevel@tonic-gate 	return (rv);
3940*7c478bd9Sstevel@tonic-gate }
3941*7c478bd9Sstevel@tonic-gate 
3942*7c478bd9Sstevel@tonic-gate /*
3943*7c478bd9Sstevel@tonic-gate  * Return memhandle, if in fact, this memunit is the owner of
3944*7c478bd9Sstevel@tonic-gate  * a scheduled memory delete.
3945*7c478bd9Sstevel@tonic-gate  */
3946*7c478bd9Sstevel@tonic-gate int
3947*7c478bd9Sstevel@tonic-gate sbd_get_memhandle(sbd_handle_t *hp, dev_info_t *dip, memhandle_t *mhp)
3948*7c478bd9Sstevel@tonic-gate {
3949*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
3950*7c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
3951*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
3952*7c478bd9Sstevel@tonic-gate 	int		unit;
3953*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_get_memhandle";
3954*7c478bd9Sstevel@tonic-gate 
3955*7c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
3956*7c478bd9Sstevel@tonic-gate 
3957*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
3958*7c478bd9Sstevel@tonic-gate 
3959*7c478bd9Sstevel@tonic-gate 	unit = sbdp_get_unit_num(hdp, dip);
3960*7c478bd9Sstevel@tonic-gate 	if (unit == -1) {
3961*7c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
3962*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
3963*7c478bd9Sstevel@tonic-gate 		return (-1);
3964*7c478bd9Sstevel@tonic-gate 	}
3965*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
3966*7c478bd9Sstevel@tonic-gate 
3967*7c478bd9Sstevel@tonic-gate 	mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
3968*7c478bd9Sstevel@tonic-gate 
3969*7c478bd9Sstevel@tonic-gate 	if (mp->sbm_flags & SBD_MFLAG_RELOWNER) {
3970*7c478bd9Sstevel@tonic-gate 		*mhp = mp->sbm_memhandle;
3971*7c478bd9Sstevel@tonic-gate 		return (0);
3972*7c478bd9Sstevel@tonic-gate 	} else {
3973*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(SBD_HD2ERR(hp), ESBD_INTERNAL);
3974*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(SBD_HD2ERR(hp), sbp->sb_mempath[unit]);
3975*7c478bd9Sstevel@tonic-gate 		return (-1);
3976*7c478bd9Sstevel@tonic-gate 	}
3977*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3978*7c478bd9Sstevel@tonic-gate }
3979*7c478bd9Sstevel@tonic-gate 
3980*7c478bd9Sstevel@tonic-gate 
3981*7c478bd9Sstevel@tonic-gate static int
3982*7c478bd9Sstevel@tonic-gate sbd_cpu_cnt(sbd_handle_t *hp, sbd_devset_t devset)
3983*7c478bd9Sstevel@tonic-gate {
3984*7c478bd9Sstevel@tonic-gate 	int		c, cix;
3985*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
3986*7c478bd9Sstevel@tonic-gate 
3987*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
3988*7c478bd9Sstevel@tonic-gate 
3989*7c478bd9Sstevel@tonic-gate 	/*
3990*7c478bd9Sstevel@tonic-gate 	 * Only look for requested devices that are actually present.
3991*7c478bd9Sstevel@tonic-gate 	 */
3992*7c478bd9Sstevel@tonic-gate 	devset &= SBD_DEVS_PRESENT(sbp);
3993*7c478bd9Sstevel@tonic-gate 
3994*7c478bd9Sstevel@tonic-gate 	for (c = cix = 0; c < MAX_CMP_UNITS_PER_BOARD; c++) {
3995*7c478bd9Sstevel@tonic-gate 		/*
3996*7c478bd9Sstevel@tonic-gate 		 * Index for core 1 , if exists.
3997*7c478bd9Sstevel@tonic-gate 		 * With the current implementation it is
3998*7c478bd9Sstevel@tonic-gate 		 * MAX_CMP_UNITS_PER_BOARD off from core 0.
3999*7c478bd9Sstevel@tonic-gate 		 * The calculation will need to change if
4000*7c478bd9Sstevel@tonic-gate 		 * the assumption is no longer true.
4001*7c478bd9Sstevel@tonic-gate 		 */
4002*7c478bd9Sstevel@tonic-gate 		int		c1 = c + MAX_CMP_UNITS_PER_BOARD;
4003*7c478bd9Sstevel@tonic-gate 
4004*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_CMP, c) == 0) {
4005*7c478bd9Sstevel@tonic-gate 			continue;
4006*7c478bd9Sstevel@tonic-gate 		}
4007*7c478bd9Sstevel@tonic-gate 
4008*7c478bd9Sstevel@tonic-gate 		/*
4009*7c478bd9Sstevel@tonic-gate 		 * Check to see if the dip(s) exist for this chip
4010*7c478bd9Sstevel@tonic-gate 		 */
4011*7c478bd9Sstevel@tonic-gate 		if ((sbp->sb_devlist[NIX(SBD_COMP_CMP)][c] == NULL) &&
4012*7c478bd9Sstevel@tonic-gate 		    (sbp->sb_devlist[NIX(SBD_COMP_CMP)][c1] == NULL))
4013*7c478bd9Sstevel@tonic-gate 			continue;
4014*7c478bd9Sstevel@tonic-gate 
4015*7c478bd9Sstevel@tonic-gate 		cix++;
4016*7c478bd9Sstevel@tonic-gate 	}
4017*7c478bd9Sstevel@tonic-gate 
4018*7c478bd9Sstevel@tonic-gate 	return (cix);
4019*7c478bd9Sstevel@tonic-gate }
4020*7c478bd9Sstevel@tonic-gate 
4021*7c478bd9Sstevel@tonic-gate static int
4022*7c478bd9Sstevel@tonic-gate sbd_mem_cnt(sbd_handle_t *hp, sbd_devset_t devset)
4023*7c478bd9Sstevel@tonic-gate {
4024*7c478bd9Sstevel@tonic-gate 	int		i, ix;
4025*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
4026*7c478bd9Sstevel@tonic-gate 
4027*7c478bd9Sstevel@tonic-gate 	/*
4028*7c478bd9Sstevel@tonic-gate 	 * Only look for requested devices that are actually present.
4029*7c478bd9Sstevel@tonic-gate 	 */
4030*7c478bd9Sstevel@tonic-gate 	devset &= SBD_DEVS_PRESENT(sbp);
4031*7c478bd9Sstevel@tonic-gate 
4032*7c478bd9Sstevel@tonic-gate 	for (i = ix = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
4033*7c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
4034*7c478bd9Sstevel@tonic-gate 
4035*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i) == 0) {
4036*7c478bd9Sstevel@tonic-gate 			continue;
4037*7c478bd9Sstevel@tonic-gate 		}
4038*7c478bd9Sstevel@tonic-gate 
4039*7c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][i];
4040*7c478bd9Sstevel@tonic-gate 		if (dip == NULL)
4041*7c478bd9Sstevel@tonic-gate 			continue;
4042*7c478bd9Sstevel@tonic-gate 
4043*7c478bd9Sstevel@tonic-gate 		ix++;
4044*7c478bd9Sstevel@tonic-gate 	}
4045*7c478bd9Sstevel@tonic-gate 
4046*7c478bd9Sstevel@tonic-gate 	return (ix);
4047*7c478bd9Sstevel@tonic-gate }
4048*7c478bd9Sstevel@tonic-gate 
4049*7c478bd9Sstevel@tonic-gate /*
4050*7c478bd9Sstevel@tonic-gate  * NOTE: This routine is only partially smart about multiple
4051*7c478bd9Sstevel@tonic-gate  *	 mem-units.  Need to make mem-status structure smart
4052*7c478bd9Sstevel@tonic-gate  *	 about them also.
4053*7c478bd9Sstevel@tonic-gate  */
4054*7c478bd9Sstevel@tonic-gate static int
4055*7c478bd9Sstevel@tonic-gate sbd_mem_status(sbd_handle_t *hp, sbd_devset_t devset, sbd_dev_stat_t *dsp)
4056*7c478bd9Sstevel@tonic-gate {
4057*7c478bd9Sstevel@tonic-gate 	int		m, mix, rv;
4058*7c478bd9Sstevel@tonic-gate 	memdelstat_t	mdst;
4059*7c478bd9Sstevel@tonic-gate 	memquery_t	mq;
4060*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
4061*7c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
4062*7c478bd9Sstevel@tonic-gate 	sbd_mem_stat_t	*msp;
4063*7c478bd9Sstevel@tonic-gate 	extern int	kcage_on;
4064*7c478bd9Sstevel@tonic-gate 	int		i;
4065*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_mem_status";
4066*7c478bd9Sstevel@tonic-gate 
4067*7c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
4068*7c478bd9Sstevel@tonic-gate 
4069*7c478bd9Sstevel@tonic-gate 	/*
4070*7c478bd9Sstevel@tonic-gate 	 * Check the present devset and access the dip with
4071*7c478bd9Sstevel@tonic-gate 	 * status lock held to protect agains a concurrent
4072*7c478bd9Sstevel@tonic-gate 	 * unconfigure or disconnect thread.
4073*7c478bd9Sstevel@tonic-gate 	 */
4074*7c478bd9Sstevel@tonic-gate 	mutex_enter(&sbp->sb_slock);
4075*7c478bd9Sstevel@tonic-gate 
4076*7c478bd9Sstevel@tonic-gate 	/*
4077*7c478bd9Sstevel@tonic-gate 	 * Only look for requested devices that are actually present.
4078*7c478bd9Sstevel@tonic-gate 	 */
4079*7c478bd9Sstevel@tonic-gate 	devset &= SBD_DEVS_PRESENT(sbp);
4080*7c478bd9Sstevel@tonic-gate 
4081*7c478bd9Sstevel@tonic-gate 	for (m = mix = 0; m < MAX_MEM_UNITS_PER_BOARD; m++) {
4082*7c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
4083*7c478bd9Sstevel@tonic-gate 
4084*7c478bd9Sstevel@tonic-gate 
4085*7c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_MEM, m) == 0)
4086*7c478bd9Sstevel@tonic-gate 			continue;
4087*7c478bd9Sstevel@tonic-gate 
4088*7c478bd9Sstevel@tonic-gate 		/*
4089*7c478bd9Sstevel@tonic-gate 		 * Check to make sure the memory unit is in a state
4090*7c478bd9Sstevel@tonic-gate 		 * where its fully initialized.
4091*7c478bd9Sstevel@tonic-gate 		 */
4092*7c478bd9Sstevel@tonic-gate 		if (SBD_DEVICE_STATE(sbp, SBD_COMP_MEM, m) == SBD_STATE_EMPTY)
4093*7c478bd9Sstevel@tonic-gate 			continue;
4094*7c478bd9Sstevel@tonic-gate 
4095*7c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][m];
4096*7c478bd9Sstevel@tonic-gate 		if (dip == NULL)
4097*7c478bd9Sstevel@tonic-gate 			continue;
4098*7c478bd9Sstevel@tonic-gate 
4099*7c478bd9Sstevel@tonic-gate 		mp = SBD_GET_BOARD_MEMUNIT(sbp, m);
4100*7c478bd9Sstevel@tonic-gate 
4101*7c478bd9Sstevel@tonic-gate 		msp = &dsp->d_mem;
4102*7c478bd9Sstevel@tonic-gate 
4103*7c478bd9Sstevel@tonic-gate 		bzero((caddr_t)msp, sizeof (*msp));
4104*7c478bd9Sstevel@tonic-gate 		msp->ms_type = SBD_COMP_MEM;
4105*7c478bd9Sstevel@tonic-gate 
4106*7c478bd9Sstevel@tonic-gate 		/*
4107*7c478bd9Sstevel@tonic-gate 		 * The plugin expects -1 for the mem unit
4108*7c478bd9Sstevel@tonic-gate 		 */
4109*7c478bd9Sstevel@tonic-gate 		msp->ms_cm.c_id.c_unit = -1;
4110*7c478bd9Sstevel@tonic-gate 
4111*7c478bd9Sstevel@tonic-gate 		/*
4112*7c478bd9Sstevel@tonic-gate 		 * Get the memory name from what sbdp gave us
4113*7c478bd9Sstevel@tonic-gate 		 */
4114*7c478bd9Sstevel@tonic-gate 		for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) {
4115*7c478bd9Sstevel@tonic-gate 			if (SBD_COMP(i) == SBD_COMP_MEM) {
4116*7c478bd9Sstevel@tonic-gate 				(void) strcpy(msp->ms_name, SBD_DEVNAME(i));
4117*7c478bd9Sstevel@tonic-gate 			}
4118*7c478bd9Sstevel@tonic-gate 		}
4119*7c478bd9Sstevel@tonic-gate 		msp->ms_cm.c_cond = mp->sbm_cm.sbdev_cond;
4120*7c478bd9Sstevel@tonic-gate 		msp->ms_cm.c_busy = mp->sbm_cm.sbdev_busy;
4121*7c478bd9Sstevel@tonic-gate 		msp->ms_cm.c_time = mp->sbm_cm.sbdev_time;
4122*7c478bd9Sstevel@tonic-gate 
4123*7c478bd9Sstevel@tonic-gate 		/* XXX revisit this after memory conversion */
4124*7c478bd9Sstevel@tonic-gate 		msp->ms_ostate = ostate_cvt(SBD_DEVICE_STATE(
4125*7c478bd9Sstevel@tonic-gate 			sbp, SBD_COMP_MEM, m));
4126*7c478bd9Sstevel@tonic-gate 
4127*7c478bd9Sstevel@tonic-gate 		msp->ms_basepfn = mp->sbm_basepfn;
4128*7c478bd9Sstevel@tonic-gate 		msp->ms_pageslost = mp->sbm_pageslost;
4129*7c478bd9Sstevel@tonic-gate 		msp->ms_cage_enabled = kcage_on;
4130*7c478bd9Sstevel@tonic-gate 		msp->ms_interleave = mp->sbm_interleave;
4131*7c478bd9Sstevel@tonic-gate 
4132*7c478bd9Sstevel@tonic-gate 		if (mp->sbm_flags & SBD_MFLAG_RELOWNER)
4133*7c478bd9Sstevel@tonic-gate 			rv = kphysm_del_status(mp->sbm_memhandle, &mdst);
4134*7c478bd9Sstevel@tonic-gate 		else
4135*7c478bd9Sstevel@tonic-gate 			rv = KPHYSM_EHANDLE;	/* force 'if' to fail */
4136*7c478bd9Sstevel@tonic-gate 
4137*7c478bd9Sstevel@tonic-gate 		if (rv == KPHYSM_OK) {
4138*7c478bd9Sstevel@tonic-gate 			msp->ms_totpages += mdst.phys_pages;
4139*7c478bd9Sstevel@tonic-gate 
4140*7c478bd9Sstevel@tonic-gate 			/*
4141*7c478bd9Sstevel@tonic-gate 			 * Any pages above managed is "free",
4142*7c478bd9Sstevel@tonic-gate 			 * i.e. it's collected.
4143*7c478bd9Sstevel@tonic-gate 			 */
4144*7c478bd9Sstevel@tonic-gate 			msp->ms_detpages += (uint_t)(mdst.collected +
4145*7c478bd9Sstevel@tonic-gate 							mdst.phys_pages -
4146*7c478bd9Sstevel@tonic-gate 							mdst.managed);
4147*7c478bd9Sstevel@tonic-gate 		} else {
4148*7c478bd9Sstevel@tonic-gate 			msp->ms_totpages += (uint_t)mp->sbm_npages;
4149*7c478bd9Sstevel@tonic-gate 
4150*7c478bd9Sstevel@tonic-gate 			/*
4151*7c478bd9Sstevel@tonic-gate 			 * If we're UNREFERENCED or UNCONFIGURED,
4152*7c478bd9Sstevel@tonic-gate 			 * then the number of detached pages is
4153*7c478bd9Sstevel@tonic-gate 			 * however many pages are on the board.
4154*7c478bd9Sstevel@tonic-gate 			 * I.e. detached = not in use by OS.
4155*7c478bd9Sstevel@tonic-gate 			 */
4156*7c478bd9Sstevel@tonic-gate 			switch (msp->ms_cm.c_ostate) {
4157*7c478bd9Sstevel@tonic-gate 			/*
4158*7c478bd9Sstevel@tonic-gate 			 * changed to use cfgadm states
4159*7c478bd9Sstevel@tonic-gate 			 *
4160*7c478bd9Sstevel@tonic-gate 			 * was:
4161*7c478bd9Sstevel@tonic-gate 			 *	case SFDR_STATE_UNREFERENCED:
4162*7c478bd9Sstevel@tonic-gate 			 *	case SFDR_STATE_UNCONFIGURED:
4163*7c478bd9Sstevel@tonic-gate 			 */
4164*7c478bd9Sstevel@tonic-gate 			case SBD_STAT_UNCONFIGURED:
4165*7c478bd9Sstevel@tonic-gate 				msp->ms_detpages = msp->ms_totpages;
4166*7c478bd9Sstevel@tonic-gate 				break;
4167*7c478bd9Sstevel@tonic-gate 
4168*7c478bd9Sstevel@tonic-gate 			default:
4169*7c478bd9Sstevel@tonic-gate 				break;
4170*7c478bd9Sstevel@tonic-gate 			}
4171*7c478bd9Sstevel@tonic-gate 		}
4172*7c478bd9Sstevel@tonic-gate 
4173*7c478bd9Sstevel@tonic-gate 		rv = kphysm_del_span_query(mp->sbm_basepfn,
4174*7c478bd9Sstevel@tonic-gate 						mp->sbm_npages, &mq);
4175*7c478bd9Sstevel@tonic-gate 		if (rv == KPHYSM_OK) {
4176*7c478bd9Sstevel@tonic-gate 			msp->ms_managed_pages = mq.managed;
4177*7c478bd9Sstevel@tonic-gate 			msp->ms_noreloc_pages = mq.nonrelocatable;
4178*7c478bd9Sstevel@tonic-gate 			msp->ms_noreloc_first = mq.first_nonrelocatable;
4179*7c478bd9Sstevel@tonic-gate 			msp->ms_noreloc_last = mq.last_nonrelocatable;
4180*7c478bd9Sstevel@tonic-gate 			msp->ms_cm.c_sflags = 0;
4181*7c478bd9Sstevel@tonic-gate 			if (mq.nonrelocatable) {
4182*7c478bd9Sstevel@tonic-gate 				SBD_SET_SUSPEND(SBD_CMD_UNCONFIGURE,
4183*7c478bd9Sstevel@tonic-gate 				    dsp->ds_suspend);
4184*7c478bd9Sstevel@tonic-gate 			}
4185*7c478bd9Sstevel@tonic-gate 		} else {
4186*7c478bd9Sstevel@tonic-gate 			PR_MEM("%s: kphysm_del_span_query() = %d\n", f, rv);
4187*7c478bd9Sstevel@tonic-gate 		}
4188*7c478bd9Sstevel@tonic-gate 
4189*7c478bd9Sstevel@tonic-gate 		mix++;
4190*7c478bd9Sstevel@tonic-gate 		dsp++;
4191*7c478bd9Sstevel@tonic-gate 	}
4192*7c478bd9Sstevel@tonic-gate 
4193*7c478bd9Sstevel@tonic-gate 	mutex_exit(&sbp->sb_slock);
4194*7c478bd9Sstevel@tonic-gate 
4195*7c478bd9Sstevel@tonic-gate 	return (mix);
4196*7c478bd9Sstevel@tonic-gate }
4197*7c478bd9Sstevel@tonic-gate 
4198*7c478bd9Sstevel@tonic-gate static void
4199*7c478bd9Sstevel@tonic-gate sbd_cancel(sbd_handle_t *hp)
4200*7c478bd9Sstevel@tonic-gate {
4201*7c478bd9Sstevel@tonic-gate 	int		i;
4202*7c478bd9Sstevel@tonic-gate 	sbd_devset_t	devset;
4203*7c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
4204*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_cancel";
4205*7c478bd9Sstevel@tonic-gate 	int		rv;
4206*7c478bd9Sstevel@tonic-gate 
4207*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
4208*7c478bd9Sstevel@tonic-gate 
4209*7c478bd9Sstevel@tonic-gate 	/*
4210*7c478bd9Sstevel@tonic-gate 	 * Only devices which have been "released" are
4211*7c478bd9Sstevel@tonic-gate 	 * subject to cancellation.
4212*7c478bd9Sstevel@tonic-gate 	 */
4213*7c478bd9Sstevel@tonic-gate 	devset = HD2MACHHD(hp)->sh_devset & SBD_DEVS_UNREFERENCED(sbp);
4214*7c478bd9Sstevel@tonic-gate 
4215*7c478bd9Sstevel@tonic-gate 	/*
4216*7c478bd9Sstevel@tonic-gate 	 * Nothing to do for CPUs or IO other than change back
4217*7c478bd9Sstevel@tonic-gate 	 * their state.
4218*7c478bd9Sstevel@tonic-gate 	 */
4219*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
4220*7c478bd9Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_CPU, i))
4221*7c478bd9Sstevel@tonic-gate 			continue;
4222*7c478bd9Sstevel@tonic-gate 		if (sbd_cancel_cpu(hp, i) != SBD_CPUERR_FATAL) {
4223*7c478bd9Sstevel@tonic-gate 			SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i,
4224*7c478bd9Sstevel@tonic-gate 						SBD_STATE_CONFIGURED);
4225*7c478bd9Sstevel@tonic-gate 		} else {
4226*7c478bd9Sstevel@tonic-gate 			SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i,
4227*7c478bd9Sstevel@tonic-gate 						SBD_STATE_FATAL);
4228*7c478bd9Sstevel@tonic-gate 		}
4229*7c478bd9Sstevel@tonic-gate 	}
4230*7c478bd9Sstevel@tonic-gate 
4231*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
4232*7c478bd9Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_IO, i))
4233*7c478bd9Sstevel@tonic-gate 			continue;
4234*7c478bd9Sstevel@tonic-gate 		SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, i,
4235*7c478bd9Sstevel@tonic-gate 					SBD_STATE_CONFIGURED);
4236*7c478bd9Sstevel@tonic-gate 	}
4237*7c478bd9Sstevel@tonic-gate 
4238*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
4239*7c478bd9Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_MEM, i))
4240*7c478bd9Sstevel@tonic-gate 			continue;
4241*7c478bd9Sstevel@tonic-gate 		if ((rv = sbd_cancel_mem(hp, i)) == 0) {
4242*7c478bd9Sstevel@tonic-gate 			SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i,
4243*7c478bd9Sstevel@tonic-gate 						SBD_STATE_CONFIGURED);
4244*7c478bd9Sstevel@tonic-gate 		} else if (rv == -1) {
4245*7c478bd9Sstevel@tonic-gate 			SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i,
4246*7c478bd9Sstevel@tonic-gate 						SBD_STATE_FATAL);
4247*7c478bd9Sstevel@tonic-gate 		}
4248*7c478bd9Sstevel@tonic-gate 	}
4249*7c478bd9Sstevel@tonic-gate 
4250*7c478bd9Sstevel@tonic-gate 	PR_ALL("%s: unreleasing devset (0x%x)\n", f, (uint_t)devset);
4251*7c478bd9Sstevel@tonic-gate 
4252*7c478bd9Sstevel@tonic-gate 	SBD_DEVS_CANCEL(sbp, devset);
4253*7c478bd9Sstevel@tonic-gate 
4254*7c478bd9Sstevel@tonic-gate 	if (SBD_DEVS_UNREFERENCED(sbp) == 0) {
4255*7c478bd9Sstevel@tonic-gate 		sbd_istate_t	new_state;
4256*7c478bd9Sstevel@tonic-gate 		/*
4257*7c478bd9Sstevel@tonic-gate 		 * If the board no longer has any released devices
4258*7c478bd9Sstevel@tonic-gate 		 * than transfer it back to the CONFIG/PARTIAL state.
4259*7c478bd9Sstevel@tonic-gate 		 */
4260*7c478bd9Sstevel@tonic-gate 		if (SBD_DEVS_ATTACHED(sbp) == SBD_DEVS_PRESENT(sbp))
4261*7c478bd9Sstevel@tonic-gate 			new_state = SBD_STATE_CONFIGURED;
4262*7c478bd9Sstevel@tonic-gate 		else
4263*7c478bd9Sstevel@tonic-gate 			new_state = SBD_STATE_PARTIAL;
4264*7c478bd9Sstevel@tonic-gate 		if (SBD_BOARD_STATE(sbp) != new_state) {
4265*7c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, new_state);
4266*7c478bd9Sstevel@tonic-gate 		}
4267*7c478bd9Sstevel@tonic-gate 		sbp->sb_ostate = SBD_STAT_CONFIGURED;
4268*7c478bd9Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&sbp->sb_time);
4269*7c478bd9Sstevel@tonic-gate 	}
4270*7c478bd9Sstevel@tonic-gate }
4271*7c478bd9Sstevel@tonic-gate 
4272*7c478bd9Sstevel@tonic-gate static void
4273*7c478bd9Sstevel@tonic-gate sbd_get_ncm(sbd_handle_t *hp)
4274*7c478bd9Sstevel@tonic-gate {
4275*7c478bd9Sstevel@tonic-gate 	sbd_devset_t devset;
4276*7c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp = HD2MACHHD(hp);
4277*7c478bd9Sstevel@tonic-gate 	sbd_cmd_t		*cmdp =  (sbd_cmd_t *)hp->h_iap;
4278*7c478bd9Sstevel@tonic-gate 	int			error;
4279*7c478bd9Sstevel@tonic-gate 
4280*7c478bd9Sstevel@tonic-gate 	/* pre_op restricted the devices to those selected by the ioctl */
4281*7c478bd9Sstevel@tonic-gate 	devset = shp->sh_devset;
4282*7c478bd9Sstevel@tonic-gate 
4283*7c478bd9Sstevel@tonic-gate 	cmdp->cmd_getncm.g_ncm = sbd_cpu_cnt(hp, devset)
4284*7c478bd9Sstevel@tonic-gate 		+ sbd_io_cnt(hp, devset) + sbd_mem_cnt(hp, devset);
4285*7c478bd9Sstevel@tonic-gate 
4286*7c478bd9Sstevel@tonic-gate 	error = sbd_copyout_ioarg(hp->h_mode, hp->h_cmd, cmdp,
4287*7c478bd9Sstevel@tonic-gate 		(sbd_ioctl_arg_t *)shp->sh_arg);
4288*7c478bd9Sstevel@tonic-gate 
4289*7c478bd9Sstevel@tonic-gate 	if (error != 0)
4290*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(SBD_HD2ERR(hp), error);
4291*7c478bd9Sstevel@tonic-gate }
4292*7c478bd9Sstevel@tonic-gate 
4293*7c478bd9Sstevel@tonic-gate static void
4294*7c478bd9Sstevel@tonic-gate sbd_status(sbd_handle_t *hp)
4295*7c478bd9Sstevel@tonic-gate {
4296*7c478bd9Sstevel@tonic-gate 	int			nstat, mode, ncm, sz, cksz;
4297*7c478bd9Sstevel@tonic-gate 	sbd_priv_handle_t	*shp = HD2MACHHD(hp);
4298*7c478bd9Sstevel@tonic-gate 	sbd_devset_t		devset;
4299*7c478bd9Sstevel@tonic-gate 	sbd_board_t		*sbp = SBDH2BD(hp->h_sbd);
4300*7c478bd9Sstevel@tonic-gate 	sbd_stat_t		*dstatp;
4301*7c478bd9Sstevel@tonic-gate 	sbd_cmd_t		*cmdp =  (sbd_cmd_t *)hp->h_iap;
4302*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t		*hdp;
4303*7c478bd9Sstevel@tonic-gate 	sbd_dev_stat_t		*devstatp;
4304*7c478bd9Sstevel@tonic-gate 
4305*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
4306*7c478bd9Sstevel@tonic-gate 	int			sz32;
4307*7c478bd9Sstevel@tonic-gate 	sbd_stat32_t		*dstat32p;
4308*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
4309*7c478bd9Sstevel@tonic-gate 
4310*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_status";
4311*7c478bd9Sstevel@tonic-gate 
4312*7c478bd9Sstevel@tonic-gate 	mode = hp->h_mode;
4313*7c478bd9Sstevel@tonic-gate 	devset = shp->sh_devset;
4314*7c478bd9Sstevel@tonic-gate 
4315*7c478bd9Sstevel@tonic-gate 	devset &= SBD_DEVS_PRESENT(sbp);
4316*7c478bd9Sstevel@tonic-gate 
4317*7c478bd9Sstevel@tonic-gate 	if (cmdp->cmd_cm.c_id.c_type == SBD_COMP_NONE) {
4318*7c478bd9Sstevel@tonic-gate 		if (cmdp->cmd_cm.c_flags & SBD_FLAG_ALLCMP) {
4319*7c478bd9Sstevel@tonic-gate 			/*
4320*7c478bd9Sstevel@tonic-gate 			 * Get the number of components "ncm" on the board.
4321*7c478bd9Sstevel@tonic-gate 			 * Calculate size of buffer required to store one
4322*7c478bd9Sstevel@tonic-gate 			 * sbd_stat_t structure plus ncm-1 sbd_dev_stat_t
4323*7c478bd9Sstevel@tonic-gate 			 * structures. Note that sbd_stat_t already contains
4324*7c478bd9Sstevel@tonic-gate 			 * one sbd_dev_stat_t, so only an additional ncm-1
4325*7c478bd9Sstevel@tonic-gate 			 * sbd_dev_stat_t structures need to be accounted for
4326*7c478bd9Sstevel@tonic-gate 			 * in the calculation when more than one component
4327*7c478bd9Sstevel@tonic-gate 			 * is present.
4328*7c478bd9Sstevel@tonic-gate 			 */
4329*7c478bd9Sstevel@tonic-gate 			ncm = sbd_cpu_cnt(hp, devset) + sbd_io_cnt(hp, devset) +
4330*7c478bd9Sstevel@tonic-gate 			    sbd_mem_cnt(hp, devset);
4331*7c478bd9Sstevel@tonic-gate 
4332*7c478bd9Sstevel@tonic-gate 		} else {
4333*7c478bd9Sstevel@tonic-gate 			/*
4334*7c478bd9Sstevel@tonic-gate 			 * In the case of c_type == SBD_COMP_NONE, and
4335*7c478bd9Sstevel@tonic-gate 			 * SBD_FLAG_ALLCMP not specified, only the board
4336*7c478bd9Sstevel@tonic-gate 			 * info is to be returned, no components.
4337*7c478bd9Sstevel@tonic-gate 			 */
4338*7c478bd9Sstevel@tonic-gate 			ncm = 0;
4339*7c478bd9Sstevel@tonic-gate 			devset = 0;
4340*7c478bd9Sstevel@tonic-gate 		}
4341*7c478bd9Sstevel@tonic-gate 	} else {
4342*7c478bd9Sstevel@tonic-gate 		/* Confirm that only one component is selected. */
4343*7c478bd9Sstevel@tonic-gate 		ncm = sbd_cpu_cnt(hp, devset) + sbd_io_cnt(hp, devset) +
4344*7c478bd9Sstevel@tonic-gate 		    sbd_mem_cnt(hp, devset);
4345*7c478bd9Sstevel@tonic-gate 		if (ncm != 1) {
4346*7c478bd9Sstevel@tonic-gate 			PR_ALL("%s: expected ncm of 1, got %d, devset 0x%x\n",
4347*7c478bd9Sstevel@tonic-gate 			    f, ncm, devset);
4348*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL);
4349*7c478bd9Sstevel@tonic-gate 			return;
4350*7c478bd9Sstevel@tonic-gate 		}
4351*7c478bd9Sstevel@tonic-gate 	}
4352*7c478bd9Sstevel@tonic-gate 
4353*7c478bd9Sstevel@tonic-gate 	sz = sizeof (sbd_stat_t);
4354*7c478bd9Sstevel@tonic-gate 	if (ncm > 1)
4355*7c478bd9Sstevel@tonic-gate 		sz += sizeof (sbd_dev_stat_t) * (ncm - 1);
4356*7c478bd9Sstevel@tonic-gate 
4357*7c478bd9Sstevel@tonic-gate 	cksz = sz;
4358*7c478bd9Sstevel@tonic-gate 
4359*7c478bd9Sstevel@tonic-gate 	/*
4360*7c478bd9Sstevel@tonic-gate 	 * s_nbytes describes the size of the preallocated user
4361*7c478bd9Sstevel@tonic-gate 	 * buffer into which the application is executing to
4362*7c478bd9Sstevel@tonic-gate 	 * receive the sbd_stat_t and sbd_dev_stat_t structures.
4363*7c478bd9Sstevel@tonic-gate 	 * This buffer must be at least the required (sz) size.
4364*7c478bd9Sstevel@tonic-gate 	 */
4365*7c478bd9Sstevel@tonic-gate 
4366*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
4367*7c478bd9Sstevel@tonic-gate 
4368*7c478bd9Sstevel@tonic-gate 	/*
4369*7c478bd9Sstevel@tonic-gate 	 * More buffer space is required for the 64bit to 32bit
4370*7c478bd9Sstevel@tonic-gate 	 * conversion of data structures.
4371*7c478bd9Sstevel@tonic-gate 	 */
4372*7c478bd9Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
4373*7c478bd9Sstevel@tonic-gate 		sz32 = sizeof (sbd_stat32_t);
4374*7c478bd9Sstevel@tonic-gate 		if (ncm > 1)
4375*7c478bd9Sstevel@tonic-gate 			sz32  += sizeof (sbd_dev_stat32_t) * (ncm - 1);
4376*7c478bd9Sstevel@tonic-gate 		cksz = sz32;
4377*7c478bd9Sstevel@tonic-gate 	} else
4378*7c478bd9Sstevel@tonic-gate 		sz32 = 0;
4379*7c478bd9Sstevel@tonic-gate #endif
4380*7c478bd9Sstevel@tonic-gate 
4381*7c478bd9Sstevel@tonic-gate 	if ((int)cmdp->cmd_stat.s_nbytes < cksz) {
4382*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s: ncm=%d s_nbytes = 0x%x\n", f, ncm,
4383*7c478bd9Sstevel@tonic-gate 		    cmdp->cmd_stat.s_nbytes);
4384*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s: expected size of 0x%x\n", f, cksz);
4385*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL);
4386*7c478bd9Sstevel@tonic-gate 		return;
4387*7c478bd9Sstevel@tonic-gate 	}
4388*7c478bd9Sstevel@tonic-gate 
4389*7c478bd9Sstevel@tonic-gate 	dstatp = kmem_zalloc(sz, KM_SLEEP);
4390*7c478bd9Sstevel@tonic-gate 	devstatp = &dstatp->s_stat[0];
4391*7c478bd9Sstevel@tonic-gate 
4392*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
4393*7c478bd9Sstevel@tonic-gate 	if (sz32 != 0)
4394*7c478bd9Sstevel@tonic-gate 		dstat32p = kmem_zalloc(sz32, KM_SLEEP);
4395*7c478bd9Sstevel@tonic-gate #endif
4396*7c478bd9Sstevel@tonic-gate 
4397*7c478bd9Sstevel@tonic-gate 	/*
4398*7c478bd9Sstevel@tonic-gate 	 * if connected or better, provide cached status if available,
4399*7c478bd9Sstevel@tonic-gate 	 * otherwise call sbdp for status
4400*7c478bd9Sstevel@tonic-gate 	 */
4401*7c478bd9Sstevel@tonic-gate 	mutex_enter(&sbp->sb_flags_mutex);
4402*7c478bd9Sstevel@tonic-gate 	switch (sbp->sb_state) {
4403*7c478bd9Sstevel@tonic-gate 
4404*7c478bd9Sstevel@tonic-gate 	case	SBD_STATE_CONNECTED:
4405*7c478bd9Sstevel@tonic-gate 	case	SBD_STATE_PARTIAL:
4406*7c478bd9Sstevel@tonic-gate 	case	SBD_STATE_CONFIGURED:
4407*7c478bd9Sstevel@tonic-gate 		if (sbp->sb_flags & SBD_BOARD_STATUS_CACHED) {
4408*7c478bd9Sstevel@tonic-gate 			bcopy(&sbp->sb_stat, dstatp, sizeof (sbd_stat_t));
4409*7c478bd9Sstevel@tonic-gate 			dstatp->s_rstate = rstate_cvt(sbp->sb_state);
4410*7c478bd9Sstevel@tonic-gate 			dstatp->s_ostate = ostate_cvt(sbp->sb_state);
4411*7c478bd9Sstevel@tonic-gate 			dstatp->s_busy = sbp->sb_busy;
4412*7c478bd9Sstevel@tonic-gate 			dstatp->s_time = sbp->sb_time;
4413*7c478bd9Sstevel@tonic-gate 			dstatp->s_cond = sbp->sb_cond;
4414*7c478bd9Sstevel@tonic-gate 			break;
4415*7c478bd9Sstevel@tonic-gate 		}
4416*7c478bd9Sstevel@tonic-gate 	/*FALLTHROUGH*/
4417*7c478bd9Sstevel@tonic-gate 
4418*7c478bd9Sstevel@tonic-gate 	default:
4419*7c478bd9Sstevel@tonic-gate 		sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED;
4420*7c478bd9Sstevel@tonic-gate 		dstatp->s_board = sbp->sb_num;
4421*7c478bd9Sstevel@tonic-gate 		dstatp->s_ostate = ostate_cvt(sbp->sb_state);
4422*7c478bd9Sstevel@tonic-gate 		dstatp->s_time = sbp->sb_time;
4423*7c478bd9Sstevel@tonic-gate 
4424*7c478bd9Sstevel@tonic-gate 		hdp = sbd_get_sbdp_handle(sbp, hp);
4425*7c478bd9Sstevel@tonic-gate 
4426*7c478bd9Sstevel@tonic-gate 		if (sbdp_get_board_status(hdp, dstatp) != 0) {
4427*7c478bd9Sstevel@tonic-gate 			SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
4428*7c478bd9Sstevel@tonic-gate 			sbd_release_sbdp_handle(hdp);
4429*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
4430*7c478bd9Sstevel@tonic-gate 			if (sz32 != 0)
4431*7c478bd9Sstevel@tonic-gate 				kmem_free(dstat32p, sz32);
4432*7c478bd9Sstevel@tonic-gate #endif
4433*7c478bd9Sstevel@tonic-gate 			kmem_free(dstatp, sz);
4434*7c478bd9Sstevel@tonic-gate 			mutex_exit(&sbp->sb_flags_mutex);
4435*7c478bd9Sstevel@tonic-gate 			return;
4436*7c478bd9Sstevel@tonic-gate 		}
4437*7c478bd9Sstevel@tonic-gate 		/*
4438*7c478bd9Sstevel@tonic-gate 		 * Do not cache status if the busy flag has
4439*7c478bd9Sstevel@tonic-gate 		 * been set by the call to sbdp_get_board_status().
4440*7c478bd9Sstevel@tonic-gate 		 */
4441*7c478bd9Sstevel@tonic-gate 		if (!dstatp->s_busy) {
4442*7c478bd9Sstevel@tonic-gate 			/* Can get board busy flag now */
4443*7c478bd9Sstevel@tonic-gate 			dstatp->s_busy = sbp->sb_busy;
4444*7c478bd9Sstevel@tonic-gate 			sbp->sb_cond = (sbd_cond_t)dstatp->s_cond;
4445*7c478bd9Sstevel@tonic-gate 			bcopy(dstatp, &sbp->sb_stat,
4446*7c478bd9Sstevel@tonic-gate 				sizeof (sbd_stat_t));
4447*7c478bd9Sstevel@tonic-gate 			sbp->sb_flags |= SBD_BOARD_STATUS_CACHED;
4448*7c478bd9Sstevel@tonic-gate 		}
4449*7c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
4450*7c478bd9Sstevel@tonic-gate 		break;
4451*7c478bd9Sstevel@tonic-gate 	}
4452*7c478bd9Sstevel@tonic-gate 	mutex_exit(&sbp->sb_flags_mutex);
4453*7c478bd9Sstevel@tonic-gate 
4454*7c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT))
4455*7c478bd9Sstevel@tonic-gate 		if ((nstat = sbd_cpu_flags(hp, devset, devstatp)) > 0) {
4456*7c478bd9Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
4457*7c478bd9Sstevel@tonic-gate 			devstatp += nstat;
4458*7c478bd9Sstevel@tonic-gate 		}
4459*7c478bd9Sstevel@tonic-gate 
4460*7c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT))
4461*7c478bd9Sstevel@tonic-gate 		if ((nstat = sbd_mem_status(hp, devset, devstatp)) > 0) {
4462*7c478bd9Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
4463*7c478bd9Sstevel@tonic-gate 			devstatp += nstat;
4464*7c478bd9Sstevel@tonic-gate 		}
4465*7c478bd9Sstevel@tonic-gate 
4466*7c478bd9Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT))
4467*7c478bd9Sstevel@tonic-gate 		if ((nstat = sbd_io_status(hp, devset, devstatp)) > 0) {
4468*7c478bd9Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
4469*7c478bd9Sstevel@tonic-gate 			devstatp += nstat;
4470*7c478bd9Sstevel@tonic-gate 		}
4471*7c478bd9Sstevel@tonic-gate 
4472*7c478bd9Sstevel@tonic-gate 	/* paranoia: detect buffer overrun */
4473*7c478bd9Sstevel@tonic-gate 	if ((caddr_t)devstatp > ((caddr_t)dstatp) + sz) {
4474*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s: buffer overrun\n", f);
4475*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
4476*7c478bd9Sstevel@tonic-gate 		if (sz32 != 0)
4477*7c478bd9Sstevel@tonic-gate 			kmem_free(dstat32p, sz32);
4478*7c478bd9Sstevel@tonic-gate #endif
4479*7c478bd9Sstevel@tonic-gate 		kmem_free(dstatp, sz);
4480*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL);
4481*7c478bd9Sstevel@tonic-gate 		return;
4482*7c478bd9Sstevel@tonic-gate 	}
4483*7c478bd9Sstevel@tonic-gate 
4484*7c478bd9Sstevel@tonic-gate /* if necessary, move data into intermediate device status buffer */
4485*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
4486*7c478bd9Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
4487*7c478bd9Sstevel@tonic-gate 		int		i, j;
4488*7c478bd9Sstevel@tonic-gate 
4489*7c478bd9Sstevel@tonic-gate 		ASSERT(sz32 != 0);
4490*7c478bd9Sstevel@tonic-gate 		/* paranoia: detect buffer overrun */
4491*7c478bd9Sstevel@tonic-gate 		if ((caddr_t)&dstat32p->s_stat[dstatp->s_nstat] >
4492*7c478bd9Sstevel@tonic-gate 		    ((caddr_t)dstat32p) + sz32) {
4493*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
4494*7c478bd9Sstevel@tonic-gate 				"sbd:%s: buffer32 overrun", f);
4495*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
4496*7c478bd9Sstevel@tonic-gate 			if (sz32 != 0)
4497*7c478bd9Sstevel@tonic-gate 				kmem_free(dstat32p, sz32);
4498*7c478bd9Sstevel@tonic-gate #endif
4499*7c478bd9Sstevel@tonic-gate 			kmem_free(dstatp, sz);
4500*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL);
4501*7c478bd9Sstevel@tonic-gate 			return;
4502*7c478bd9Sstevel@tonic-gate 		}
4503*7c478bd9Sstevel@tonic-gate 
4504*7c478bd9Sstevel@tonic-gate 		/*
4505*7c478bd9Sstevel@tonic-gate 		 * initialize 32 bit sbd board status structure
4506*7c478bd9Sstevel@tonic-gate 		 */
4507*7c478bd9Sstevel@tonic-gate 		dstat32p->s_board = (int32_t)dstatp->s_board;
4508*7c478bd9Sstevel@tonic-gate 		dstat32p->s_nstat = (int32_t)dstatp->s_nstat;
4509*7c478bd9Sstevel@tonic-gate 		dstat32p->s_rstate = dstatp->s_rstate;
4510*7c478bd9Sstevel@tonic-gate 		dstat32p->s_ostate = dstatp->s_ostate;
4511*7c478bd9Sstevel@tonic-gate 		dstat32p->s_cond = dstatp->s_cond;
4512*7c478bd9Sstevel@tonic-gate 		dstat32p->s_busy = dstatp->s_busy;
4513*7c478bd9Sstevel@tonic-gate 		dstat32p->s_time = dstatp->s_time;
4514*7c478bd9Sstevel@tonic-gate 		dstat32p->s_assigned = dstatp->s_assigned;
4515*7c478bd9Sstevel@tonic-gate 		dstat32p->s_power = dstatp->s_power;
4516*7c478bd9Sstevel@tonic-gate 		dstat32p->s_platopts = (int32_t)dstatp->s_platopts;
4517*7c478bd9Sstevel@tonic-gate 		(void) strcpy(dstat32p->s_type, dstatp->s_type);
4518*7c478bd9Sstevel@tonic-gate 
4519*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < dstatp->s_nstat; i++) {
4520*7c478bd9Sstevel@tonic-gate 			sbd_dev_stat_t	*dsp = &dstatp->s_stat[i];
4521*7c478bd9Sstevel@tonic-gate 			sbd_dev_stat32_t	*ds32p = &dstat32p->s_stat[i];
4522*7c478bd9Sstevel@tonic-gate 
4523*7c478bd9Sstevel@tonic-gate 			/*
4524*7c478bd9Sstevel@tonic-gate 			 * copy common data for the device
4525*7c478bd9Sstevel@tonic-gate 			 */
4526*7c478bd9Sstevel@tonic-gate 			ds32p->d_cm.ci_type = (int32_t)dsp->d_cm.ci_type;
4527*7c478bd9Sstevel@tonic-gate 			ds32p->d_cm.ci_unit = (int32_t)dsp->d_cm.ci_unit;
4528*7c478bd9Sstevel@tonic-gate 			ds32p->d_cm.c_ostate = (int32_t)dsp->d_cm.c_ostate;
4529*7c478bd9Sstevel@tonic-gate 			ds32p->d_cm.c_cond = (int32_t)dsp->d_cm.c_cond;
4530*7c478bd9Sstevel@tonic-gate 			ds32p->d_cm.c_busy = (int32_t)dsp->d_cm.c_busy;
4531*7c478bd9Sstevel@tonic-gate 			ds32p->d_cm.c_time = (time32_t)dsp->d_cm.c_time;
4532*7c478bd9Sstevel@tonic-gate 			ds32p->d_cm.c_sflags = (int32_t)dsp->d_cm.c_sflags;
4533*7c478bd9Sstevel@tonic-gate 			(void) strcpy(ds32p->d_cm.ci_name, dsp->d_cm.ci_name);
4534*7c478bd9Sstevel@tonic-gate 
4535*7c478bd9Sstevel@tonic-gate 			/* copy type specific data for the device */
4536*7c478bd9Sstevel@tonic-gate 			switch (dsp->d_cm.ci_type) {
4537*7c478bd9Sstevel@tonic-gate 
4538*7c478bd9Sstevel@tonic-gate 			case SBD_COMP_CPU:
4539*7c478bd9Sstevel@tonic-gate 				ds32p->d_cpu.cs_isbootproc =
4540*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_cpu.cs_isbootproc;
4541*7c478bd9Sstevel@tonic-gate 				ds32p->d_cpu.cs_cpuid =
4542*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_cpu.cs_cpuid;
4543*7c478bd9Sstevel@tonic-gate 				ds32p->d_cpu.cs_speed =
4544*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_cpu.cs_speed;
4545*7c478bd9Sstevel@tonic-gate 				ds32p->d_cpu.cs_ecache =
4546*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_cpu.cs_ecache;
4547*7c478bd9Sstevel@tonic-gate 				break;
4548*7c478bd9Sstevel@tonic-gate 
4549*7c478bd9Sstevel@tonic-gate 			case SBD_COMP_MEM:
4550*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_type =
4551*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_mem.ms_type;
4552*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_ostate =
4553*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_mem.ms_ostate;
4554*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_cond =
4555*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_mem.ms_cond;
4556*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_interleave =
4557*7c478bd9Sstevel@tonic-gate 					(uint32_t)dsp->d_mem.ms_interleave;
4558*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_basepfn =
4559*7c478bd9Sstevel@tonic-gate 					(uint32_t)dsp->d_mem.ms_basepfn;
4560*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_totpages =
4561*7c478bd9Sstevel@tonic-gate 					(uint32_t)dsp->d_mem.ms_totpages;
4562*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_detpages =
4563*7c478bd9Sstevel@tonic-gate 					(uint32_t)dsp->d_mem.ms_detpages;
4564*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_pageslost =
4565*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_mem.ms_pageslost;
4566*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_managed_pages =
4567*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_mem.ms_managed_pages;
4568*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_noreloc_pages =
4569*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_mem.ms_noreloc_pages;
4570*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_noreloc_first =
4571*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_mem.ms_noreloc_first;
4572*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_noreloc_last =
4573*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_mem.ms_noreloc_last;
4574*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_cage_enabled =
4575*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_mem.ms_cage_enabled;
4576*7c478bd9Sstevel@tonic-gate 				ds32p->d_mem.ms_peer_is_target =
4577*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_mem.ms_peer_is_target;
4578*7c478bd9Sstevel@tonic-gate 				(void) strcpy(ds32p->d_mem.ms_peer_ap_id,
4579*7c478bd9Sstevel@tonic-gate 					dsp->d_mem.ms_peer_ap_id);
4580*7c478bd9Sstevel@tonic-gate 				break;
4581*7c478bd9Sstevel@tonic-gate 
4582*7c478bd9Sstevel@tonic-gate 
4583*7c478bd9Sstevel@tonic-gate 			case SBD_COMP_IO:
4584*7c478bd9Sstevel@tonic-gate 
4585*7c478bd9Sstevel@tonic-gate 				ds32p->d_io.is_type =
4586*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_io.is_type;
4587*7c478bd9Sstevel@tonic-gate 				ds32p->d_io.is_unsafe_count =
4588*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_io.is_unsafe_count;
4589*7c478bd9Sstevel@tonic-gate 				ds32p->d_io.is_referenced =
4590*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_io.is_referenced;
4591*7c478bd9Sstevel@tonic-gate 				for (j = 0; j < SBD_MAX_UNSAFE; j++)
4592*7c478bd9Sstevel@tonic-gate 					ds32p->d_io.is_unsafe_list[j] =
4593*7c478bd9Sstevel@tonic-gate 					    (int32_t)
4594*7c478bd9Sstevel@tonic-gate 					    ds32p->d_io.is_unsafe_list[j];
4595*7c478bd9Sstevel@tonic-gate 				bcopy(dsp->d_io.is_pathname,
4596*7c478bd9Sstevel@tonic-gate 				    ds32p->d_io.is_pathname, MAXPATHLEN);
4597*7c478bd9Sstevel@tonic-gate 				break;
4598*7c478bd9Sstevel@tonic-gate 
4599*7c478bd9Sstevel@tonic-gate 			case SBD_COMP_CMP:
4600*7c478bd9Sstevel@tonic-gate 				/* copy sbd_cmp_stat_t structure members */
4601*7c478bd9Sstevel@tonic-gate 				bcopy(&dsp->d_cmp.ps_cpuid[0],
4602*7c478bd9Sstevel@tonic-gate 					&ds32p->d_cmp.ps_cpuid[0],
4603*7c478bd9Sstevel@tonic-gate 					sizeof (ds32p->d_cmp.ps_cpuid));
4604*7c478bd9Sstevel@tonic-gate 				ds32p->d_cmp.ps_ncores =
4605*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_cmp.ps_ncores;
4606*7c478bd9Sstevel@tonic-gate 				ds32p->d_cmp.ps_speed =
4607*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_cmp.ps_speed;
4608*7c478bd9Sstevel@tonic-gate 				ds32p->d_cmp.ps_ecache =
4609*7c478bd9Sstevel@tonic-gate 					(int32_t)dsp->d_cmp.ps_ecache;
4610*7c478bd9Sstevel@tonic-gate 				break;
4611*7c478bd9Sstevel@tonic-gate 
4612*7c478bd9Sstevel@tonic-gate 			default:
4613*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
4614*7c478bd9Sstevel@tonic-gate 				    "sbd:%s: unknown dev type (%d)", f,
4615*7c478bd9Sstevel@tonic-gate 				    (int)dsp->d_cm.c_id.c_type);
4616*7c478bd9Sstevel@tonic-gate 				break;
4617*7c478bd9Sstevel@tonic-gate 			}
4618*7c478bd9Sstevel@tonic-gate 		}
4619*7c478bd9Sstevel@tonic-gate 
4620*7c478bd9Sstevel@tonic-gate 		if (ddi_copyout((void *)dstat32p,
4621*7c478bd9Sstevel@tonic-gate 		    cmdp->cmd_stat.s_statp, sz32, mode) != 0) {
4622*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
4623*7c478bd9Sstevel@tonic-gate 				"sbd:%s: failed to copyout status "
4624*7c478bd9Sstevel@tonic-gate 				"for board %d", f, sbp->sb_num);
4625*7c478bd9Sstevel@tonic-gate 			SBD_SET_ERRNO(SBD_HD2ERR(hp), EFAULT);
4626*7c478bd9Sstevel@tonic-gate 		}
4627*7c478bd9Sstevel@tonic-gate 	} else
4628*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
4629*7c478bd9Sstevel@tonic-gate 	if (ddi_copyout((void *)dstatp, cmdp->cmd_stat.s_statp,
4630*7c478bd9Sstevel@tonic-gate 	    sz, mode) != 0) {
4631*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
4632*7c478bd9Sstevel@tonic-gate 			"sbd:%s: failed to copyout status for board %d",
4633*7c478bd9Sstevel@tonic-gate 			f, sbp->sb_num);
4634*7c478bd9Sstevel@tonic-gate 		SBD_SET_ERRNO(SBD_HD2ERR(hp), EFAULT);
4635*7c478bd9Sstevel@tonic-gate 	}
4636*7c478bd9Sstevel@tonic-gate 
4637*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
4638*7c478bd9Sstevel@tonic-gate 	if (sz32 != 0)
4639*7c478bd9Sstevel@tonic-gate 		kmem_free(dstat32p, sz32);
4640*7c478bd9Sstevel@tonic-gate #endif
4641*7c478bd9Sstevel@tonic-gate 	kmem_free(dstatp, sz);
4642*7c478bd9Sstevel@tonic-gate }
4643*7c478bd9Sstevel@tonic-gate 
4644*7c478bd9Sstevel@tonic-gate /*
4645*7c478bd9Sstevel@tonic-gate  * Called at driver load time to determine the state and condition
4646*7c478bd9Sstevel@tonic-gate  * of an existing board in the system.
4647*7c478bd9Sstevel@tonic-gate  */
4648*7c478bd9Sstevel@tonic-gate static void
4649*7c478bd9Sstevel@tonic-gate sbd_board_discovery(sbd_board_t *sbp)
4650*7c478bd9Sstevel@tonic-gate {
4651*7c478bd9Sstevel@tonic-gate 	int		i;
4652*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
4653*7c478bd9Sstevel@tonic-gate 	sbd_devset_t	devs_lost, devs_attached = 0;
4654*7c478bd9Sstevel@tonic-gate 	extern kmutex_t	cpu_lock;
4655*7c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
4656*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_board_discovery";
4657*7c478bd9Sstevel@tonic-gate 	sbderror_t	error, *ep;
4658*7c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp = MACHBD2HD(sbp);
4659*7c478bd9Sstevel@tonic-gate 
4660*7c478bd9Sstevel@tonic-gate 	if (SBD_DEVS_PRESENT(sbp) == 0) {
4661*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s: board %d has no devices present\n",
4662*7c478bd9Sstevel@tonic-gate 			f, sbp->sb_num);
4663*7c478bd9Sstevel@tonic-gate 		return;
4664*7c478bd9Sstevel@tonic-gate 	}
4665*7c478bd9Sstevel@tonic-gate 
4666*7c478bd9Sstevel@tonic-gate 	ep = &error;
4667*7c478bd9Sstevel@tonic-gate 	bzero(ep, sizeof (sbderror_t));
4668*7c478bd9Sstevel@tonic-gate 
4669*7c478bd9Sstevel@tonic-gate 	/*
4670*7c478bd9Sstevel@tonic-gate 	 * Check for existence of cpus.
4671*7c478bd9Sstevel@tonic-gate 	 */
4672*7c478bd9Sstevel@tonic-gate 
4673*7c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
4674*7c478bd9Sstevel@tonic-gate 
4675*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
4676*7c478bd9Sstevel@tonic-gate 		processorid_t	cpuid;
4677*7c478bd9Sstevel@tonic-gate 
4678*7c478bd9Sstevel@tonic-gate 		if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i))
4679*7c478bd9Sstevel@tonic-gate 			continue;
4680*7c478bd9Sstevel@tonic-gate 
4681*7c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][i];
4682*7c478bd9Sstevel@tonic-gate 
4683*7c478bd9Sstevel@tonic-gate 		if (dip != NULL) {
4684*7c478bd9Sstevel@tonic-gate 			cpuid = sbdp_get_cpuid(hdp, dip);
4685*7c478bd9Sstevel@tonic-gate 
4686*7c478bd9Sstevel@tonic-gate 			if (cpuid < 0) {
4687*7c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err,
4688*7c478bd9Sstevel@tonic-gate 				    ep);
4689*7c478bd9Sstevel@tonic-gate 				continue;
4690*7c478bd9Sstevel@tonic-gate 			}
4691*7c478bd9Sstevel@tonic-gate 
4692*7c478bd9Sstevel@tonic-gate 			mutex_enter(&cpu_lock);	/* needed to call cpu_get() */
4693*7c478bd9Sstevel@tonic-gate 			if (cpu_get(cpuid)) {
4694*7c478bd9Sstevel@tonic-gate 				SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_CPU, i);
4695*7c478bd9Sstevel@tonic-gate 				DEVSET_ADD(devs_attached, SBD_COMP_CPU, i);
4696*7c478bd9Sstevel@tonic-gate 				PR_ALL("%s: board %d, cpuid %d - attached\n",
4697*7c478bd9Sstevel@tonic-gate 					f, sbp->sb_num, cpuid);
4698*7c478bd9Sstevel@tonic-gate 			}
4699*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
4700*7c478bd9Sstevel@tonic-gate 			sbd_init_cpu_unit(sbp, i);
4701*7c478bd9Sstevel@tonic-gate 		}
4702*7c478bd9Sstevel@tonic-gate 	}
4703*7c478bd9Sstevel@tonic-gate 
4704*7c478bd9Sstevel@tonic-gate 	/*
4705*7c478bd9Sstevel@tonic-gate 	 * Check for existence of memory.
4706*7c478bd9Sstevel@tonic-gate 	 */
4707*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
4708*7c478bd9Sstevel@tonic-gate 		uint64_t	basepa, endpa;
4709*7c478bd9Sstevel@tonic-gate 		struct memlist	*ml;
4710*7c478bd9Sstevel@tonic-gate 		extern struct memlist	*phys_install;
4711*7c478bd9Sstevel@tonic-gate 
4712*7c478bd9Sstevel@tonic-gate 		if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i))
4713*7c478bd9Sstevel@tonic-gate 			continue;
4714*7c478bd9Sstevel@tonic-gate 
4715*7c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][i];
4716*7c478bd9Sstevel@tonic-gate 		if (dip == NULL)
4717*7c478bd9Sstevel@tonic-gate 			continue;
4718*7c478bd9Sstevel@tonic-gate 
4719*7c478bd9Sstevel@tonic-gate 		if (sbdphw_get_base_physaddr(hdp, dip, &basepa)) {
4720*7c478bd9Sstevel@tonic-gate 			/* omit phantom memory controllers on I/O boards */
4721*7c478bd9Sstevel@tonic-gate 			if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i)) {
4722*7c478bd9Sstevel@tonic-gate 				ASSERT(sbp->sb_ndev != 0);
4723*7c478bd9Sstevel@tonic-gate 				SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, i);
4724*7c478bd9Sstevel@tonic-gate 				sbp->sb_ndev--;
4725*7c478bd9Sstevel@tonic-gate 			}
4726*7c478bd9Sstevel@tonic-gate 			sbp->sb_devlist[NIX(SBD_COMP_MEM)][i] = NULL;
4727*7c478bd9Sstevel@tonic-gate 			continue;
4728*7c478bd9Sstevel@tonic-gate 		}
4729*7c478bd9Sstevel@tonic-gate 
4730*7c478bd9Sstevel@tonic-gate 		/*
4731*7c478bd9Sstevel@tonic-gate 		 * basepa may not be on a alignment boundary, make it so.
4732*7c478bd9Sstevel@tonic-gate 		 */
4733*7c478bd9Sstevel@tonic-gate 		if (sbdp_get_mem_alignment(hdp, dip, &endpa)) {
4734*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s sbdp_get_mem_alignment fail", f);
4735*7c478bd9Sstevel@tonic-gate 			continue;
4736*7c478bd9Sstevel@tonic-gate 		}
4737*7c478bd9Sstevel@tonic-gate 
4738*7c478bd9Sstevel@tonic-gate 		basepa &= ~(endpa - 1);
4739*7c478bd9Sstevel@tonic-gate 		endpa += basepa;
4740*7c478bd9Sstevel@tonic-gate 
4741*7c478bd9Sstevel@tonic-gate 		/*
4742*7c478bd9Sstevel@tonic-gate 		 * Check if base address is in phys_install.
4743*7c478bd9Sstevel@tonic-gate 		 */
4744*7c478bd9Sstevel@tonic-gate 		memlist_read_lock();
4745*7c478bd9Sstevel@tonic-gate 		for (ml = phys_install; ml; ml = ml->next)
4746*7c478bd9Sstevel@tonic-gate 			if ((endpa <= ml->address) ||
4747*7c478bd9Sstevel@tonic-gate 					(basepa >= (ml->address + ml->size)))
4748*7c478bd9Sstevel@tonic-gate 				continue;
4749*7c478bd9Sstevel@tonic-gate 			else
4750*7c478bd9Sstevel@tonic-gate 				break;
4751*7c478bd9Sstevel@tonic-gate 		memlist_read_unlock();
4752*7c478bd9Sstevel@tonic-gate 
4753*7c478bd9Sstevel@tonic-gate 		if (ml) {
4754*7c478bd9Sstevel@tonic-gate 			SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_MEM, i);
4755*7c478bd9Sstevel@tonic-gate 			DEVSET_ADD(devs_attached, SBD_COMP_MEM, i);
4756*7c478bd9Sstevel@tonic-gate 			PR_ALL("%s: board %d, mem-unit %d - attached\n",
4757*7c478bd9Sstevel@tonic-gate 				f, sbp->sb_num, i);
4758*7c478bd9Sstevel@tonic-gate 		}
4759*7c478bd9Sstevel@tonic-gate 		sbd_init_mem_unit(sbp, i, ep);
4760*7c478bd9Sstevel@tonic-gate 	}
4761*7c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
4762*7c478bd9Sstevel@tonic-gate 
4763*7c478bd9Sstevel@tonic-gate 	/*
4764*7c478bd9Sstevel@tonic-gate 	 * If so far we have found an error, we just log it but continue
4765*7c478bd9Sstevel@tonic-gate 	 */
4766*7c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERRNO(ep) != 0)
4767*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s errno has occurred: errno %d", f,
4768*7c478bd9Sstevel@tonic-gate 			SBD_GET_ERRNO(ep));
4769*7c478bd9Sstevel@tonic-gate 
4770*7c478bd9Sstevel@tonic-gate 	/*
4771*7c478bd9Sstevel@tonic-gate 	 * Check for i/o state.
4772*7c478bd9Sstevel@tonic-gate 	 */
4773*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
4774*7c478bd9Sstevel@tonic-gate 
4775*7c478bd9Sstevel@tonic-gate 		if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_IO, i))
4776*7c478bd9Sstevel@tonic-gate 			continue;
4777*7c478bd9Sstevel@tonic-gate 
4778*7c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_IO)][i];
4779*7c478bd9Sstevel@tonic-gate 		if (dip == NULL)
4780*7c478bd9Sstevel@tonic-gate 			continue;
4781*7c478bd9Sstevel@tonic-gate 
4782*7c478bd9Sstevel@tonic-gate 		ASSERT(e_ddi_branch_held(dip));
4783*7c478bd9Sstevel@tonic-gate 
4784*7c478bd9Sstevel@tonic-gate 		/*
4785*7c478bd9Sstevel@tonic-gate 		 * XXX Is the devstate check needed ?
4786*7c478bd9Sstevel@tonic-gate 		 */
4787*7c478bd9Sstevel@tonic-gate 		if (i_ddi_node_state(dip) >= DS_ATTACHED ||
4788*7c478bd9Sstevel@tonic-gate 		    ddi_get_devstate(dip) == DDI_DEVSTATE_UP) {
4789*7c478bd9Sstevel@tonic-gate 
4790*7c478bd9Sstevel@tonic-gate 			/*
4791*7c478bd9Sstevel@tonic-gate 			 * Found it!
4792*7c478bd9Sstevel@tonic-gate 			 */
4793*7c478bd9Sstevel@tonic-gate 			SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_IO, i);
4794*7c478bd9Sstevel@tonic-gate 			DEVSET_ADD(devs_attached, SBD_COMP_IO, i);
4795*7c478bd9Sstevel@tonic-gate 			PR_ALL("%s: board %d, io-unit %d - attached\n",
4796*7c478bd9Sstevel@tonic-gate 				f, sbp->sb_num, i);
4797*7c478bd9Sstevel@tonic-gate 		}
4798*7c478bd9Sstevel@tonic-gate 		sbd_init_io_unit(sbp, i);
4799*7c478bd9Sstevel@tonic-gate 	}
4800*7c478bd9Sstevel@tonic-gate 
4801*7c478bd9Sstevel@tonic-gate 	SBD_DEVS_CONFIGURE(sbp, devs_attached);
4802*7c478bd9Sstevel@tonic-gate 	if (devs_attached && ((devs_lost = SBD_DEVS_UNATTACHED(sbp)) != 0)) {
4803*7c478bd9Sstevel@tonic-gate 		int		ut;
4804*7c478bd9Sstevel@tonic-gate 		/*
4805*7c478bd9Sstevel@tonic-gate 		 * A prior comment stated that a partially configured
4806*7c478bd9Sstevel@tonic-gate 		 * board was not permitted. The Serengeti architecture
4807*7c478bd9Sstevel@tonic-gate 		 * makes this possible, so the SB_DEVS_DISCONNECT
4808*7c478bd9Sstevel@tonic-gate 		 * at the end of this block has been removed.
4809*7c478bd9Sstevel@tonic-gate 		 */
4810*7c478bd9Sstevel@tonic-gate 
4811*7c478bd9Sstevel@tonic-gate 		PR_ALL("%s: some devices not configured (0x%x)...\n",
4812*7c478bd9Sstevel@tonic-gate 			f, devs_lost);
4813*7c478bd9Sstevel@tonic-gate 
4814*7c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++)
4815*7c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devs_lost, SBD_COMP_CPU, ut)) {
4816*7c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU,
4817*7c478bd9Sstevel@tonic-gate 					ut, SBD_STATE_UNCONFIGURED);
4818*7c478bd9Sstevel@tonic-gate 			}
4819*7c478bd9Sstevel@tonic-gate 
4820*7c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++)
4821*7c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devs_lost, SBD_COMP_MEM, ut)) {
4822*7c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM,
4823*7c478bd9Sstevel@tonic-gate 					ut, SBD_STATE_UNCONFIGURED);
4824*7c478bd9Sstevel@tonic-gate 			}
4825*7c478bd9Sstevel@tonic-gate 
4826*7c478bd9Sstevel@tonic-gate 		for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++)
4827*7c478bd9Sstevel@tonic-gate 			if (DEVSET_IN_SET(devs_lost, SBD_COMP_IO, ut)) {
4828*7c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO,
4829*7c478bd9Sstevel@tonic-gate 					ut, SBD_STATE_UNCONFIGURED);
4830*7c478bd9Sstevel@tonic-gate 			}
4831*7c478bd9Sstevel@tonic-gate 	}
4832*7c478bd9Sstevel@tonic-gate }
4833*7c478bd9Sstevel@tonic-gate 
4834*7c478bd9Sstevel@tonic-gate static int
4835*7c478bd9Sstevel@tonic-gate hold_rele_branch(dev_info_t *rdip, void *arg)
4836*7c478bd9Sstevel@tonic-gate {
4837*7c478bd9Sstevel@tonic-gate 	walk_tree_t	*wp = (walk_tree_t *)arg;
4838*7c478bd9Sstevel@tonic-gate 
4839*7c478bd9Sstevel@tonic-gate 	ASSERT(wp && (wp->hold == 0 || wp->hold == 1));
4840*7c478bd9Sstevel@tonic-gate 
4841*7c478bd9Sstevel@tonic-gate 	switch (get_node_type(wp->sbp, rdip, NULL)) {
4842*7c478bd9Sstevel@tonic-gate 		case SBD_COMP_CMP:
4843*7c478bd9Sstevel@tonic-gate 		case SBD_COMP_MEM:
4844*7c478bd9Sstevel@tonic-gate 		case SBD_COMP_IO:
4845*7c478bd9Sstevel@tonic-gate 			break;
4846*7c478bd9Sstevel@tonic-gate 		case SBD_COMP_CPU:
4847*7c478bd9Sstevel@tonic-gate 
4848*7c478bd9Sstevel@tonic-gate 			/*
4849*7c478bd9Sstevel@tonic-gate 			 * All CPU nodes under CMP nodes should have
4850*7c478bd9Sstevel@tonic-gate 			 * gotten pruned when the CMP node was first
4851*7c478bd9Sstevel@tonic-gate 			 * encountered.
4852*7c478bd9Sstevel@tonic-gate 			 */
4853*7c478bd9Sstevel@tonic-gate 			ASSERT(!sbd_is_cmp_child(rdip));
4854*7c478bd9Sstevel@tonic-gate 
4855*7c478bd9Sstevel@tonic-gate 			break;
4856*7c478bd9Sstevel@tonic-gate 
4857*7c478bd9Sstevel@tonic-gate 		case SBD_COMP_UNKNOWN:
4858*7c478bd9Sstevel@tonic-gate 			/* Not of interest to us */
4859*7c478bd9Sstevel@tonic-gate 			return (DDI_WALK_CONTINUE);
4860*7c478bd9Sstevel@tonic-gate 		default:
4861*7c478bd9Sstevel@tonic-gate 			ASSERT(0);
4862*7c478bd9Sstevel@tonic-gate 			return (DDI_WALK_PRUNECHILD);
4863*7c478bd9Sstevel@tonic-gate 	}
4864*7c478bd9Sstevel@tonic-gate 
4865*7c478bd9Sstevel@tonic-gate 	if (wp->hold) {
4866*7c478bd9Sstevel@tonic-gate 		ASSERT(!e_ddi_branch_held(rdip));
4867*7c478bd9Sstevel@tonic-gate 		e_ddi_branch_hold(rdip);
4868*7c478bd9Sstevel@tonic-gate 	} else {
4869*7c478bd9Sstevel@tonic-gate 		ASSERT(e_ddi_branch_held(rdip));
4870*7c478bd9Sstevel@tonic-gate 		e_ddi_branch_rele(rdip);
4871*7c478bd9Sstevel@tonic-gate 	}
4872*7c478bd9Sstevel@tonic-gate 
4873*7c478bd9Sstevel@tonic-gate 	return (DDI_WALK_PRUNECHILD);
4874*7c478bd9Sstevel@tonic-gate }
4875*7c478bd9Sstevel@tonic-gate 
4876*7c478bd9Sstevel@tonic-gate static void
4877*7c478bd9Sstevel@tonic-gate sbd_board_init(sbd_board_t *sbp, sbd_softstate_t *softsp,
4878*7c478bd9Sstevel@tonic-gate 	int bd, dev_info_t *top_dip, int wnode)
4879*7c478bd9Sstevel@tonic-gate {
4880*7c478bd9Sstevel@tonic-gate 	int		i;
4881*7c478bd9Sstevel@tonic-gate 	dev_info_t	*pdip;
4882*7c478bd9Sstevel@tonic-gate 	int		circ;
4883*7c478bd9Sstevel@tonic-gate 	walk_tree_t	walk = {0};
4884*7c478bd9Sstevel@tonic-gate 
4885*7c478bd9Sstevel@tonic-gate 	mutex_init(&sbp->sb_mutex, NULL, MUTEX_DRIVER, NULL);
4886*7c478bd9Sstevel@tonic-gate 	mutex_init(&sbp->sb_flags_mutex, NULL, MUTEX_DRIVER, NULL);
4887*7c478bd9Sstevel@tonic-gate 	mutex_init(&sbp->sb_slock, NULL, MUTEX_DRIVER, NULL);
4888*7c478bd9Sstevel@tonic-gate 
4889*7c478bd9Sstevel@tonic-gate 	sbp->sb_ref = 0;
4890*7c478bd9Sstevel@tonic-gate 	sbp->sb_num = bd;
4891*7c478bd9Sstevel@tonic-gate 	sbp->sb_time = gethrestime_sec();
4892*7c478bd9Sstevel@tonic-gate 	/*
4893*7c478bd9Sstevel@tonic-gate 	 * For serengeti, top_dip doesn't need to be held because
4894*7c478bd9Sstevel@tonic-gate 	 * sbp i.e. sbd_board_t will be destroyed in sbd_teardown_instance()
4895*7c478bd9Sstevel@tonic-gate 	 * before top_dip detaches. For Daktari, top_dip is the
4896*7c478bd9Sstevel@tonic-gate 	 * root node which never has to be held.
4897*7c478bd9Sstevel@tonic-gate 	 */
4898*7c478bd9Sstevel@tonic-gate 	sbp->sb_topdip = top_dip;
4899*7c478bd9Sstevel@tonic-gate 	sbp->sb_cpuid = -1;
4900*7c478bd9Sstevel@tonic-gate 	sbp->sb_softsp = (void *) softsp;
4901*7c478bd9Sstevel@tonic-gate 	sbp->sb_cond = SBD_COND_UNKNOWN;
4902*7c478bd9Sstevel@tonic-gate 	sbp->sb_wnode = wnode;
4903*7c478bd9Sstevel@tonic-gate 	sbp->sb_memaccess_ok = 1;
4904*7c478bd9Sstevel@tonic-gate 
4905*7c478bd9Sstevel@tonic-gate 	ASSERT(MAX_IO_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD);
4906*7c478bd9Sstevel@tonic-gate 	ASSERT(MAX_CPU_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD);
4907*7c478bd9Sstevel@tonic-gate 	ASSERT(MAX_MEM_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD);
4908*7c478bd9Sstevel@tonic-gate 
4909*7c478bd9Sstevel@tonic-gate 	/*
4910*7c478bd9Sstevel@tonic-gate 	 * Allocate the devlist for cpus.
4911*7c478bd9Sstevel@tonic-gate 	 */
4912*7c478bd9Sstevel@tonic-gate 	sbp->sb_devlist[NIX(SBD_COMP_CPU)] = GETSTRUCT(dev_info_t *,
4913*7c478bd9Sstevel@tonic-gate 						MAX_CPU_UNITS_PER_BOARD);
4914*7c478bd9Sstevel@tonic-gate 
4915*7c478bd9Sstevel@tonic-gate 	/*
4916*7c478bd9Sstevel@tonic-gate 	 * Allocate the devlist for mem.
4917*7c478bd9Sstevel@tonic-gate 	 */
4918*7c478bd9Sstevel@tonic-gate 	sbp->sb_devlist[NIX(SBD_COMP_MEM)] = GETSTRUCT(dev_info_t *,
4919*7c478bd9Sstevel@tonic-gate 						MAX_MEM_UNITS_PER_BOARD);
4920*7c478bd9Sstevel@tonic-gate 
4921*7c478bd9Sstevel@tonic-gate 	/*
4922*7c478bd9Sstevel@tonic-gate 	 * Allocate the devlist for io.
4923*7c478bd9Sstevel@tonic-gate 	 */
4924*7c478bd9Sstevel@tonic-gate 	sbp->sb_devlist[NIX(SBD_COMP_IO)] = GETSTRUCT(dev_info_t *,
4925*7c478bd9Sstevel@tonic-gate 						MAX_IO_UNITS_PER_BOARD);
4926*7c478bd9Sstevel@tonic-gate 
4927*7c478bd9Sstevel@tonic-gate 
4928*7c478bd9Sstevel@tonic-gate 	sbp->sb_dev[NIX(SBD_COMP_CPU)] = GETSTRUCT(sbd_dev_unit_t,
4929*7c478bd9Sstevel@tonic-gate 						MAX_CPU_UNITS_PER_BOARD);
4930*7c478bd9Sstevel@tonic-gate 
4931*7c478bd9Sstevel@tonic-gate 	sbp->sb_dev[NIX(SBD_COMP_MEM)] = GETSTRUCT(sbd_dev_unit_t,
4932*7c478bd9Sstevel@tonic-gate 						MAX_MEM_UNITS_PER_BOARD);
4933*7c478bd9Sstevel@tonic-gate 
4934*7c478bd9Sstevel@tonic-gate 	sbp->sb_dev[NIX(SBD_COMP_IO)] = GETSTRUCT(sbd_dev_unit_t,
4935*7c478bd9Sstevel@tonic-gate 						MAX_IO_UNITS_PER_BOARD);
4936*7c478bd9Sstevel@tonic-gate 
4937*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
4938*7c478bd9Sstevel@tonic-gate 		sbp->sb_cpupath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
4939*7c478bd9Sstevel@tonic-gate 	}
4940*7c478bd9Sstevel@tonic-gate 
4941*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
4942*7c478bd9Sstevel@tonic-gate 		sbp->sb_mempath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
4943*7c478bd9Sstevel@tonic-gate 	}
4944*7c478bd9Sstevel@tonic-gate 
4945*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
4946*7c478bd9Sstevel@tonic-gate 		sbp->sb_iopath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
4947*7c478bd9Sstevel@tonic-gate 	}
4948*7c478bd9Sstevel@tonic-gate 
4949*7c478bd9Sstevel@tonic-gate 	/*
4950*7c478bd9Sstevel@tonic-gate 	 * Walk the device tree, find all top dips on this board and
4951*7c478bd9Sstevel@tonic-gate 	 * hold the branches rooted at them
4952*7c478bd9Sstevel@tonic-gate 	 */
4953*7c478bd9Sstevel@tonic-gate 	ASSERT(sbp->sb_topdip);
4954*7c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(sbp->sb_topdip);
4955*7c478bd9Sstevel@tonic-gate 	if (pdip)
4956*7c478bd9Sstevel@tonic-gate 		ndi_devi_enter(pdip, &circ);
4957*7c478bd9Sstevel@tonic-gate 	walk.sbp = sbp;
4958*7c478bd9Sstevel@tonic-gate 	walk.hold = 1;
4959*7c478bd9Sstevel@tonic-gate 	ddi_walk_devs(sbp->sb_topdip, hold_rele_branch, (void *)&walk);
4960*7c478bd9Sstevel@tonic-gate 	if (pdip)
4961*7c478bd9Sstevel@tonic-gate 		ndi_devi_exit(pdip, circ);
4962*7c478bd9Sstevel@tonic-gate 
4963*7c478bd9Sstevel@tonic-gate 	/*
4964*7c478bd9Sstevel@tonic-gate 	 * Initialize the devlists
4965*7c478bd9Sstevel@tonic-gate 	 */
4966*7c478bd9Sstevel@tonic-gate 	if (sbd_init_devlists(sbp) == 0) {
4967*7c478bd9Sstevel@tonic-gate 		SBD_BOARD_TRANSITION(sbp, SBD_STATE_EMPTY);
4968*7c478bd9Sstevel@tonic-gate 	} else {
4969*7c478bd9Sstevel@tonic-gate 		/*
4970*7c478bd9Sstevel@tonic-gate 		 * Couldn't have made it down here without
4971*7c478bd9Sstevel@tonic-gate 		 * having found at least one device.
4972*7c478bd9Sstevel@tonic-gate 		 */
4973*7c478bd9Sstevel@tonic-gate 		ASSERT(SBD_DEVS_PRESENT(sbp) != 0);
4974*7c478bd9Sstevel@tonic-gate 		/*
4975*7c478bd9Sstevel@tonic-gate 		 * Check the state of any possible devices on the
4976*7c478bd9Sstevel@tonic-gate 		 * board.
4977*7c478bd9Sstevel@tonic-gate 		 */
4978*7c478bd9Sstevel@tonic-gate 		sbd_board_discovery(sbp);
4979*7c478bd9Sstevel@tonic-gate 
4980*7c478bd9Sstevel@tonic-gate 		if (SBD_DEVS_UNATTACHED(sbp) == 0) {
4981*7c478bd9Sstevel@tonic-gate 			/*
4982*7c478bd9Sstevel@tonic-gate 			 * The board has no unattached devices, therefore
4983*7c478bd9Sstevel@tonic-gate 			 * by reason of insanity it must be configured!
4984*7c478bd9Sstevel@tonic-gate 			 */
4985*7c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED);
4986*7c478bd9Sstevel@tonic-gate 			sbp->sb_cond = SBD_COND_OK;
4987*7c478bd9Sstevel@tonic-gate 		} else if (SBD_DEVS_ATTACHED(sbp)) {
4988*7c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL);
4989*7c478bd9Sstevel@tonic-gate 		} else {
4990*7c478bd9Sstevel@tonic-gate 			SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONNECTED);
4991*7c478bd9Sstevel@tonic-gate 		}
4992*7c478bd9Sstevel@tonic-gate 	}
4993*7c478bd9Sstevel@tonic-gate }
4994*7c478bd9Sstevel@tonic-gate 
4995*7c478bd9Sstevel@tonic-gate static void
4996*7c478bd9Sstevel@tonic-gate sbd_board_destroy(sbd_board_t *sbp)
4997*7c478bd9Sstevel@tonic-gate {
4998*7c478bd9Sstevel@tonic-gate 	int		i;
4999*7c478bd9Sstevel@tonic-gate 	dev_info_t	*pdip;
5000*7c478bd9Sstevel@tonic-gate 	int		circ;
5001*7c478bd9Sstevel@tonic-gate 	walk_tree_t	walk = {0};
5002*7c478bd9Sstevel@tonic-gate 
5003*7c478bd9Sstevel@tonic-gate 	SBD_BOARD_TRANSITION(sbp, SBD_STATE_EMPTY);
5004*7c478bd9Sstevel@tonic-gate 
5005*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
5006*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
5007*7c478bd9Sstevel@tonic-gate 		sbd_mem_unit_t *mp;
5008*7c478bd9Sstevel@tonic-gate 
5009*7c478bd9Sstevel@tonic-gate 		mp = SBD_GET_BOARD_MEMUNIT(sbp, i);
5010*7c478bd9Sstevel@tonic-gate 		ASSERT(mp->sbm_mlist == NULL);
5011*7c478bd9Sstevel@tonic-gate 	}
5012*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
5013*7c478bd9Sstevel@tonic-gate 
5014*7c478bd9Sstevel@tonic-gate 	/*
5015*7c478bd9Sstevel@tonic-gate 	 * Free up MEM unit structs.
5016*7c478bd9Sstevel@tonic-gate 	 */
5017*7c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_MEM)],
5018*7c478bd9Sstevel@tonic-gate 			sbd_dev_unit_t, MAX_MEM_UNITS_PER_BOARD);
5019*7c478bd9Sstevel@tonic-gate 	sbp->sb_dev[NIX(SBD_COMP_MEM)] = NULL;
5020*7c478bd9Sstevel@tonic-gate 
5021*7c478bd9Sstevel@tonic-gate 	/*
5022*7c478bd9Sstevel@tonic-gate 	 * Free up CPU unit structs.
5023*7c478bd9Sstevel@tonic-gate 	 */
5024*7c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_CPU)],
5025*7c478bd9Sstevel@tonic-gate 			sbd_dev_unit_t, MAX_CPU_UNITS_PER_BOARD);
5026*7c478bd9Sstevel@tonic-gate 	sbp->sb_dev[NIX(SBD_COMP_CPU)] = NULL;
5027*7c478bd9Sstevel@tonic-gate 
5028*7c478bd9Sstevel@tonic-gate 	/*
5029*7c478bd9Sstevel@tonic-gate 	 * Free up IO unit structs.
5030*7c478bd9Sstevel@tonic-gate 	 */
5031*7c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_IO)],
5032*7c478bd9Sstevel@tonic-gate 			sbd_dev_unit_t, MAX_IO_UNITS_PER_BOARD);
5033*7c478bd9Sstevel@tonic-gate 	sbp->sb_dev[NIX(SBD_COMP_IO)] = NULL;
5034*7c478bd9Sstevel@tonic-gate 
5035*7c478bd9Sstevel@tonic-gate 	/*
5036*7c478bd9Sstevel@tonic-gate 	 * free up CPU devlists.
5037*7c478bd9Sstevel@tonic-gate 	 */
5038*7c478bd9Sstevel@tonic-gate 
5039*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
5040*7c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)sbp->sb_cpupath[i], MAXPATHLEN);
5041*7c478bd9Sstevel@tonic-gate 	}
5042*7c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_CPU)], dev_info_t *,
5043*7c478bd9Sstevel@tonic-gate 		MAX_CPU_UNITS_PER_BOARD);
5044*7c478bd9Sstevel@tonic-gate 	sbp->sb_devlist[NIX(SBD_COMP_CPU)] = NULL;
5045*7c478bd9Sstevel@tonic-gate 
5046*7c478bd9Sstevel@tonic-gate 	/*
5047*7c478bd9Sstevel@tonic-gate 	 * free up MEM devlists.
5048*7c478bd9Sstevel@tonic-gate 	 */
5049*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
5050*7c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)sbp->sb_mempath[i], MAXPATHLEN);
5051*7c478bd9Sstevel@tonic-gate 	}
5052*7c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_MEM)], dev_info_t *,
5053*7c478bd9Sstevel@tonic-gate 		MAX_MEM_UNITS_PER_BOARD);
5054*7c478bd9Sstevel@tonic-gate 	sbp->sb_devlist[NIX(SBD_COMP_MEM)] = NULL;
5055*7c478bd9Sstevel@tonic-gate 
5056*7c478bd9Sstevel@tonic-gate 	/*
5057*7c478bd9Sstevel@tonic-gate 	 * free up IO devlists.
5058*7c478bd9Sstevel@tonic-gate 	 */
5059*7c478bd9Sstevel@tonic-gate 	for (i = 0; i <  MAX_IO_UNITS_PER_BOARD; i++) {
5060*7c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)sbp->sb_iopath[i], MAXPATHLEN);
5061*7c478bd9Sstevel@tonic-gate 	}
5062*7c478bd9Sstevel@tonic-gate 	FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_IO)], dev_info_t *,
5063*7c478bd9Sstevel@tonic-gate 		MAX_IO_UNITS_PER_BOARD);
5064*7c478bd9Sstevel@tonic-gate 	sbp->sb_devlist[NIX(SBD_COMP_IO)] = NULL;
5065*7c478bd9Sstevel@tonic-gate 
5066*7c478bd9Sstevel@tonic-gate 	/*
5067*7c478bd9Sstevel@tonic-gate 	 * Release all branches held earlier
5068*7c478bd9Sstevel@tonic-gate 	 */
5069*7c478bd9Sstevel@tonic-gate 	ASSERT(sbp->sb_topdip);
5070*7c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(sbp->sb_topdip);
5071*7c478bd9Sstevel@tonic-gate 	if (pdip)
5072*7c478bd9Sstevel@tonic-gate 		ndi_devi_enter(pdip, &circ);
5073*7c478bd9Sstevel@tonic-gate 	walk.sbp = sbp;
5074*7c478bd9Sstevel@tonic-gate 	walk.hold = 0;
5075*7c478bd9Sstevel@tonic-gate 	ddi_walk_devs(sbp->sb_topdip, hold_rele_branch, (void *)&walk);
5076*7c478bd9Sstevel@tonic-gate 	if (pdip)
5077*7c478bd9Sstevel@tonic-gate 		ndi_devi_exit(pdip, circ);
5078*7c478bd9Sstevel@tonic-gate 
5079*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbp->sb_slock);
5080*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbp->sb_flags_mutex);
5081*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbp->sb_mutex);
5082*7c478bd9Sstevel@tonic-gate }
5083*7c478bd9Sstevel@tonic-gate 
5084*7c478bd9Sstevel@tonic-gate sbd_comp_type_t
5085*7c478bd9Sstevel@tonic-gate sbd_cm_type(char *name)
5086*7c478bd9Sstevel@tonic-gate {
5087*7c478bd9Sstevel@tonic-gate 	sbd_comp_type_t type = SBD_COMP_UNKNOWN;
5088*7c478bd9Sstevel@tonic-gate 	int i;
5089*7c478bd9Sstevel@tonic-gate 
5090*7c478bd9Sstevel@tonic-gate 	/* look up type in table */
5091*7c478bd9Sstevel@tonic-gate 	for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) {
5092*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, SBD_OTYPE(i)) == 0) {
5093*7c478bd9Sstevel@tonic-gate 			type = SBD_COMP(i);
5094*7c478bd9Sstevel@tonic-gate 			break;
5095*7c478bd9Sstevel@tonic-gate 		}
5096*7c478bd9Sstevel@tonic-gate 	}
5097*7c478bd9Sstevel@tonic-gate 
5098*7c478bd9Sstevel@tonic-gate 	return (type);
5099*7c478bd9Sstevel@tonic-gate }
5100*7c478bd9Sstevel@tonic-gate 
5101*7c478bd9Sstevel@tonic-gate /*
5102*7c478bd9Sstevel@tonic-gate  * There are certain cases where obp marks components as failed
5103*7c478bd9Sstevel@tonic-gate  * If the status is ok the node won't have any status property. It
5104*7c478bd9Sstevel@tonic-gate  * is only there if the status is other than ok.
5105*7c478bd9Sstevel@tonic-gate  *
5106*7c478bd9Sstevel@tonic-gate  * The translation is as follows:
5107*7c478bd9Sstevel@tonic-gate  * If there is no status prop, the the cond is SBD_COND_OK
5108*7c478bd9Sstevel@tonic-gate  * If we find a status prop but can't get to it then cond is SBD_COND_UNKNOWN
5109*7c478bd9Sstevel@tonic-gate  * if we find a stat and it is failed the cond is SBD_COND_FAILED
5110*7c478bd9Sstevel@tonic-gate  * If the stat is disabled, the cond is SBD_COND_UNUSABLE
5111*7c478bd9Sstevel@tonic-gate  * Otherwise we return con as SBD_COND_OK
5112*7c478bd9Sstevel@tonic-gate  */
5113*7c478bd9Sstevel@tonic-gate sbd_cond_t
5114*7c478bd9Sstevel@tonic-gate sbd_get_comp_cond(dev_info_t *dip)
5115*7c478bd9Sstevel@tonic-gate {
5116*7c478bd9Sstevel@tonic-gate 	int			len;
5117*7c478bd9Sstevel@tonic-gate 	char			*status_buf;
5118*7c478bd9Sstevel@tonic-gate 	static const char	*status = "status";
5119*7c478bd9Sstevel@tonic-gate 	static const char	*failed = "fail";
5120*7c478bd9Sstevel@tonic-gate 	static const char	*disabled = "disabled";
5121*7c478bd9Sstevel@tonic-gate 
5122*7c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
5123*7c478bd9Sstevel@tonic-gate 		PR_BYP("dip is NULL\n");
5124*7c478bd9Sstevel@tonic-gate 		return (SBD_COND_UNKNOWN);
5125*7c478bd9Sstevel@tonic-gate 	}
5126*7c478bd9Sstevel@tonic-gate 
5127*7c478bd9Sstevel@tonic-gate 	if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
5128*7c478bd9Sstevel@tonic-gate 	    (char *)status, &len) != DDI_PROP_SUCCESS) {
5129*7c478bd9Sstevel@tonic-gate 		PR_CPU("status in sbd is ok\n");
5130*7c478bd9Sstevel@tonic-gate 		return (SBD_COND_OK);
5131*7c478bd9Sstevel@tonic-gate 	}
5132*7c478bd9Sstevel@tonic-gate 
5133*7c478bd9Sstevel@tonic-gate 	status_buf = kmem_zalloc(sizeof (char) * OBP_MAXPROPNAME, KM_SLEEP);
5134*7c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
5135*7c478bd9Sstevel@tonic-gate 	    (char *)status, status_buf, &len) != DDI_PROP_SUCCESS) {
5136*7c478bd9Sstevel@tonic-gate 		PR_CPU("status in sbd is unknown\n");
5137*7c478bd9Sstevel@tonic-gate 		return (SBD_COND_UNKNOWN);
5138*7c478bd9Sstevel@tonic-gate 	}
5139*7c478bd9Sstevel@tonic-gate 
5140*7c478bd9Sstevel@tonic-gate 	if (strncmp(status_buf, failed, strlen(failed)) == 0) {
5141*7c478bd9Sstevel@tonic-gate 		PR_CPU("status in sbd is failed\n");
5142*7c478bd9Sstevel@tonic-gate 		kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME);
5143*7c478bd9Sstevel@tonic-gate 		return (SBD_COND_FAILED);
5144*7c478bd9Sstevel@tonic-gate 	}
5145*7c478bd9Sstevel@tonic-gate 
5146*7c478bd9Sstevel@tonic-gate 	if (strcmp(status_buf, disabled) == 0) {
5147*7c478bd9Sstevel@tonic-gate 		PR_CPU("status in sbd is unusable\n");
5148*7c478bd9Sstevel@tonic-gate 		kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME);
5149*7c478bd9Sstevel@tonic-gate 		return (SBD_COND_UNUSABLE);
5150*7c478bd9Sstevel@tonic-gate 	}
5151*7c478bd9Sstevel@tonic-gate 
5152*7c478bd9Sstevel@tonic-gate 	kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME);
5153*7c478bd9Sstevel@tonic-gate 	return (SBD_COND_OK);
5154*7c478bd9Sstevel@tonic-gate }
5155*7c478bd9Sstevel@tonic-gate 
5156*7c478bd9Sstevel@tonic-gate #ifdef SBD_DEBUG_ERRS
5157*7c478bd9Sstevel@tonic-gate 
5158*7c478bd9Sstevel@tonic-gate /* function to simulate errors throughout the sbd code */
5159*7c478bd9Sstevel@tonic-gate void
5160*7c478bd9Sstevel@tonic-gate sbd_inject_err(int error, sbderror_t *ep, int Errno, int ecode,
5161*7c478bd9Sstevel@tonic-gate 	char *rsc)
5162*7c478bd9Sstevel@tonic-gate {
5163*7c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_inject_err";
5164*7c478bd9Sstevel@tonic-gate 
5165*7c478bd9Sstevel@tonic-gate 	if (sbd_err_debug == 0)
5166*7c478bd9Sstevel@tonic-gate 		return;
5167*7c478bd9Sstevel@tonic-gate 
5168*7c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
5169*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s ep is NULL", f);
5170*7c478bd9Sstevel@tonic-gate 		return;
5171*7c478bd9Sstevel@tonic-gate 	}
5172*7c478bd9Sstevel@tonic-gate 
5173*7c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERRNO(ep) != 0) {
5174*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s errno already set to %d", f,
5175*7c478bd9Sstevel@tonic-gate 			SBD_GET_ERRNO(ep));
5176*7c478bd9Sstevel@tonic-gate 		return;
5177*7c478bd9Sstevel@tonic-gate 	}
5178*7c478bd9Sstevel@tonic-gate 
5179*7c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERR(ep) != 0) {
5180*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s code already set to %d", f,
5181*7c478bd9Sstevel@tonic-gate 			SBD_GET_ERR(ep));
5182*7c478bd9Sstevel@tonic-gate 		return;
5183*7c478bd9Sstevel@tonic-gate 	}
5184*7c478bd9Sstevel@tonic-gate 
5185*7c478bd9Sstevel@tonic-gate 	if ((sbd_err_debug & (1 << error)) != 0) {
5186*7c478bd9Sstevel@tonic-gate 		ep->e_errno = Errno;
5187*7c478bd9Sstevel@tonic-gate 		ep->e_code = ecode;
5188*7c478bd9Sstevel@tonic-gate 
5189*7c478bd9Sstevel@tonic-gate 		if (rsc != NULL)
5190*7c478bd9Sstevel@tonic-gate 			bcopy((caddr_t)rsc,
5191*7c478bd9Sstevel@tonic-gate 			(caddr_t)ep->e_rsc,
5192*7c478bd9Sstevel@tonic-gate 			sizeof (ep->e_rsc));
5193*7c478bd9Sstevel@tonic-gate 
5194*7c478bd9Sstevel@tonic-gate 		if (Errno != 0)
5195*7c478bd9Sstevel@tonic-gate 			PR_ERR_ERRNO("%s set errno to %d", f, ep->e_errno);
5196*7c478bd9Sstevel@tonic-gate 
5197*7c478bd9Sstevel@tonic-gate 		if (ecode != 0)
5198*7c478bd9Sstevel@tonic-gate 			PR_ERR_ECODE("%s set ecode to %d", f, ep->e_code);
5199*7c478bd9Sstevel@tonic-gate 
5200*7c478bd9Sstevel@tonic-gate 		if (rsc != NULL)
5201*7c478bd9Sstevel@tonic-gate 			PR_ERR_RSC("%s set rsc to %s", f, ep->e_rsc);
5202*7c478bd9Sstevel@tonic-gate 	}
5203*7c478bd9Sstevel@tonic-gate }
5204*7c478bd9Sstevel@tonic-gate #endif
5205