xref: /onnv-gate/usr/src/uts/sun4u/ngdr/io/dr.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * PIM-DR layer of DR driver.  Provides interface between user
31*0Sstevel@tonic-gate  * level applications and the PSM-DR layer.
32*0Sstevel@tonic-gate  */
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #include <sys/note.h>
35*0Sstevel@tonic-gate #include <sys/debug.h>
36*0Sstevel@tonic-gate #include <sys/types.h>
37*0Sstevel@tonic-gate #include <sys/errno.h>
38*0Sstevel@tonic-gate #include <sys/cred.h>
39*0Sstevel@tonic-gate #include <sys/dditypes.h>
40*0Sstevel@tonic-gate #include <sys/devops.h>
41*0Sstevel@tonic-gate #include <sys/modctl.h>
42*0Sstevel@tonic-gate #include <sys/poll.h>
43*0Sstevel@tonic-gate #include <sys/conf.h>
44*0Sstevel@tonic-gate #include <sys/ddi.h>
45*0Sstevel@tonic-gate #include <sys/sunddi.h>
46*0Sstevel@tonic-gate #include <sys/sunndi.h>
47*0Sstevel@tonic-gate #include <sys/stat.h>
48*0Sstevel@tonic-gate #include <sys/kmem.h>
49*0Sstevel@tonic-gate #include <sys/processor.h>
50*0Sstevel@tonic-gate #include <sys/cpuvar.h>
51*0Sstevel@tonic-gate #include <sys/mem_config.h>
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate #include <sys/autoconf.h>
54*0Sstevel@tonic-gate #include <sys/cmn_err.h>
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
57*0Sstevel@tonic-gate #include <sys/promif.h>
58*0Sstevel@tonic-gate #include <sys/machsystm.h>
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #include <sys/dr.h>
61*0Sstevel@tonic-gate #include <sys/drmach.h>
62*0Sstevel@tonic-gate #include <sys/dr_util.h>
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate extern int		 nulldev();
65*0Sstevel@tonic-gate extern int		 nodev();
66*0Sstevel@tonic-gate extern struct memlist	*phys_install;
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate #ifdef DEBUG
69*0Sstevel@tonic-gate uint_t	dr_debug = 0;			/* dr.h for bit values */
70*0Sstevel@tonic-gate #endif /* DEBUG */
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /*
73*0Sstevel@tonic-gate  * NOTE: state_str, nt_str and SBD_CMD_STR are only used in a debug
74*0Sstevel@tonic-gate  * kernel.  They are, however, referenced during both debug and non-debug
75*0Sstevel@tonic-gate  * compiles.
76*0Sstevel@tonic-gate  */
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate static char *state_str[] = {
79*0Sstevel@tonic-gate 	"EMPTY", "OCCUPIED", "CONNECTED", "UNCONFIGURED",
80*0Sstevel@tonic-gate 	"PARTIAL", "CONFIGURED", "RELEASE", "UNREFERENCED",
81*0Sstevel@tonic-gate 	"FATAL"
82*0Sstevel@tonic-gate };
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate #define	SBD_CMD_STR(c) \
85*0Sstevel@tonic-gate 	(((c) == SBD_CMD_ASSIGN)	? "ASSIGN"	: \
86*0Sstevel@tonic-gate 	((c) == SBD_CMD_UNASSIGN)	? "UNASSIGN"	: \
87*0Sstevel@tonic-gate 	((c) == SBD_CMD_POWERON)	? "POWERON"	: \
88*0Sstevel@tonic-gate 	((c) == SBD_CMD_POWEROFF)	? "POWEROFF"	: \
89*0Sstevel@tonic-gate 	((c) == SBD_CMD_TEST)		? "TEST"	: \
90*0Sstevel@tonic-gate 	((c) == SBD_CMD_CONNECT)	? "CONNECT"	: \
91*0Sstevel@tonic-gate 	((c) == SBD_CMD_DISCONNECT)	? "DISCONNECT"	: \
92*0Sstevel@tonic-gate 	((c) == SBD_CMD_CONFIGURE)	? "CONFIGURE"	: \
93*0Sstevel@tonic-gate 	((c) == SBD_CMD_UNCONFIGURE)	? "UNCONFIGURE"	: \
94*0Sstevel@tonic-gate 	((c) == SBD_CMD_GETNCM)		? "GETNCM"	: \
95*0Sstevel@tonic-gate 	((c) == SBD_CMD_PASSTHRU)	? "PASSTHRU"	: \
96*0Sstevel@tonic-gate 	((c) == SBD_CMD_STATUS)		? "STATUS"	: "unknown")
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate #define	DR_GET_BOARD_DEVUNIT(sb, ut, un) (&((sb)->b_dev[NIX(ut)][un]))
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate #define	DR_MAKE_MINOR(i, b)	(((i) << 16) | (b))
101*0Sstevel@tonic-gate #define	DR_MINOR2INST(m)	(((m) >> 16) & 0xffff)
102*0Sstevel@tonic-gate #define	DR_MINOR2BNUM(m)	((m) & 0xffff)
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate /* for the DR*INTERNAL_ERROR macros.  see sys/dr.h. */
105*0Sstevel@tonic-gate static char *dr_ie_fmt = "dr.c %d";
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate /* struct for drmach device name to sbd_comp_type_t mapping */
108*0Sstevel@tonic-gate typedef	struct {
109*0Sstevel@tonic-gate 	char		*s_devtype;
110*0Sstevel@tonic-gate 	sbd_comp_type_t	s_nodetype;
111*0Sstevel@tonic-gate } dr_devname_t;
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate /* struct to map starfire device attributes - name:sbd_comp_type_t */
114*0Sstevel@tonic-gate static	dr_devname_t	dr_devattr[] = {
115*0Sstevel@tonic-gate 	{ DRMACH_DEVTYPE_MEM,	SBD_COMP_MEM },
116*0Sstevel@tonic-gate 	{ DRMACH_DEVTYPE_CPU,	SBD_COMP_CPU },
117*0Sstevel@tonic-gate 	{ DRMACH_DEVTYPE_PCI,	SBD_COMP_IO },
118*0Sstevel@tonic-gate 	{ DRMACH_DEVTYPE_SBUS,	SBD_COMP_IO },
119*0Sstevel@tonic-gate #if defined(DRMACH_DEVTYPE_WCI)
120*0Sstevel@tonic-gate 	{ DRMACH_DEVTYPE_WCI,	SBD_COMP_IO },
121*0Sstevel@tonic-gate #endif
122*0Sstevel@tonic-gate 	/* last s_devtype must be NULL, s_nodetype must be SBD_COMP_UNKNOWN */
123*0Sstevel@tonic-gate 	{ NULL,			SBD_COMP_UNKNOWN }
124*0Sstevel@tonic-gate };
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate /*
127*0Sstevel@tonic-gate  * Per instance soft-state structure.
128*0Sstevel@tonic-gate  */
129*0Sstevel@tonic-gate typedef struct dr_softstate {
130*0Sstevel@tonic-gate 	dev_info_t	*dip;
131*0Sstevel@tonic-gate 	dr_board_t	*boards;
132*0Sstevel@tonic-gate 	kmutex_t	i_lock;
133*0Sstevel@tonic-gate 	int		 dr_initialized;
134*0Sstevel@tonic-gate } dr_softstate_t;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate /*
137*0Sstevel@tonic-gate  * dr Global data elements
138*0Sstevel@tonic-gate  */
139*0Sstevel@tonic-gate struct dr_global {
140*0Sstevel@tonic-gate 	dr_softstate_t	*softsp;	/* pointer to initialize soft state */
141*0Sstevel@tonic-gate 	kmutex_t	lock;
142*0Sstevel@tonic-gate } dr_g;
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate dr_unsafe_devs_t	dr_unsafe_devs;
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate /*
147*0Sstevel@tonic-gate  * Table of known passthru commands.
148*0Sstevel@tonic-gate  */
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate struct {
151*0Sstevel@tonic-gate 	char	*pt_name;
152*0Sstevel@tonic-gate 	int	(*pt_func)(dr_handle_t *);
153*0Sstevel@tonic-gate } pt_arr[] = {
154*0Sstevel@tonic-gate 	"quiesce",		dr_pt_test_suspend,
155*0Sstevel@tonic-gate };
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate int dr_modunload_okay = 0;		/* set to non-zero to allow unload */
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate /*
160*0Sstevel@tonic-gate  * State transition table.  States valid transitions for "board" state.
161*0Sstevel@tonic-gate  * Recall that non-zero return value terminates operation, however
162*0Sstevel@tonic-gate  * the herrno value is what really indicates an error , if any.
163*0Sstevel@tonic-gate  */
164*0Sstevel@tonic-gate static int
165*0Sstevel@tonic-gate _cmd2index(int c)
166*0Sstevel@tonic-gate {
167*0Sstevel@tonic-gate 	/*
168*0Sstevel@tonic-gate 	 * Translate DR CMD to index into dr_state_transition.
169*0Sstevel@tonic-gate 	 */
170*0Sstevel@tonic-gate 	switch (c) {
171*0Sstevel@tonic-gate 	case SBD_CMD_CONNECT:		return (0);
172*0Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:	return (1);
173*0Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:		return (2);
174*0Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:	return (3);
175*0Sstevel@tonic-gate 	case SBD_CMD_ASSIGN:		return (4);
176*0Sstevel@tonic-gate 	case SBD_CMD_UNASSIGN:		return (5);
177*0Sstevel@tonic-gate 	case SBD_CMD_POWERON:		return (6);
178*0Sstevel@tonic-gate 	case SBD_CMD_POWEROFF:		return (7);
179*0Sstevel@tonic-gate 	case SBD_CMD_TEST:		return (8);
180*0Sstevel@tonic-gate 	default:			return (-1);
181*0Sstevel@tonic-gate 	}
182*0Sstevel@tonic-gate }
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate #define	CMD2INDEX(c)	_cmd2index(c)
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate static struct dr_state_trans {
187*0Sstevel@tonic-gate 	int	x_cmd;
188*0Sstevel@tonic-gate 	struct {
189*0Sstevel@tonic-gate 		int	x_rv;		/* return value of pre_op */
190*0Sstevel@tonic-gate 		int	x_err;		/* error, if any */
191*0Sstevel@tonic-gate 	} x_op[DR_STATE_MAX];
192*0Sstevel@tonic-gate } dr_state_transition[] = {
193*0Sstevel@tonic-gate 	{ SBD_CMD_CONNECT,
194*0Sstevel@tonic-gate 		{
195*0Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
196*0Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
197*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
198*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
199*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
200*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
201*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
202*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
203*0Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
204*0Sstevel@tonic-gate 		}
205*0Sstevel@tonic-gate 	},
206*0Sstevel@tonic-gate 	{ SBD_CMD_DISCONNECT,
207*0Sstevel@tonic-gate 		{
208*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* empty */
209*0Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
210*0Sstevel@tonic-gate 			{ 0, 0 },			/* connected */
211*0Sstevel@tonic-gate 			{ 0, 0 },			/* unconfigured */
212*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
213*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
214*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
215*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
216*0Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
217*0Sstevel@tonic-gate 		}
218*0Sstevel@tonic-gate 	},
219*0Sstevel@tonic-gate 	{ SBD_CMD_CONFIGURE,
220*0Sstevel@tonic-gate 		{
221*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* empty */
222*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* occupied */
223*0Sstevel@tonic-gate 			{ 0, 0 },			/* connected */
224*0Sstevel@tonic-gate 			{ 0, 0 },			/* unconfigured */
225*0Sstevel@tonic-gate 			{ 0, 0 },			/* partial */
226*0Sstevel@tonic-gate 			{ 0, 0 },			/* configured */
227*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
228*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
229*0Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
230*0Sstevel@tonic-gate 		}
231*0Sstevel@tonic-gate 	},
232*0Sstevel@tonic-gate 	{ SBD_CMD_UNCONFIGURE,
233*0Sstevel@tonic-gate 		{
234*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* empty */
235*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* occupied */
236*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
237*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
238*0Sstevel@tonic-gate 			{ 0, 0 },			/* partial */
239*0Sstevel@tonic-gate 			{ 0, 0 },			/* configured */
240*0Sstevel@tonic-gate 			{ 0, 0 },			/* release */
241*0Sstevel@tonic-gate 			{ 0, 0 },			/* unreferenced */
242*0Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
243*0Sstevel@tonic-gate 		}
244*0Sstevel@tonic-gate 	},
245*0Sstevel@tonic-gate 	{ SBD_CMD_ASSIGN,
246*0Sstevel@tonic-gate 		{
247*0Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
248*0Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
249*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
250*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
251*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
252*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
253*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
254*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
255*0Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
256*0Sstevel@tonic-gate 		}
257*0Sstevel@tonic-gate 	},
258*0Sstevel@tonic-gate 	{ SBD_CMD_UNASSIGN,
259*0Sstevel@tonic-gate 		{
260*0Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
261*0Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
262*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
263*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
264*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
265*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
266*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
267*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
268*0Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
269*0Sstevel@tonic-gate 		}
270*0Sstevel@tonic-gate 	},
271*0Sstevel@tonic-gate 	{ SBD_CMD_POWERON,
272*0Sstevel@tonic-gate 		{
273*0Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
274*0Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
275*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
276*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
277*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
278*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
279*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
280*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
281*0Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
282*0Sstevel@tonic-gate 		}
283*0Sstevel@tonic-gate 	},
284*0Sstevel@tonic-gate 	{ SBD_CMD_POWEROFF,
285*0Sstevel@tonic-gate 		{
286*0Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
287*0Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
288*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
289*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
290*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
291*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
292*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
293*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
294*0Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
295*0Sstevel@tonic-gate 		}
296*0Sstevel@tonic-gate 	},
297*0Sstevel@tonic-gate 	{ SBD_CMD_TEST,
298*0Sstevel@tonic-gate 		{
299*0Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
300*0Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
301*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
302*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
303*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
304*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
305*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
306*0Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
307*0Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
308*0Sstevel@tonic-gate 		}
309*0Sstevel@tonic-gate 	},
310*0Sstevel@tonic-gate };
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate /*
313*0Sstevel@tonic-gate  * Global R/W lock to synchronize access across
314*0Sstevel@tonic-gate  * multiple boards.  Users wanting multi-board access
315*0Sstevel@tonic-gate  * must grab WRITE lock, others must grab READ lock.
316*0Sstevel@tonic-gate  */
317*0Sstevel@tonic-gate krwlock_t	dr_grwlock;
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate /*
320*0Sstevel@tonic-gate  * Head of the boardlist used as a reference point for
321*0Sstevel@tonic-gate  * locating board structs.
322*0Sstevel@tonic-gate  * TODO: eliminate dr_boardlist
323*0Sstevel@tonic-gate  */
324*0Sstevel@tonic-gate dr_board_t	*dr_boardlist;
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate /*
327*0Sstevel@tonic-gate  * DR support functions.
328*0Sstevel@tonic-gate  */
329*0Sstevel@tonic-gate static dr_devset_t	dr_dev2devset(sbd_comp_id_t *cid);
330*0Sstevel@tonic-gate static int		dr_check_transition(dr_board_t *bp,
331*0Sstevel@tonic-gate 					dr_devset_t *devsetp,
332*0Sstevel@tonic-gate 					struct dr_state_trans *transp,
333*0Sstevel@tonic-gate 					int cmd);
334*0Sstevel@tonic-gate static int		dr_check_unit_attached(dr_common_unit_t *dp);
335*0Sstevel@tonic-gate static sbd_error_t	*dr_init_devlists(dr_board_t *bp);
336*0Sstevel@tonic-gate static void		dr_board_discovery(dr_board_t *bp);
337*0Sstevel@tonic-gate static int		dr_board_init(dr_board_t *bp, dev_info_t *dip,
338*0Sstevel@tonic-gate 					int bd);
339*0Sstevel@tonic-gate static void		dr_board_destroy(dr_board_t *bp);
340*0Sstevel@tonic-gate static void		dr_board_transition(dr_board_t *bp, dr_state_t st);
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate /*
343*0Sstevel@tonic-gate  * DR driver (DDI) entry points.
344*0Sstevel@tonic-gate  */
345*0Sstevel@tonic-gate static int	dr_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
346*0Sstevel@tonic-gate 				void *arg, void **result);
347*0Sstevel@tonic-gate static int	dr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
348*0Sstevel@tonic-gate static int	dr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
349*0Sstevel@tonic-gate static int	dr_probe(dev_info_t *dip);
350*0Sstevel@tonic-gate static int	dr_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
351*0Sstevel@tonic-gate 				cred_t *cred_p, int *rval_p);
352*0Sstevel@tonic-gate static int	dr_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
353*0Sstevel@tonic-gate static int	dr_open(dev_t *dev, int flag, int otyp, cred_t *cred_p);
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate /*
356*0Sstevel@tonic-gate  * DR command processing operations.
357*0Sstevel@tonic-gate  */
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate static int	dr_copyin_iocmd(dr_handle_t *hp);
360*0Sstevel@tonic-gate static int	dr_copyout_iocmd(dr_handle_t *hp);
361*0Sstevel@tonic-gate static int	dr_copyout_errs(dr_handle_t *hp);
362*0Sstevel@tonic-gate static int	dr_pre_op(dr_handle_t *hp);
363*0Sstevel@tonic-gate static int	dr_post_op(dr_handle_t *hp);
364*0Sstevel@tonic-gate static int	dr_exec_op(dr_handle_t *hp);
365*0Sstevel@tonic-gate static void	dr_assign_board(dr_handle_t *hp);
366*0Sstevel@tonic-gate static void	dr_unassign_board(dr_handle_t *hp);
367*0Sstevel@tonic-gate static void	dr_connect(dr_handle_t *hp);
368*0Sstevel@tonic-gate static int	dr_disconnect(dr_handle_t *hp);
369*0Sstevel@tonic-gate static void	dr_dev_configure(dr_handle_t *hp);
370*0Sstevel@tonic-gate static void	dr_dev_release(dr_handle_t *hp);
371*0Sstevel@tonic-gate static int	dr_dev_unconfigure(dr_handle_t *hp);
372*0Sstevel@tonic-gate static void	dr_dev_cancel(dr_handle_t *hp);
373*0Sstevel@tonic-gate static int	dr_dev_status(dr_handle_t *hp);
374*0Sstevel@tonic-gate static int	dr_get_ncm(dr_handle_t *hp);
375*0Sstevel@tonic-gate static int	dr_pt_ioctl(dr_handle_t *hp);
376*0Sstevel@tonic-gate static void	dr_poweron_board(dr_handle_t *hp);
377*0Sstevel@tonic-gate static void	dr_poweroff_board(dr_handle_t *hp);
378*0Sstevel@tonic-gate static void	dr_test_board(dr_handle_t *hp);
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate /*
383*0Sstevel@tonic-gate  * Autoconfiguration data structures
384*0Sstevel@tonic-gate  */
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate struct cb_ops dr_cb_ops = {
387*0Sstevel@tonic-gate 	dr_open,	/* open */
388*0Sstevel@tonic-gate 	dr_close,	/* close */
389*0Sstevel@tonic-gate 	nodev,		/* strategy */
390*0Sstevel@tonic-gate 	nodev,		/* print */
391*0Sstevel@tonic-gate 	nodev,		/* dump */
392*0Sstevel@tonic-gate 	nodev,		/* read */
393*0Sstevel@tonic-gate 	nodev,		/* write */
394*0Sstevel@tonic-gate 	dr_ioctl,	/* ioctl */
395*0Sstevel@tonic-gate 	nodev,		/* devmap */
396*0Sstevel@tonic-gate 	nodev,		/* mmap */
397*0Sstevel@tonic-gate 	nodev,		/* segmap */
398*0Sstevel@tonic-gate 	nochpoll,	/* chpoll */
399*0Sstevel@tonic-gate 	ddi_prop_op,	/* cb_prop_op */
400*0Sstevel@tonic-gate 	NULL,		/* struct streamtab */
401*0Sstevel@tonic-gate 	D_NEW | D_MP | D_MTSAFE,	/* compatibility flags */
402*0Sstevel@tonic-gate 	CB_REV,		/* Rev */
403*0Sstevel@tonic-gate 	nodev,		/* cb_aread */
404*0Sstevel@tonic-gate 	nodev		/* cb_awrite */
405*0Sstevel@tonic-gate };
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate struct dev_ops dr_dev_ops = {
408*0Sstevel@tonic-gate 	DEVO_REV,	/* build version */
409*0Sstevel@tonic-gate 	0,		/* dev ref count */
410*0Sstevel@tonic-gate 	dr_getinfo,	/* getinfo */
411*0Sstevel@tonic-gate 	nulldev,	/* identify */
412*0Sstevel@tonic-gate 	dr_probe,	/* probe */
413*0Sstevel@tonic-gate 	dr_attach,	/* attach */
414*0Sstevel@tonic-gate 	dr_detach,	/* detach */
415*0Sstevel@tonic-gate 	nodev,		/* reset */
416*0Sstevel@tonic-gate 	&dr_cb_ops,	/* cb_ops */
417*0Sstevel@tonic-gate 	(struct bus_ops *)NULL, /* bus ops */
418*0Sstevel@tonic-gate 	NULL		/* power */
419*0Sstevel@tonic-gate };
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate extern struct mod_ops mod_driverops;
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate static struct modldrv modldrv = {
424*0Sstevel@tonic-gate 	&mod_driverops,
425*0Sstevel@tonic-gate 	"Dynamic Reconfiguration %I%",
426*0Sstevel@tonic-gate 	&dr_dev_ops
427*0Sstevel@tonic-gate };
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
430*0Sstevel@tonic-gate 	MODREV_1,
431*0Sstevel@tonic-gate 	(void *)&modldrv,
432*0Sstevel@tonic-gate 	NULL
433*0Sstevel@tonic-gate };
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate /*
436*0Sstevel@tonic-gate  * Driver entry points.
437*0Sstevel@tonic-gate  */
438*0Sstevel@tonic-gate int
439*0Sstevel@tonic-gate _init(void)
440*0Sstevel@tonic-gate {
441*0Sstevel@tonic-gate 	int	err;
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate 	/*
444*0Sstevel@tonic-gate 	 * If you need to support multiple nodes (instances), then
445*0Sstevel@tonic-gate 	 * whatever the maximum number of supported nodes is would
446*0Sstevel@tonic-gate 	 * need to passed as the third parameter to ddi_soft_state_init().
447*0Sstevel@tonic-gate 	 * Alternative would be to dynamically fini and re-init the
448*0Sstevel@tonic-gate 	 * soft state structure each time a node is attached.
449*0Sstevel@tonic-gate 	 */
450*0Sstevel@tonic-gate 	err = ddi_soft_state_init((void **)&dr_g.softsp,
451*0Sstevel@tonic-gate 					sizeof (dr_softstate_t), 1);
452*0Sstevel@tonic-gate 	if (err)
453*0Sstevel@tonic-gate 		return (err);
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	mutex_init(&dr_g.lock, NULL, MUTEX_DRIVER, NULL);
456*0Sstevel@tonic-gate 	rw_init(&dr_grwlock, NULL, RW_DEFAULT, NULL);
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	return (mod_install(&modlinkage));
459*0Sstevel@tonic-gate }
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate int
462*0Sstevel@tonic-gate _fini(void)
463*0Sstevel@tonic-gate {
464*0Sstevel@tonic-gate 	int	err;
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	if ((err = mod_remove(&modlinkage)) != 0)
467*0Sstevel@tonic-gate 		return (err);
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 	mutex_destroy(&dr_g.lock);
470*0Sstevel@tonic-gate 	rw_destroy(&dr_grwlock);
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	ddi_soft_state_fini((void **)&dr_g.softsp);
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	return (0);
475*0Sstevel@tonic-gate }
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate int
478*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
479*0Sstevel@tonic-gate {
480*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
481*0Sstevel@tonic-gate }
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate /*ARGSUSED1*/
484*0Sstevel@tonic-gate static int
485*0Sstevel@tonic-gate dr_open(dev_t *dev, int flag, int otyp, cred_t *cred_p)
486*0Sstevel@tonic-gate {
487*0Sstevel@tonic-gate 	int		 instance;
488*0Sstevel@tonic-gate 	dr_softstate_t	*softsp;
489*0Sstevel@tonic-gate 	dr_board_t	*bp;
490*0Sstevel@tonic-gate 	/*
491*0Sstevel@tonic-gate 	 * Don't open unless we've attached.
492*0Sstevel@tonic-gate 	 */
493*0Sstevel@tonic-gate 	instance = DR_MINOR2INST(getminor(*dev));
494*0Sstevel@tonic-gate 	softsp = ddi_get_soft_state(dr_g.softsp, instance);
495*0Sstevel@tonic-gate 	if (softsp == NULL)
496*0Sstevel@tonic-gate 		return (ENXIO);
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate 	mutex_enter(&softsp->i_lock);
499*0Sstevel@tonic-gate 	if (!softsp->dr_initialized) {
500*0Sstevel@tonic-gate 		int		 bd;
501*0Sstevel@tonic-gate 		int		 rv = 0;
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 		bp = softsp->boards;
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 		/* initialize each array element */
506*0Sstevel@tonic-gate 		for (bd = 0; bd < MAX_BOARDS; bd++, bp++) {
507*0Sstevel@tonic-gate 			rv = dr_board_init(bp, softsp->dip, bd);
508*0Sstevel@tonic-gate 			if (rv)
509*0Sstevel@tonic-gate 				break;
510*0Sstevel@tonic-gate 		}
511*0Sstevel@tonic-gate 
512*0Sstevel@tonic-gate 		if (rv == 0) {
513*0Sstevel@tonic-gate 			softsp->dr_initialized = 1;
514*0Sstevel@tonic-gate 		} else {
515*0Sstevel@tonic-gate 			/* destroy elements initialized thus far */
516*0Sstevel@tonic-gate 			while (--bp >= softsp->boards)
517*0Sstevel@tonic-gate 				dr_board_destroy(bp);
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 			/* TODO: should this be another errno val ? */
521*0Sstevel@tonic-gate 			mutex_exit(&softsp->i_lock);
522*0Sstevel@tonic-gate 			return (ENXIO);
523*0Sstevel@tonic-gate 		}
524*0Sstevel@tonic-gate 	}
525*0Sstevel@tonic-gate 	mutex_exit(&softsp->i_lock);
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 	bp = &softsp->boards[DR_MINOR2BNUM(getminor(*dev))];
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	/*
530*0Sstevel@tonic-gate 	 * prevent opening of a dyn-ap for a board
531*0Sstevel@tonic-gate 	 * that does not exist
532*0Sstevel@tonic-gate 	 */
533*0Sstevel@tonic-gate 	if (!bp->b_assigned) {
534*0Sstevel@tonic-gate 		if (drmach_board_lookup(bp->b_num, &bp->b_id) != 0)
535*0Sstevel@tonic-gate 			return (ENODEV);
536*0Sstevel@tonic-gate 	}
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 	return (0);
539*0Sstevel@tonic-gate }
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate /*ARGSUSED*/
542*0Sstevel@tonic-gate static int
543*0Sstevel@tonic-gate dr_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
544*0Sstevel@tonic-gate {
545*0Sstevel@tonic-gate 	return (0);
546*0Sstevel@tonic-gate }
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate /*
549*0Sstevel@tonic-gate  * Enable/disable Starcat DR features.
550*0Sstevel@tonic-gate  */
551*0Sstevel@tonic-gate #ifndef _STARFIRE
552*0Sstevel@tonic-gate int dr_enable = 1;
553*0Sstevel@tonic-gate int slot1_dr_enable = 1;
554*0Sstevel@tonic-gate #endif /* _STARFIRE */
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate /*ARGSUSED3*/
557*0Sstevel@tonic-gate static int
558*0Sstevel@tonic-gate dr_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
559*0Sstevel@tonic-gate 	cred_t *cred_p, int *rval_p)
560*0Sstevel@tonic-gate {
561*0Sstevel@tonic-gate 	static int	dr_dev_type_to_nt(char *);
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	int		rv = 0;
564*0Sstevel@tonic-gate 	int		instance;
565*0Sstevel@tonic-gate 	int		bd;
566*0Sstevel@tonic-gate 	dr_handle_t	*hp;
567*0Sstevel@tonic-gate 	dr_softstate_t	*softsp;
568*0Sstevel@tonic-gate 	static fn_t	f = "dr_ioctl";
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 	instance = DR_MINOR2INST(getminor(dev));
573*0Sstevel@tonic-gate 	softsp = ddi_get_soft_state(dr_g.softsp, instance);
574*0Sstevel@tonic-gate 	if (softsp == NULL) {
575*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "dr%d: module not yet attached", instance);
576*0Sstevel@tonic-gate 		return (ENXIO);
577*0Sstevel@tonic-gate 	}
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate #ifndef _STARFIRE
580*0Sstevel@tonic-gate 	if (!dr_enable) {
581*0Sstevel@tonic-gate 		switch (cmd) {
582*0Sstevel@tonic-gate 			case SBD_CMD_STATUS:
583*0Sstevel@tonic-gate 			case SBD_CMD_GETNCM:
584*0Sstevel@tonic-gate 			case SBD_CMD_PASSTHRU:
585*0Sstevel@tonic-gate 				break;
586*0Sstevel@tonic-gate 			default:
587*0Sstevel@tonic-gate 				return (ENOTSUP);
588*0Sstevel@tonic-gate 		}
589*0Sstevel@tonic-gate 	}
590*0Sstevel@tonic-gate #endif /* _STARFIRE */
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate 	bd = DR_MINOR2BNUM(getminor(dev));
593*0Sstevel@tonic-gate 	if (bd >= MAX_BOARDS)
594*0Sstevel@tonic-gate 		return (ENXIO);
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate #ifndef _STARFIRE
597*0Sstevel@tonic-gate 	if (!slot1_dr_enable && (bd & 0x1)) {
598*0Sstevel@tonic-gate 		switch (cmd) {
599*0Sstevel@tonic-gate 			case SBD_CMD_STATUS:
600*0Sstevel@tonic-gate 			case SBD_CMD_GETNCM:
601*0Sstevel@tonic-gate 			case SBD_CMD_PASSTHRU:
602*0Sstevel@tonic-gate 				break;
603*0Sstevel@tonic-gate 			default:
604*0Sstevel@tonic-gate 				return (ENOTSUP);
605*0Sstevel@tonic-gate 		}
606*0Sstevel@tonic-gate 	}
607*0Sstevel@tonic-gate #endif /* _STARFIRE */
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate 	/* get and initialize storage for new handle */
610*0Sstevel@tonic-gate 	hp = GETSTRUCT(dr_handle_t, 1);
611*0Sstevel@tonic-gate 	hp->h_bd = &softsp->boards[bd];
612*0Sstevel@tonic-gate 	hp->h_err = NULL;
613*0Sstevel@tonic-gate 	hp->h_dev = getminor(dev);
614*0Sstevel@tonic-gate 	hp->h_cmd = cmd;
615*0Sstevel@tonic-gate 	hp->h_mode = mode;
616*0Sstevel@tonic-gate 	hp->h_iap = (sbd_ioctl_arg_t *)arg;
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 	/* copy sbd command into handle */
619*0Sstevel@tonic-gate 	rv = dr_copyin_iocmd(hp);
620*0Sstevel@tonic-gate 	if (rv) {
621*0Sstevel@tonic-gate 		FREESTRUCT(hp, dr_handle_t, 1);
622*0Sstevel@tonic-gate 		return (EINVAL);
623*0Sstevel@tonic-gate 	}
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	/* translate canonical name to component type */
626*0Sstevel@tonic-gate 	if (hp->h_sbdcmd.cmd_cm.c_id.c_name[0] != '\0') {
627*0Sstevel@tonic-gate 		hp->h_sbdcmd.cmd_cm.c_id.c_type =
628*0Sstevel@tonic-gate 			dr_dev_type_to_nt(hp->h_sbdcmd.cmd_cm.c_id.c_name);
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 		PR_ALL("%s: c_name = %s, c_type = %d\n",
631*0Sstevel@tonic-gate 			f,
632*0Sstevel@tonic-gate 			hp->h_sbdcmd.cmd_cm.c_id.c_name,
633*0Sstevel@tonic-gate 			hp->h_sbdcmd.cmd_cm.c_id.c_type);
634*0Sstevel@tonic-gate 	} else {
635*0Sstevel@tonic-gate 		/*EMPTY*/
636*0Sstevel@tonic-gate 		PR_ALL("%s: c_name is NULL\n", f);
637*0Sstevel@tonic-gate 	}
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 	/* determine scope of operation */
640*0Sstevel@tonic-gate 	hp->h_devset = dr_dev2devset(&hp->h_sbdcmd.cmd_cm.c_id);
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 	switch (hp->h_cmd) {
643*0Sstevel@tonic-gate 	case SBD_CMD_STATUS:
644*0Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
645*0Sstevel@tonic-gate 		/* no locks needed for these commands */
646*0Sstevel@tonic-gate 		break;
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	default:
649*0Sstevel@tonic-gate 		rw_enter(&dr_grwlock, RW_WRITER);
650*0Sstevel@tonic-gate 		mutex_enter(&hp->h_bd->b_lock);
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 		/*
653*0Sstevel@tonic-gate 		 * If we're dealing with memory at all, then we have
654*0Sstevel@tonic-gate 		 * to keep the "exclusive" global lock held.  This is
655*0Sstevel@tonic-gate 		 * necessary since we will probably need to look at
656*0Sstevel@tonic-gate 		 * multiple board structs.  Otherwise, we only have
657*0Sstevel@tonic-gate 		 * to deal with the board in question and so can drop
658*0Sstevel@tonic-gate 		 * the global lock to "shared".
659*0Sstevel@tonic-gate 		 */
660*0Sstevel@tonic-gate 		rv = DEVSET_IN_SET(hp->h_devset, SBD_COMP_MEM, DEVSET_ANYUNIT);
661*0Sstevel@tonic-gate 		if (rv == 0)
662*0Sstevel@tonic-gate 			rw_downgrade(&dr_grwlock);
663*0Sstevel@tonic-gate 		break;
664*0Sstevel@tonic-gate 	}
665*0Sstevel@tonic-gate 	rv = 0;
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	if (rv == 0)
668*0Sstevel@tonic-gate 		rv = dr_pre_op(hp);
669*0Sstevel@tonic-gate 	if (rv == 0)
670*0Sstevel@tonic-gate 		rv = dr_exec_op(hp);
671*0Sstevel@tonic-gate 	if (rv == 0)
672*0Sstevel@tonic-gate 		rv = dr_post_op(hp);
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 	if (rv == -1)
675*0Sstevel@tonic-gate 		rv = EIO;
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 	if (hp->h_err != NULL)
678*0Sstevel@tonic-gate 		if (!(rv = dr_copyout_errs(hp)))
679*0Sstevel@tonic-gate 			rv = EIO;
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 	/* undo locking, if any, done before dr_pre_op */
682*0Sstevel@tonic-gate 	switch (hp->h_cmd) {
683*0Sstevel@tonic-gate 	case SBD_CMD_STATUS:
684*0Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
685*0Sstevel@tonic-gate 		break;
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 	case SBD_CMD_ASSIGN:
688*0Sstevel@tonic-gate 	case SBD_CMD_UNASSIGN:
689*0Sstevel@tonic-gate 	case SBD_CMD_POWERON:
690*0Sstevel@tonic-gate 	case SBD_CMD_POWEROFF:
691*0Sstevel@tonic-gate 	case SBD_CMD_CONNECT:
692*0Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:
693*0Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:
694*0Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:
695*0Sstevel@tonic-gate 		/* Board changed state. Log a sysevent. */
696*0Sstevel@tonic-gate 		if (rv == 0)
697*0Sstevel@tonic-gate 			(void) drmach_log_sysevent(hp->h_bd->b_num, "",
698*0Sstevel@tonic-gate 						    SE_SLEEP, 1);
699*0Sstevel@tonic-gate 		/* Fall through */
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate 	default:
702*0Sstevel@tonic-gate 		mutex_exit(&hp->h_bd->b_lock);
703*0Sstevel@tonic-gate 		rw_exit(&dr_grwlock);
704*0Sstevel@tonic-gate 	}
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 	if (hp->h_opts.size != 0)
707*0Sstevel@tonic-gate 		FREESTRUCT(hp->h_opts.copts, char, hp->h_opts.size);
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 	FREESTRUCT(hp, dr_handle_t, 1);
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 	return (rv);
712*0Sstevel@tonic-gate }
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate /*ARGSUSED*/
715*0Sstevel@tonic-gate static int
716*0Sstevel@tonic-gate dr_probe(dev_info_t *dip)
717*0Sstevel@tonic-gate {
718*0Sstevel@tonic-gate 	return (DDI_PROBE_SUCCESS);
719*0Sstevel@tonic-gate }
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate static int
722*0Sstevel@tonic-gate dr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
723*0Sstevel@tonic-gate {
724*0Sstevel@tonic-gate 	int		rv, rv2;
725*0Sstevel@tonic-gate 	int		bd;
726*0Sstevel@tonic-gate 	int 		instance;
727*0Sstevel@tonic-gate 	sbd_error_t	*err;
728*0Sstevel@tonic-gate 	dr_softstate_t	*softsp;
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 	switch (cmd) {
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 	case DDI_ATTACH:
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 		rw_enter(&dr_grwlock, RW_WRITER);
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 		rv = ddi_soft_state_zalloc(dr_g.softsp, instance);
739*0Sstevel@tonic-gate 		if (rv != DDI_SUCCESS) {
740*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "dr%d: failed to alloc soft-state",
741*0Sstevel@tonic-gate 				instance);
742*0Sstevel@tonic-gate 			return (DDI_FAILURE);
743*0Sstevel@tonic-gate 		}
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 		/* initialize softstate structure */
746*0Sstevel@tonic-gate 		softsp = ddi_get_soft_state(dr_g.softsp, instance);
747*0Sstevel@tonic-gate 		softsp->dip = dip;
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 		mutex_init(&softsp->i_lock, NULL, MUTEX_DRIVER, NULL);
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate 		/* allocate board array (aka boardlist) */
752*0Sstevel@tonic-gate 		softsp->boards = GETSTRUCT(dr_board_t, MAX_BOARDS);
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 		/* TODO: eliminate dr_boardlist */
755*0Sstevel@tonic-gate 		dr_boardlist = softsp->boards;
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate 		/* initialize each array element */
758*0Sstevel@tonic-gate 		rv = DDI_SUCCESS;
759*0Sstevel@tonic-gate 		for (bd = 0; bd < MAX_BOARDS; bd++) {
760*0Sstevel@tonic-gate 			dr_board_t	*bp = &softsp->boards[bd];
761*0Sstevel@tonic-gate 			char		*p, *name;
762*0Sstevel@tonic-gate 			int		 l, minor_num;
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 			/*
765*0Sstevel@tonic-gate 			 * initialized board attachment point path
766*0Sstevel@tonic-gate 			 * (relative to pseudo) in a form immediately
767*0Sstevel@tonic-gate 			 * reusable as an cfgadm command argument.
768*0Sstevel@tonic-gate 			 * TODO: clean this up
769*0Sstevel@tonic-gate 			 */
770*0Sstevel@tonic-gate 			p = bp->b_path;
771*0Sstevel@tonic-gate 			l = sizeof (bp->b_path);
772*0Sstevel@tonic-gate 			(void) snprintf(p, l, "dr@%d:", instance);
773*0Sstevel@tonic-gate 			while (*p != '\0') {
774*0Sstevel@tonic-gate 				l--;
775*0Sstevel@tonic-gate 				p++;
776*0Sstevel@tonic-gate 			}
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 			name = p;
779*0Sstevel@tonic-gate 			err = drmach_board_name(bd, p, l);
780*0Sstevel@tonic-gate 			if (err) {
781*0Sstevel@tonic-gate 				sbd_err_clear(&err);
782*0Sstevel@tonic-gate 				rv = DDI_FAILURE;
783*0Sstevel@tonic-gate 				break;
784*0Sstevel@tonic-gate 			}
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 			minor_num = DR_MAKE_MINOR(instance, bd);
787*0Sstevel@tonic-gate 			rv = ddi_create_minor_node(dip, name, S_IFCHR,
788*0Sstevel@tonic-gate 				minor_num, DDI_NT_SBD_ATTACHMENT_POINT, NULL);
789*0Sstevel@tonic-gate 			if (rv != DDI_SUCCESS)
790*0Sstevel@tonic-gate 				rv = DDI_FAILURE;
791*0Sstevel@tonic-gate 		}
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 		if (rv == DDI_SUCCESS) {
794*0Sstevel@tonic-gate 			/*
795*0Sstevel@tonic-gate 			 * Announce the node's presence.
796*0Sstevel@tonic-gate 			 */
797*0Sstevel@tonic-gate 			ddi_report_dev(dip);
798*0Sstevel@tonic-gate 		} else {
799*0Sstevel@tonic-gate 			ddi_remove_minor_node(dip, NULL);
800*0Sstevel@tonic-gate 		}
801*0Sstevel@tonic-gate 		/*
802*0Sstevel@tonic-gate 		 * Init registered unsafe devs.
803*0Sstevel@tonic-gate 		 */
804*0Sstevel@tonic-gate 		dr_unsafe_devs.devnames = NULL;
805*0Sstevel@tonic-gate 		rv2 = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
806*0Sstevel@tonic-gate 			DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
807*0Sstevel@tonic-gate 			"unsupported-io-drivers", &dr_unsafe_devs.devnames,
808*0Sstevel@tonic-gate 			&dr_unsafe_devs.ndevs);
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate 		if (rv2 != DDI_PROP_SUCCESS)
811*0Sstevel@tonic-gate 			dr_unsafe_devs.ndevs = 0;
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate 		rw_exit(&dr_grwlock);
814*0Sstevel@tonic-gate 		return (rv);
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate 	default:
817*0Sstevel@tonic-gate 		return (DDI_FAILURE);
818*0Sstevel@tonic-gate 	}
819*0Sstevel@tonic-gate 
820*0Sstevel@tonic-gate 	/*NOTREACHED*/
821*0Sstevel@tonic-gate }
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate static int
824*0Sstevel@tonic-gate dr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
825*0Sstevel@tonic-gate {
826*0Sstevel@tonic-gate 	int 		instance;
827*0Sstevel@tonic-gate 	dr_softstate_t	*softsp;
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	switch (cmd) {
830*0Sstevel@tonic-gate 	case DDI_DETACH:
831*0Sstevel@tonic-gate 		if (!dr_modunload_okay)
832*0Sstevel@tonic-gate 			return (DDI_FAILURE);
833*0Sstevel@tonic-gate 
834*0Sstevel@tonic-gate 		rw_enter(&dr_grwlock, RW_WRITER);
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 		instance = ddi_get_instance(dip);
837*0Sstevel@tonic-gate 		softsp = ddi_get_soft_state(dr_g.softsp, instance);
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 		/* TODO: eliminate dr_boardlist */
840*0Sstevel@tonic-gate 		ASSERT(softsp->boards == dr_boardlist);
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 		/* remove all minor nodes */
843*0Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
844*0Sstevel@tonic-gate 
845*0Sstevel@tonic-gate 		if (softsp->dr_initialized) {
846*0Sstevel@tonic-gate 			int bd;
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate 			for (bd = 0; bd < MAX_BOARDS; bd++)
849*0Sstevel@tonic-gate 				dr_board_destroy(&softsp->boards[bd]);
850*0Sstevel@tonic-gate 		}
851*0Sstevel@tonic-gate 
852*0Sstevel@tonic-gate 		FREESTRUCT(softsp->boards, dr_board_t, MAX_BOARDS);
853*0Sstevel@tonic-gate 		mutex_destroy(&softsp->i_lock);
854*0Sstevel@tonic-gate 		ddi_soft_state_free(dr_g.softsp, instance);
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate 		rw_exit(&dr_grwlock);
857*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate 	default:
860*0Sstevel@tonic-gate 		return (DDI_FAILURE);
861*0Sstevel@tonic-gate 	}
862*0Sstevel@tonic-gate 	/*NOTREACHED*/
863*0Sstevel@tonic-gate }
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate static int
866*0Sstevel@tonic-gate dr_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
867*0Sstevel@tonic-gate {
868*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip))
869*0Sstevel@tonic-gate 
870*0Sstevel@tonic-gate 	dev_t		dev = (dev_t)arg;
871*0Sstevel@tonic-gate 	int		instance, error;
872*0Sstevel@tonic-gate 	dr_softstate_t	*softsp;
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 	*result = NULL;
875*0Sstevel@tonic-gate 	error = DDI_SUCCESS;
876*0Sstevel@tonic-gate 	instance = DR_MINOR2INST(getminor(dev));
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 	switch (cmd) {
879*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
880*0Sstevel@tonic-gate 		softsp = ddi_get_soft_state(dr_g.softsp, instance);
881*0Sstevel@tonic-gate 		if (softsp == NULL)
882*0Sstevel@tonic-gate 			return (DDI_FAILURE);
883*0Sstevel@tonic-gate 		*result = (void *)softsp->dip;
884*0Sstevel@tonic-gate 		break;
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
887*0Sstevel@tonic-gate 		*result = (void *)instance;
888*0Sstevel@tonic-gate 		break;
889*0Sstevel@tonic-gate 
890*0Sstevel@tonic-gate 	default:
891*0Sstevel@tonic-gate 		error = DDI_FAILURE;
892*0Sstevel@tonic-gate 		break;
893*0Sstevel@tonic-gate 	}
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 	return (error);
896*0Sstevel@tonic-gate }
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate /*
899*0Sstevel@tonic-gate  * DR operations.
900*0Sstevel@tonic-gate  */
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate static int
903*0Sstevel@tonic-gate dr_copyin_iocmd(dr_handle_t *hp)
904*0Sstevel@tonic-gate {
905*0Sstevel@tonic-gate 	static fn_t	f = "dr_copyin_iocmd";
906*0Sstevel@tonic-gate 	sbd_cmd_t	*scp = &hp->h_sbdcmd;
907*0Sstevel@tonic-gate 
908*0Sstevel@tonic-gate 	if (hp->h_iap == NULL)
909*0Sstevel@tonic-gate 		return (EINVAL);
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate 	bzero((caddr_t)scp, sizeof (sbd_cmd_t));
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
914*0Sstevel@tonic-gate 	if (ddi_model_convert_from(hp->h_mode & FMODELS) == DDI_MODEL_ILP32) {
915*0Sstevel@tonic-gate 		sbd_cmd32_t	scmd32;
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate 		bzero((caddr_t)&scmd32, sizeof (sbd_cmd32_t));
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate 		if (ddi_copyin((void *)hp->h_iap, (void *)&scmd32,
920*0Sstevel@tonic-gate 				sizeof (sbd_cmd32_t), hp->h_mode)) {
921*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
922*0Sstevel@tonic-gate 				"%s: (32bit) failed to copyin "
923*0Sstevel@tonic-gate 					"sbdcmd-struct", f);
924*0Sstevel@tonic-gate 			return (EFAULT);
925*0Sstevel@tonic-gate 		}
926*0Sstevel@tonic-gate 		scp->cmd_cm.c_id.c_type = scmd32.cmd_cm.c_id.c_type;
927*0Sstevel@tonic-gate 		scp->cmd_cm.c_id.c_unit = scmd32.cmd_cm.c_id.c_unit;
928*0Sstevel@tonic-gate 		bcopy(&scmd32.cmd_cm.c_id.c_name[0],
929*0Sstevel@tonic-gate 			&scp->cmd_cm.c_id.c_name[0], OBP_MAXPROPNAME);
930*0Sstevel@tonic-gate 		scp->cmd_cm.c_flags = scmd32.cmd_cm.c_flags;
931*0Sstevel@tonic-gate 		scp->cmd_cm.c_len = scmd32.cmd_cm.c_len;
932*0Sstevel@tonic-gate 		scp->cmd_cm.c_opts = (caddr_t)scmd32.cmd_cm.c_opts;
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 		switch (hp->h_cmd) {
935*0Sstevel@tonic-gate 		case SBD_CMD_STATUS:
936*0Sstevel@tonic-gate 			scp->cmd_stat.s_nbytes = scmd32.cmd_stat.s_nbytes;
937*0Sstevel@tonic-gate 			scp->cmd_stat.s_statp =
938*0Sstevel@tonic-gate 				(caddr_t)scmd32.cmd_stat.s_statp;
939*0Sstevel@tonic-gate 			break;
940*0Sstevel@tonic-gate 		default:
941*0Sstevel@tonic-gate 			break;
942*0Sstevel@tonic-gate 
943*0Sstevel@tonic-gate 		}
944*0Sstevel@tonic-gate 	} else
945*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
946*0Sstevel@tonic-gate 	if (ddi_copyin((void *)hp->h_iap, (void *)scp,
947*0Sstevel@tonic-gate 			sizeof (sbd_cmd_t), hp->h_mode) != 0) {
948*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
949*0Sstevel@tonic-gate 			"%s: failed to copyin sbdcmd-struct", f);
950*0Sstevel@tonic-gate 		return (EFAULT);
951*0Sstevel@tonic-gate 	}
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 	if ((hp->h_opts.size = scp->cmd_cm.c_len) != 0) {
954*0Sstevel@tonic-gate 		hp->h_opts.copts = GETSTRUCT(char, scp->cmd_cm.c_len + 1);
955*0Sstevel@tonic-gate 		++hp->h_opts.size;
956*0Sstevel@tonic-gate 		if (ddi_copyin((void *)scp->cmd_cm.c_opts,
957*0Sstevel@tonic-gate 			(void *)hp->h_opts.copts,
958*0Sstevel@tonic-gate 			scp->cmd_cm.c_len, hp->h_mode) != 0) {
959*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: failed to copyin options", f);
960*0Sstevel@tonic-gate 			return (EFAULT);
961*0Sstevel@tonic-gate 		}
962*0Sstevel@tonic-gate 	}
963*0Sstevel@tonic-gate 	return (0);
964*0Sstevel@tonic-gate }
965*0Sstevel@tonic-gate 
966*0Sstevel@tonic-gate static int
967*0Sstevel@tonic-gate dr_copyout_iocmd(dr_handle_t *hp)
968*0Sstevel@tonic-gate {
969*0Sstevel@tonic-gate 	static fn_t	f = "dr_copyout_iocmd";
970*0Sstevel@tonic-gate 	sbd_cmd_t	*scp = &hp->h_sbdcmd;
971*0Sstevel@tonic-gate 
972*0Sstevel@tonic-gate 	if (hp->h_iap == NULL)
973*0Sstevel@tonic-gate 		return (EINVAL);
974*0Sstevel@tonic-gate 
975*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
976*0Sstevel@tonic-gate 	if (ddi_model_convert_from(hp->h_mode & FMODELS) == DDI_MODEL_ILP32) {
977*0Sstevel@tonic-gate 		sbd_cmd32_t	scmd32;
978*0Sstevel@tonic-gate 
979*0Sstevel@tonic-gate 		scmd32.cmd_cm.c_id.c_type = scp->cmd_cm.c_id.c_type;
980*0Sstevel@tonic-gate 		scmd32.cmd_cm.c_id.c_unit = scp->cmd_cm.c_id.c_unit;
981*0Sstevel@tonic-gate 		bcopy(&scp->cmd_cm.c_id.c_name[0],
982*0Sstevel@tonic-gate 			&scmd32.cmd_cm.c_id.c_name[0], OBP_MAXPROPNAME);
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 		scmd32.cmd_cm.c_flags = scp->cmd_cm.c_flags;
985*0Sstevel@tonic-gate 		scmd32.cmd_cm.c_len = scp->cmd_cm.c_len;
986*0Sstevel@tonic-gate 		scmd32.cmd_cm.c_opts = (caddr32_t)scp->cmd_cm.c_opts;
987*0Sstevel@tonic-gate 
988*0Sstevel@tonic-gate 		switch (hp->h_cmd) {
989*0Sstevel@tonic-gate 		case SBD_CMD_GETNCM:
990*0Sstevel@tonic-gate 			scmd32.cmd_getncm.g_ncm = scp->cmd_getncm.g_ncm;
991*0Sstevel@tonic-gate 			break;
992*0Sstevel@tonic-gate 		default:
993*0Sstevel@tonic-gate 			break;
994*0Sstevel@tonic-gate 		}
995*0Sstevel@tonic-gate 
996*0Sstevel@tonic-gate 		if (ddi_copyout((void *)&scmd32, (void *)hp->h_iap,
997*0Sstevel@tonic-gate 				sizeof (sbd_cmd32_t), hp->h_mode)) {
998*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
999*0Sstevel@tonic-gate 				"%s: (32bit) failed to copyout "
1000*0Sstevel@tonic-gate 					"sbdcmd-struct", f);
1001*0Sstevel@tonic-gate 			return (EFAULT);
1002*0Sstevel@tonic-gate 		}
1003*0Sstevel@tonic-gate 	} else
1004*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
1005*0Sstevel@tonic-gate 	if (ddi_copyout((void *)scp, (void *)hp->h_iap,
1006*0Sstevel@tonic-gate 			sizeof (sbd_cmd_t), hp->h_mode) != 0) {
1007*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
1008*0Sstevel@tonic-gate 			"%s: failed to copyout sbdcmd-struct", f);
1009*0Sstevel@tonic-gate 		return (EFAULT);
1010*0Sstevel@tonic-gate 	}
1011*0Sstevel@tonic-gate 
1012*0Sstevel@tonic-gate 	return (0);
1013*0Sstevel@tonic-gate }
1014*0Sstevel@tonic-gate 
1015*0Sstevel@tonic-gate static int
1016*0Sstevel@tonic-gate dr_copyout_errs(dr_handle_t *hp)
1017*0Sstevel@tonic-gate {
1018*0Sstevel@tonic-gate 	static fn_t	f = "dr_copyout_errs";
1019*0Sstevel@tonic-gate 
1020*0Sstevel@tonic-gate 	if (hp->h_err == NULL)
1021*0Sstevel@tonic-gate 		return (0);
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate 	if (hp->h_err->e_code) {
1024*0Sstevel@tonic-gate 		PR_ALL("%s: error %d %s",
1025*0Sstevel@tonic-gate 			f, hp->h_err->e_code, hp->h_err->e_rsc);
1026*0Sstevel@tonic-gate 	}
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
1029*0Sstevel@tonic-gate 	if (ddi_model_convert_from(hp->h_mode & FMODELS) == DDI_MODEL_ILP32) {
1030*0Sstevel@tonic-gate 		sbd_error32_t	*serr32p;
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate 		serr32p = GETSTRUCT(sbd_error32_t, 1);
1033*0Sstevel@tonic-gate 
1034*0Sstevel@tonic-gate 		serr32p->e_code = hp->h_err->e_code;
1035*0Sstevel@tonic-gate 		bcopy(&hp->h_err->e_rsc[0], &serr32p->e_rsc[0],
1036*0Sstevel@tonic-gate 			MAXPATHLEN);
1037*0Sstevel@tonic-gate 		if (ddi_copyout((void *)serr32p,
1038*0Sstevel@tonic-gate 			(void *)&((sbd_ioctl_arg32_t *)hp->h_iap)->i_err,
1039*0Sstevel@tonic-gate 				sizeof (sbd_error32_t), hp->h_mode)) {
1040*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
1041*0Sstevel@tonic-gate 				"%s: (32bit) failed to copyout", f);
1042*0Sstevel@tonic-gate 			return (EFAULT);
1043*0Sstevel@tonic-gate 		}
1044*0Sstevel@tonic-gate 		FREESTRUCT(serr32p, sbd_error32_t, 1);
1045*0Sstevel@tonic-gate 	} else
1046*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
1047*0Sstevel@tonic-gate 	if (ddi_copyout((void *)hp->h_err,
1048*0Sstevel@tonic-gate 		(void *)&hp->h_iap->i_err,
1049*0Sstevel@tonic-gate 			sizeof (sbd_error_t), hp->h_mode)) {
1050*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
1051*0Sstevel@tonic-gate 			"%s: failed to copyout", f);
1052*0Sstevel@tonic-gate 		return (EFAULT);
1053*0Sstevel@tonic-gate 	}
1054*0Sstevel@tonic-gate 
1055*0Sstevel@tonic-gate 	sbd_err_clear(&hp->h_err);
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate 	return (0);
1058*0Sstevel@tonic-gate 
1059*0Sstevel@tonic-gate }
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate /*
1062*0Sstevel@tonic-gate  * pre-op entry point must sbd_err_set_c(), if needed.
1063*0Sstevel@tonic-gate  * Return value of non-zero indicates failure.
1064*0Sstevel@tonic-gate  */
1065*0Sstevel@tonic-gate static int
1066*0Sstevel@tonic-gate dr_pre_op(dr_handle_t *hp)
1067*0Sstevel@tonic-gate {
1068*0Sstevel@tonic-gate 	int		rv = 0, t;
1069*0Sstevel@tonic-gate 	int		cmd, serr = 0;
1070*0Sstevel@tonic-gate 	dr_devset_t	devset;
1071*0Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
1072*0Sstevel@tonic-gate 	dr_handle_t	*shp = hp;
1073*0Sstevel@tonic-gate 	static fn_t	f = "dr_pre_op";
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 	cmd = hp->h_cmd;
1076*0Sstevel@tonic-gate 	devset = shp->h_devset;
1077*0Sstevel@tonic-gate 
1078*0Sstevel@tonic-gate 	PR_ALL("%s (cmd = %s)...\n", f, (uint_t)SBD_CMD_STR(cmd));
1079*0Sstevel@tonic-gate 
1080*0Sstevel@tonic-gate 	hp->h_err = drmach_pre_op(cmd, bp->b_id, &hp->h_opts);
1081*0Sstevel@tonic-gate 	if (hp->h_err != NULL) {
1082*0Sstevel@tonic-gate 		PR_ALL("drmach_pre_op failed for cmd %s(%d)\n",
1083*0Sstevel@tonic-gate 			SBD_CMD_STR(cmd), cmd);
1084*0Sstevel@tonic-gate 		return (-1);
1085*0Sstevel@tonic-gate 	}
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 	/*
1088*0Sstevel@tonic-gate 	 * Check for valid state transitions.
1089*0Sstevel@tonic-gate 	 */
1090*0Sstevel@tonic-gate 	if ((t = CMD2INDEX(cmd)) != -1) {
1091*0Sstevel@tonic-gate 		struct dr_state_trans	*transp;
1092*0Sstevel@tonic-gate 		int			state_err;
1093*0Sstevel@tonic-gate 
1094*0Sstevel@tonic-gate 		transp = &dr_state_transition[t];
1095*0Sstevel@tonic-gate 		ASSERT(transp->x_cmd == cmd);
1096*0Sstevel@tonic-gate 
1097*0Sstevel@tonic-gate 		state_err = dr_check_transition(bp, &devset, transp, cmd);
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate 		if (state_err < 0) {
1100*0Sstevel@tonic-gate 			/*
1101*0Sstevel@tonic-gate 			 * Invalidate device.
1102*0Sstevel@tonic-gate 			 */
1103*0Sstevel@tonic-gate 			dr_op_err(CE_IGNORE, hp, ESBD_INVAL, NULL);
1104*0Sstevel@tonic-gate 			serr = -1;
1105*0Sstevel@tonic-gate 			PR_ALL("%s: invalid devset (0x%x)\n",
1106*0Sstevel@tonic-gate 				f, (uint_t)devset);
1107*0Sstevel@tonic-gate 		} else if (state_err != 0) {
1108*0Sstevel@tonic-gate 			/*
1109*0Sstevel@tonic-gate 			 * State transition is not a valid one.
1110*0Sstevel@tonic-gate 			 */
1111*0Sstevel@tonic-gate 			dr_op_err(CE_IGNORE, hp,
1112*0Sstevel@tonic-gate 				transp->x_op[state_err].x_err, NULL);
1113*0Sstevel@tonic-gate 
1114*0Sstevel@tonic-gate 			serr = transp->x_op[state_err].x_rv;
1115*0Sstevel@tonic-gate 
1116*0Sstevel@tonic-gate 			PR_ALL("%s: invalid state %s(%d) for cmd %s(%d)\n",
1117*0Sstevel@tonic-gate 				f, state_str[state_err], state_err,
1118*0Sstevel@tonic-gate 				SBD_CMD_STR(cmd), cmd);
1119*0Sstevel@tonic-gate 		} else {
1120*0Sstevel@tonic-gate 			shp->h_devset = devset;
1121*0Sstevel@tonic-gate 		}
1122*0Sstevel@tonic-gate 	}
1123*0Sstevel@tonic-gate 
1124*0Sstevel@tonic-gate 	if (serr) {
1125*0Sstevel@tonic-gate 		rv = -1;
1126*0Sstevel@tonic-gate 	}
1127*0Sstevel@tonic-gate 
1128*0Sstevel@tonic-gate 	return (rv);
1129*0Sstevel@tonic-gate }
1130*0Sstevel@tonic-gate 
1131*0Sstevel@tonic-gate static int
1132*0Sstevel@tonic-gate dr_post_op(dr_handle_t *hp)
1133*0Sstevel@tonic-gate {
1134*0Sstevel@tonic-gate 	int		rv = 0;
1135*0Sstevel@tonic-gate 	int		cmd;
1136*0Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
1137*0Sstevel@tonic-gate 	static fn_t	f = "dr_post_op";
1138*0Sstevel@tonic-gate 
1139*0Sstevel@tonic-gate 	cmd = hp->h_cmd;
1140*0Sstevel@tonic-gate 
1141*0Sstevel@tonic-gate 	PR_ALL("%s (cmd = %s)...\n", f, (uint_t)SBD_CMD_STR(cmd));
1142*0Sstevel@tonic-gate 
1143*0Sstevel@tonic-gate 	/* errors should have been caught by now */
1144*0Sstevel@tonic-gate 	ASSERT(hp->h_err == NULL);
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate 	hp->h_err = drmach_post_op(cmd, bp->b_id, &hp->h_opts);
1147*0Sstevel@tonic-gate 	if (hp->h_err != NULL) {
1148*0Sstevel@tonic-gate 		PR_ALL("drmach_post_op failed for cmd %s(%d)\n",
1149*0Sstevel@tonic-gate 			SBD_CMD_STR(cmd), cmd);
1150*0Sstevel@tonic-gate 		return (-1);
1151*0Sstevel@tonic-gate 	}
1152*0Sstevel@tonic-gate 
1153*0Sstevel@tonic-gate 	switch (cmd) {
1154*0Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:
1155*0Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:
1156*0Sstevel@tonic-gate 	case SBD_CMD_CONNECT:
1157*0Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:
1158*0Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
1159*0Sstevel@tonic-gate 	case SBD_CMD_STATUS:
1160*0Sstevel@tonic-gate 		break;
1161*0Sstevel@tonic-gate 
1162*0Sstevel@tonic-gate 	default:
1163*0Sstevel@tonic-gate 		break;
1164*0Sstevel@tonic-gate 	}
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate 	return (rv);
1167*0Sstevel@tonic-gate }
1168*0Sstevel@tonic-gate 
1169*0Sstevel@tonic-gate static int
1170*0Sstevel@tonic-gate dr_exec_op(dr_handle_t *hp)
1171*0Sstevel@tonic-gate {
1172*0Sstevel@tonic-gate 	int		rv = 0;
1173*0Sstevel@tonic-gate 	static fn_t	f = "dr_exec_op";
1174*0Sstevel@tonic-gate 
1175*0Sstevel@tonic-gate 	/* errors should have been caught by now */
1176*0Sstevel@tonic-gate 	ASSERT(hp->h_err == NULL);
1177*0Sstevel@tonic-gate 
1178*0Sstevel@tonic-gate 	switch (hp->h_cmd) {
1179*0Sstevel@tonic-gate 	case SBD_CMD_ASSIGN:
1180*0Sstevel@tonic-gate 		dr_assign_board(hp);
1181*0Sstevel@tonic-gate 		break;
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 	case SBD_CMD_UNASSIGN:
1184*0Sstevel@tonic-gate 		dr_unassign_board(hp);
1185*0Sstevel@tonic-gate 		break;
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate 	case SBD_CMD_POWEROFF:
1188*0Sstevel@tonic-gate 		dr_poweroff_board(hp);
1189*0Sstevel@tonic-gate 		break;
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate 	case SBD_CMD_POWERON:
1192*0Sstevel@tonic-gate 		dr_poweron_board(hp);
1193*0Sstevel@tonic-gate 		break;
1194*0Sstevel@tonic-gate 
1195*0Sstevel@tonic-gate 	case SBD_CMD_TEST:
1196*0Sstevel@tonic-gate 		dr_test_board(hp);
1197*0Sstevel@tonic-gate 		break;
1198*0Sstevel@tonic-gate 
1199*0Sstevel@tonic-gate 	case SBD_CMD_CONNECT:
1200*0Sstevel@tonic-gate 		dr_connect(hp);
1201*0Sstevel@tonic-gate 		break;
1202*0Sstevel@tonic-gate 
1203*0Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:
1204*0Sstevel@tonic-gate 		dr_dev_configure(hp);
1205*0Sstevel@tonic-gate 		break;
1206*0Sstevel@tonic-gate 
1207*0Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:
1208*0Sstevel@tonic-gate 		dr_dev_release(hp);
1209*0Sstevel@tonic-gate 		if (hp->h_err == NULL)
1210*0Sstevel@tonic-gate 			rv = dr_dev_unconfigure(hp);
1211*0Sstevel@tonic-gate 		else
1212*0Sstevel@tonic-gate 			dr_dev_cancel(hp);
1213*0Sstevel@tonic-gate 		break;
1214*0Sstevel@tonic-gate 
1215*0Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:
1216*0Sstevel@tonic-gate 		rv = dr_disconnect(hp);
1217*0Sstevel@tonic-gate 		break;
1218*0Sstevel@tonic-gate 
1219*0Sstevel@tonic-gate 	case SBD_CMD_STATUS:
1220*0Sstevel@tonic-gate 		rv = dr_dev_status(hp);
1221*0Sstevel@tonic-gate 		break;
1222*0Sstevel@tonic-gate 
1223*0Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
1224*0Sstevel@tonic-gate 		hp->h_sbdcmd.cmd_getncm.g_ncm = dr_get_ncm(hp);
1225*0Sstevel@tonic-gate 		rv = dr_copyout_iocmd(hp);
1226*0Sstevel@tonic-gate 		break;
1227*0Sstevel@tonic-gate 
1228*0Sstevel@tonic-gate 	case SBD_CMD_PASSTHRU:
1229*0Sstevel@tonic-gate 		rv = dr_pt_ioctl(hp);
1230*0Sstevel@tonic-gate 		break;
1231*0Sstevel@tonic-gate 
1232*0Sstevel@tonic-gate 	default:
1233*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
1234*0Sstevel@tonic-gate 			"%s: unknown command (%d)",
1235*0Sstevel@tonic-gate 			f, hp->h_cmd);
1236*0Sstevel@tonic-gate 		break;
1237*0Sstevel@tonic-gate 	}
1238*0Sstevel@tonic-gate 
1239*0Sstevel@tonic-gate 	if (hp->h_err != NULL) {
1240*0Sstevel@tonic-gate 		rv = -1;
1241*0Sstevel@tonic-gate 	}
1242*0Sstevel@tonic-gate 
1243*0Sstevel@tonic-gate 	return (rv);
1244*0Sstevel@tonic-gate }
1245*0Sstevel@tonic-gate 
1246*0Sstevel@tonic-gate static void
1247*0Sstevel@tonic-gate dr_assign_board(dr_handle_t *hp)
1248*0Sstevel@tonic-gate {
1249*0Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
1250*0Sstevel@tonic-gate 
1251*0Sstevel@tonic-gate 	hp->h_err = drmach_board_assign(bp->b_num, &bp->b_id);
1252*0Sstevel@tonic-gate 	if (hp->h_err == NULL) {
1253*0Sstevel@tonic-gate 		bp->b_assigned = 1;
1254*0Sstevel@tonic-gate 	}
1255*0Sstevel@tonic-gate }
1256*0Sstevel@tonic-gate 
1257*0Sstevel@tonic-gate static void
1258*0Sstevel@tonic-gate dr_unassign_board(dr_handle_t *hp)
1259*0Sstevel@tonic-gate {
1260*0Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
1261*0Sstevel@tonic-gate 
1262*0Sstevel@tonic-gate 	/*
1263*0Sstevel@tonic-gate 	 * Block out status during unassign.
1264*0Sstevel@tonic-gate 	 * Not doing cv_wait_sig here as starfire SSP software
1265*0Sstevel@tonic-gate 	 * ignores unassign failure and removes board from
1266*0Sstevel@tonic-gate 	 * domain mask causing system panic.
1267*0Sstevel@tonic-gate 	 * TODO: Change cv_wait to cv_wait_sig when SSP software
1268*0Sstevel@tonic-gate 	 * handles unassign failure.
1269*0Sstevel@tonic-gate 	 */
1270*0Sstevel@tonic-gate 	dr_lock_status(bp);
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate 	hp->h_err = drmach_board_unassign(bp->b_id);
1273*0Sstevel@tonic-gate 	if (hp->h_err == NULL) {
1274*0Sstevel@tonic-gate 		/*
1275*0Sstevel@tonic-gate 		 * clear drmachid_t handle; not valid after board unassign
1276*0Sstevel@tonic-gate 		 */
1277*0Sstevel@tonic-gate 		bp->b_id = 0;
1278*0Sstevel@tonic-gate 		bp->b_assigned = 0;
1279*0Sstevel@tonic-gate 	}
1280*0Sstevel@tonic-gate 
1281*0Sstevel@tonic-gate 	dr_unlock_status(bp);
1282*0Sstevel@tonic-gate }
1283*0Sstevel@tonic-gate 
1284*0Sstevel@tonic-gate static void
1285*0Sstevel@tonic-gate dr_poweron_board(dr_handle_t *hp)
1286*0Sstevel@tonic-gate {
1287*0Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
1288*0Sstevel@tonic-gate 
1289*0Sstevel@tonic-gate 	hp->h_err = drmach_board_poweron(bp->b_id);
1290*0Sstevel@tonic-gate }
1291*0Sstevel@tonic-gate 
1292*0Sstevel@tonic-gate static void
1293*0Sstevel@tonic-gate dr_poweroff_board(dr_handle_t *hp)
1294*0Sstevel@tonic-gate {
1295*0Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
1296*0Sstevel@tonic-gate 
1297*0Sstevel@tonic-gate 	hp->h_err = drmach_board_poweroff(bp->b_id);
1298*0Sstevel@tonic-gate }
1299*0Sstevel@tonic-gate 
1300*0Sstevel@tonic-gate static void
1301*0Sstevel@tonic-gate dr_test_board(dr_handle_t *hp)
1302*0Sstevel@tonic-gate {
1303*0Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
1304*0Sstevel@tonic-gate 	hp->h_err = drmach_board_test(bp->b_id, &hp->h_opts,
1305*0Sstevel@tonic-gate 	    dr_cmd_flags(hp) & SBD_FLAG_FORCE);
1306*0Sstevel@tonic-gate }
1307*0Sstevel@tonic-gate 
1308*0Sstevel@tonic-gate /*
1309*0Sstevel@tonic-gate  * Create and populate the component nodes for a board.  Assumes that the
1310*0Sstevel@tonic-gate  * devlists for the board have been initialized.
1311*0Sstevel@tonic-gate  */
1312*0Sstevel@tonic-gate static void
1313*0Sstevel@tonic-gate dr_make_comp_nodes(dr_board_t *bp) {
1314*0Sstevel@tonic-gate 
1315*0Sstevel@tonic-gate 	int	i;
1316*0Sstevel@tonic-gate 
1317*0Sstevel@tonic-gate 	/*
1318*0Sstevel@tonic-gate 	 * Make nodes for the individual components on the board.
1319*0Sstevel@tonic-gate 	 * First we need to initialize memory unit data structures of board
1320*0Sstevel@tonic-gate 	 * structure.
1321*0Sstevel@tonic-gate 	 */
1322*0Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
1323*0Sstevel@tonic-gate 		dr_mem_unit_t *mp;
1324*0Sstevel@tonic-gate 
1325*0Sstevel@tonic-gate 		mp = dr_get_mem_unit(bp, i);
1326*0Sstevel@tonic-gate 		dr_init_mem_unit(mp);
1327*0Sstevel@tonic-gate 	}
1328*0Sstevel@tonic-gate 
1329*0Sstevel@tonic-gate 	/*
1330*0Sstevel@tonic-gate 	 * Initialize cpu unit data structures.
1331*0Sstevel@tonic-gate 	 */
1332*0Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
1333*0Sstevel@tonic-gate 		dr_cpu_unit_t *cp;
1334*0Sstevel@tonic-gate 
1335*0Sstevel@tonic-gate 		cp = dr_get_cpu_unit(bp, i);
1336*0Sstevel@tonic-gate 		dr_init_cpu_unit(cp);
1337*0Sstevel@tonic-gate 	}
1338*0Sstevel@tonic-gate 
1339*0Sstevel@tonic-gate 	/*
1340*0Sstevel@tonic-gate 	 * Initialize io unit data structures.
1341*0Sstevel@tonic-gate 	 */
1342*0Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
1343*0Sstevel@tonic-gate 		dr_io_unit_t *ip;
1344*0Sstevel@tonic-gate 
1345*0Sstevel@tonic-gate 		ip = dr_get_io_unit(bp, i);
1346*0Sstevel@tonic-gate 		dr_init_io_unit(ip);
1347*0Sstevel@tonic-gate 	}
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 	dr_board_transition(bp, DR_STATE_CONNECTED);
1350*0Sstevel@tonic-gate 
1351*0Sstevel@tonic-gate 	bp->b_rstate = SBD_STAT_CONNECTED;
1352*0Sstevel@tonic-gate 	bp->b_ostate = SBD_STAT_UNCONFIGURED;
1353*0Sstevel@tonic-gate 	bp->b_cond = SBD_COND_OK;
1354*0Sstevel@tonic-gate 	(void) drv_getparm(TIME, (void *)&bp->b_time);
1355*0Sstevel@tonic-gate 
1356*0Sstevel@tonic-gate }
1357*0Sstevel@tonic-gate 
1358*0Sstevel@tonic-gate /*
1359*0Sstevel@tonic-gate  * Only do work if called to operate on an entire board
1360*0Sstevel@tonic-gate  * which doesn't already have components present.
1361*0Sstevel@tonic-gate  */
1362*0Sstevel@tonic-gate static void
1363*0Sstevel@tonic-gate dr_connect(dr_handle_t *hp)
1364*0Sstevel@tonic-gate {
1365*0Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
1366*0Sstevel@tonic-gate 	static fn_t	f = "dr_connect";
1367*0Sstevel@tonic-gate 
1368*0Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
1369*0Sstevel@tonic-gate 
1370*0Sstevel@tonic-gate 	if (DR_DEVS_PRESENT(bp)) {
1371*0Sstevel@tonic-gate 		/*
1372*0Sstevel@tonic-gate 		 * Board already has devices present.
1373*0Sstevel@tonic-gate 		 */
1374*0Sstevel@tonic-gate 		PR_ALL("%s: devices already present (0x%x)\n",
1375*0Sstevel@tonic-gate 			f, DR_DEVS_PRESENT(bp));
1376*0Sstevel@tonic-gate 		return;
1377*0Sstevel@tonic-gate 	}
1378*0Sstevel@tonic-gate 
1379*0Sstevel@tonic-gate 	hp->h_err = drmach_board_connect(bp->b_id, &hp->h_opts);
1380*0Sstevel@tonic-gate 	if (hp->h_err)
1381*0Sstevel@tonic-gate 		return;
1382*0Sstevel@tonic-gate 
1383*0Sstevel@tonic-gate 	hp->h_err = dr_init_devlists(bp);
1384*0Sstevel@tonic-gate 	if (hp->h_err)
1385*0Sstevel@tonic-gate 		return;
1386*0Sstevel@tonic-gate 	else if (bp->b_ndev == 0) {
1387*0Sstevel@tonic-gate 		dr_op_err(CE_WARN, hp, ESBD_EMPTY_BD, bp->b_path);
1388*0Sstevel@tonic-gate 		return;
1389*0Sstevel@tonic-gate 	} else {
1390*0Sstevel@tonic-gate 		dr_make_comp_nodes(bp);
1391*0Sstevel@tonic-gate 		return;
1392*0Sstevel@tonic-gate 	}
1393*0Sstevel@tonic-gate 	/*NOTREACHED*/
1394*0Sstevel@tonic-gate }
1395*0Sstevel@tonic-gate 
1396*0Sstevel@tonic-gate static int
1397*0Sstevel@tonic-gate dr_disconnect(dr_handle_t *hp)
1398*0Sstevel@tonic-gate {
1399*0Sstevel@tonic-gate 	int		i;
1400*0Sstevel@tonic-gate 	dr_devset_t	devset;
1401*0Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
1402*0Sstevel@tonic-gate 	static fn_t	f = "dr_disconnect";
1403*0Sstevel@tonic-gate 
1404*0Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
1405*0Sstevel@tonic-gate 
1406*0Sstevel@tonic-gate 	/*
1407*0Sstevel@tonic-gate 	 * Only devices which are present, but
1408*0Sstevel@tonic-gate 	 * unattached can be disconnected.
1409*0Sstevel@tonic-gate 	 */
1410*0Sstevel@tonic-gate 	devset = hp->h_devset & DR_DEVS_PRESENT(bp) &
1411*0Sstevel@tonic-gate 			DR_DEVS_UNATTACHED(bp);
1412*0Sstevel@tonic-gate 
1413*0Sstevel@tonic-gate 	if ((devset == 0) && DR_DEVS_PRESENT(bp)) {
1414*0Sstevel@tonic-gate 		dr_op_err(CE_IGNORE, hp, ESBD_EMPTY_BD, bp->b_path);
1415*0Sstevel@tonic-gate 		return (0);
1416*0Sstevel@tonic-gate 	}
1417*0Sstevel@tonic-gate 
1418*0Sstevel@tonic-gate 	/*
1419*0Sstevel@tonic-gate 	 * Block out status during disconnect.
1420*0Sstevel@tonic-gate 	 */
1421*0Sstevel@tonic-gate 	mutex_enter(&bp->b_slock);
1422*0Sstevel@tonic-gate 	while (bp->b_sflags & DR_BSLOCK) {
1423*0Sstevel@tonic-gate 		if (cv_wait_sig(&bp->b_scv, &bp->b_slock) == 0) {
1424*0Sstevel@tonic-gate 			mutex_exit(&bp->b_slock);
1425*0Sstevel@tonic-gate 			return (EINTR);
1426*0Sstevel@tonic-gate 		}
1427*0Sstevel@tonic-gate 	}
1428*0Sstevel@tonic-gate 	bp->b_sflags |= DR_BSLOCK;
1429*0Sstevel@tonic-gate 	mutex_exit(&bp->b_slock);
1430*0Sstevel@tonic-gate 
1431*0Sstevel@tonic-gate 	hp->h_err = drmach_board_disconnect(bp->b_id, &hp->h_opts);
1432*0Sstevel@tonic-gate 
1433*0Sstevel@tonic-gate 	DR_DEVS_DISCONNECT(bp, devset);
1434*0Sstevel@tonic-gate 
1435*0Sstevel@tonic-gate 	ASSERT((DR_DEVS_ATTACHED(bp) & devset) == 0);
1436*0Sstevel@tonic-gate 
1437*0Sstevel@tonic-gate 	/*
1438*0Sstevel@tonic-gate 	 * Update per-device state transitions.
1439*0Sstevel@tonic-gate 	 */
1440*0Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
1441*0Sstevel@tonic-gate 		dr_cpu_unit_t *cp;
1442*0Sstevel@tonic-gate 
1443*0Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_CPU, i))
1444*0Sstevel@tonic-gate 			continue;
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate 		cp = dr_get_cpu_unit(bp, i);
1447*0Sstevel@tonic-gate 		if (dr_disconnect_cpu(cp) == 0)
1448*0Sstevel@tonic-gate 			dr_device_transition(&cp->sbc_cm, DR_STATE_EMPTY);
1449*0Sstevel@tonic-gate 		else if (cp->sbc_cm.sbdev_error != NULL)
1450*0Sstevel@tonic-gate 			DRERR_SET_C(&hp->h_err, &cp->sbc_cm.sbdev_error);
1451*0Sstevel@tonic-gate 
1452*0Sstevel@tonic-gate 		ASSERT(cp->sbc_cm.sbdev_error == NULL);
1453*0Sstevel@tonic-gate 	}
1454*0Sstevel@tonic-gate 
1455*0Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
1456*0Sstevel@tonic-gate 		dr_mem_unit_t *mp;
1457*0Sstevel@tonic-gate 
1458*0Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_MEM, i))
1459*0Sstevel@tonic-gate 			continue;
1460*0Sstevel@tonic-gate 
1461*0Sstevel@tonic-gate 		mp = dr_get_mem_unit(bp, i);
1462*0Sstevel@tonic-gate 		if (dr_disconnect_mem(mp) == 0)
1463*0Sstevel@tonic-gate 			dr_device_transition(&mp->sbm_cm, DR_STATE_EMPTY);
1464*0Sstevel@tonic-gate 		else if (mp->sbm_cm.sbdev_error != NULL)
1465*0Sstevel@tonic-gate 			DRERR_SET_C(&hp->h_err, &mp->sbm_cm.sbdev_error);
1466*0Sstevel@tonic-gate 
1467*0Sstevel@tonic-gate 		ASSERT(mp->sbm_cm.sbdev_error == NULL);
1468*0Sstevel@tonic-gate 	}
1469*0Sstevel@tonic-gate 
1470*0Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
1471*0Sstevel@tonic-gate 		dr_io_unit_t *ip;
1472*0Sstevel@tonic-gate 
1473*0Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_IO, i))
1474*0Sstevel@tonic-gate 			continue;
1475*0Sstevel@tonic-gate 
1476*0Sstevel@tonic-gate 		ip = dr_get_io_unit(bp, i);
1477*0Sstevel@tonic-gate 		if (dr_disconnect_io(ip) == 0)
1478*0Sstevel@tonic-gate 			dr_device_transition(&ip->sbi_cm, DR_STATE_EMPTY);
1479*0Sstevel@tonic-gate 		else if (ip->sbi_cm.sbdev_error != NULL)
1480*0Sstevel@tonic-gate 			DRERR_SET_C(&hp->h_err, &ip->sbi_cm.sbdev_error);
1481*0Sstevel@tonic-gate 
1482*0Sstevel@tonic-gate 		ASSERT(ip->sbi_cm.sbdev_error == NULL);
1483*0Sstevel@tonic-gate 	}
1484*0Sstevel@tonic-gate 	if (hp->h_err) {
1485*0Sstevel@tonic-gate 		/*
1486*0Sstevel@tonic-gate 		 * For certain errors, drmach_board_disconnect will mark
1487*0Sstevel@tonic-gate 		 * the board as unusable; in these cases the devtree must
1488*0Sstevel@tonic-gate 		 * be purged so that status calls will succeed.
1489*0Sstevel@tonic-gate 		 * XXX
1490*0Sstevel@tonic-gate 		 * This implementation checks for discrete error codes -
1491*0Sstevel@tonic-gate 		 * someday, the i/f to drmach_board_disconnect should be
1492*0Sstevel@tonic-gate 		 * changed to avoid the e_code testing.
1493*0Sstevel@tonic-gate 		 */
1494*0Sstevel@tonic-gate 		if ((hp->h_err->e_code == ESTC_MBXRPLY) ||
1495*0Sstevel@tonic-gate 			(hp->h_err->e_code == ESTC_MBXRQST) ||
1496*0Sstevel@tonic-gate 			(hp->h_err->e_code == ESTC_SMS_ERR_UNRECOVERABLE) ||
1497*0Sstevel@tonic-gate 			(hp->h_err->e_code == ESTC_SMS_ERR_RECOVERABLE) ||
1498*0Sstevel@tonic-gate 			(hp->h_err->e_code == ESTC_DEPROBE)) {
1499*0Sstevel@tonic-gate 			bp->b_ostate = SBD_STAT_UNCONFIGURED;
1500*0Sstevel@tonic-gate 			bp->b_busy = 0;
1501*0Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&bp->b_time);
1502*0Sstevel@tonic-gate 
1503*0Sstevel@tonic-gate 			if (drmach_board_deprobe(bp->b_id))
1504*0Sstevel@tonic-gate 				goto disconnect_done;
1505*0Sstevel@tonic-gate 			else
1506*0Sstevel@tonic-gate 				bp->b_ndev = 0;
1507*0Sstevel@tonic-gate 		}
1508*0Sstevel@tonic-gate 
1509*0Sstevel@tonic-gate 		/*
1510*0Sstevel@tonic-gate 		 * If the disconnect failed in a recoverable way,
1511*0Sstevel@tonic-gate 		 * more work is required.
1512*0Sstevel@tonic-gate 		 * XXX
1513*0Sstevel@tonic-gate 		 * This implementation checks for discrete error codes -
1514*0Sstevel@tonic-gate 		 * someday, the i/f to drmach_board_disconnect should be
1515*0Sstevel@tonic-gate 		 * changed to avoid the e_code testing.
1516*0Sstevel@tonic-gate 		 */
1517*0Sstevel@tonic-gate 		if ((hp->h_err->e_code == ESTC_MBXRQST) ||
1518*0Sstevel@tonic-gate 		    (hp->h_err->e_code == ESTC_SMS_ERR_RECOVERABLE) ||
1519*0Sstevel@tonic-gate 		    (hp->h_err->e_code == ESTC_DEPROBE)) {
1520*0Sstevel@tonic-gate 			/*
1521*0Sstevel@tonic-gate 			 * With this failure, the board has been deprobed
1522*0Sstevel@tonic-gate 			 * by IKP, and reprobed.  We've already gotten rid
1523*0Sstevel@tonic-gate 			 * of the old devtree, now we need to reconstruct it
1524*0Sstevel@tonic-gate 			 * based on the new IKP probe
1525*0Sstevel@tonic-gate 			 */
1526*0Sstevel@tonic-gate 			if (dr_init_devlists(bp) || (bp->b_ndev == 0))
1527*0Sstevel@tonic-gate 				goto disconnect_done;
1528*0Sstevel@tonic-gate 
1529*0Sstevel@tonic-gate 			dr_make_comp_nodes(bp);
1530*0Sstevel@tonic-gate 		}
1531*0Sstevel@tonic-gate 	}
1532*0Sstevel@tonic-gate 	/*
1533*0Sstevel@tonic-gate 	 * Once all the components on a board have been disconnect
1534*0Sstevel@tonic-gate 	 * the board's state can transition to disconnected and
1535*0Sstevel@tonic-gate 	 * we can allow the deprobe to take place.
1536*0Sstevel@tonic-gate 	 */
1537*0Sstevel@tonic-gate 	if (hp->h_err == NULL && DR_DEVS_PRESENT(bp) == 0) {
1538*0Sstevel@tonic-gate 		dr_board_transition(bp, DR_STATE_OCCUPIED);
1539*0Sstevel@tonic-gate 		bp->b_rstate = SBD_STAT_DISCONNECTED;
1540*0Sstevel@tonic-gate 		bp->b_ostate = SBD_STAT_UNCONFIGURED;
1541*0Sstevel@tonic-gate 		bp->b_busy = 0;
1542*0Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&bp->b_time);
1543*0Sstevel@tonic-gate 
1544*0Sstevel@tonic-gate 		hp->h_err = drmach_board_deprobe(bp->b_id);
1545*0Sstevel@tonic-gate 
1546*0Sstevel@tonic-gate 		if (hp->h_err == NULL) {
1547*0Sstevel@tonic-gate 			bp->b_ndev = 0;
1548*0Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_EMPTY);
1549*0Sstevel@tonic-gate 			bp->b_rstate = SBD_STAT_EMPTY;
1550*0Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&bp->b_time);
1551*0Sstevel@tonic-gate 		}
1552*0Sstevel@tonic-gate 	}
1553*0Sstevel@tonic-gate 
1554*0Sstevel@tonic-gate disconnect_done:
1555*0Sstevel@tonic-gate 	dr_unlock_status(bp);
1556*0Sstevel@tonic-gate 
1557*0Sstevel@tonic-gate 	return (0);
1558*0Sstevel@tonic-gate }
1559*0Sstevel@tonic-gate 
1560*0Sstevel@tonic-gate /*
1561*0Sstevel@tonic-gate  * Check if a particular device is a valid target of the current
1562*0Sstevel@tonic-gate  * operation. Return 1 if it is a valid target, and 0 otherwise.
1563*0Sstevel@tonic-gate  */
1564*0Sstevel@tonic-gate static int
1565*0Sstevel@tonic-gate dr_dev_is_target(dr_dev_unit_t *dp, int present_only, uint_t uset)
1566*0Sstevel@tonic-gate {
1567*0Sstevel@tonic-gate 	dr_common_unit_t *cp;
1568*0Sstevel@tonic-gate 	int		 is_present;
1569*0Sstevel@tonic-gate 	int		 is_attached;
1570*0Sstevel@tonic-gate 
1571*0Sstevel@tonic-gate 	cp = &dp->du_common;
1572*0Sstevel@tonic-gate 
1573*0Sstevel@tonic-gate 	/* check if the user requested this device */
1574*0Sstevel@tonic-gate 	if ((uset & (1 << cp->sbdev_unum)) == 0) {
1575*0Sstevel@tonic-gate 		return (0);
1576*0Sstevel@tonic-gate 	}
1577*0Sstevel@tonic-gate 
1578*0Sstevel@tonic-gate 	is_present = DR_DEV_IS_PRESENT(cp) ? 1 : 0;
1579*0Sstevel@tonic-gate 	is_attached = DR_DEV_IS_ATTACHED(cp) ? 1 : 0;
1580*0Sstevel@tonic-gate 
1581*0Sstevel@tonic-gate 	/*
1582*0Sstevel@tonic-gate 	 * If the present_only flag is set, a valid target
1583*0Sstevel@tonic-gate 	 * must be present but not attached. Otherwise, it
1584*0Sstevel@tonic-gate 	 * must be both present and attached.
1585*0Sstevel@tonic-gate 	 */
1586*0Sstevel@tonic-gate 	if (is_present && (present_only ^ is_attached)) {
1587*0Sstevel@tonic-gate 		/* sanity check */
1588*0Sstevel@tonic-gate 		ASSERT(cp->sbdev_id != (drmachid_t)0);
1589*0Sstevel@tonic-gate 
1590*0Sstevel@tonic-gate 		return (1);
1591*0Sstevel@tonic-gate 	}
1592*0Sstevel@tonic-gate 
1593*0Sstevel@tonic-gate 	return (0);
1594*0Sstevel@tonic-gate }
1595*0Sstevel@tonic-gate 
1596*0Sstevel@tonic-gate static void
1597*0Sstevel@tonic-gate dr_dev_make_list(dr_handle_t *hp, sbd_comp_type_t type, int present_only,
1598*0Sstevel@tonic-gate 	dr_common_unit_t ***devlist, int *devnum)
1599*0Sstevel@tonic-gate {
1600*0Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
1601*0Sstevel@tonic-gate 	int		 unum;
1602*0Sstevel@tonic-gate 	int		 nunits;
1603*0Sstevel@tonic-gate 	uint_t		 uset;
1604*0Sstevel@tonic-gate 	int		 len;
1605*0Sstevel@tonic-gate 	dr_common_unit_t **list, **wp;
1606*0Sstevel@tonic-gate 
1607*0Sstevel@tonic-gate 	switch (type) {
1608*0Sstevel@tonic-gate 	case SBD_COMP_CPU:
1609*0Sstevel@tonic-gate 		nunits = MAX_CPU_UNITS_PER_BOARD;
1610*0Sstevel@tonic-gate 		break;
1611*0Sstevel@tonic-gate 	case SBD_COMP_MEM:
1612*0Sstevel@tonic-gate 		nunits = MAX_MEM_UNITS_PER_BOARD;
1613*0Sstevel@tonic-gate 		break;
1614*0Sstevel@tonic-gate 	case SBD_COMP_IO:
1615*0Sstevel@tonic-gate 		nunits = MAX_IO_UNITS_PER_BOARD;
1616*0Sstevel@tonic-gate 		break;
1617*0Sstevel@tonic-gate 	default:
1618*0Sstevel@tonic-gate 		/* catch this in debug kernels */
1619*0Sstevel@tonic-gate 		ASSERT(0);
1620*0Sstevel@tonic-gate 		break;
1621*0Sstevel@tonic-gate 	}
1622*0Sstevel@tonic-gate 
1623*0Sstevel@tonic-gate 	/* allocate list storage. */
1624*0Sstevel@tonic-gate 	len = sizeof (dr_common_unit_t *) * (nunits + 1);
1625*0Sstevel@tonic-gate 	list = kmem_zalloc(len, KM_SLEEP);
1626*0Sstevel@tonic-gate 
1627*0Sstevel@tonic-gate 	/* record length of storage in first element */
1628*0Sstevel@tonic-gate 	*list++ = (dr_common_unit_t *)len;
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate 	/* get bit array signifying which units are to be involved */
1631*0Sstevel@tonic-gate 	uset = DEVSET_GET_UNITSET(hp->h_devset, type);
1632*0Sstevel@tonic-gate 
1633*0Sstevel@tonic-gate 	/*
1634*0Sstevel@tonic-gate 	 * Adjust the loop count for CPU devices since all cores
1635*0Sstevel@tonic-gate 	 * in a CMP will be examined in a single iteration.
1636*0Sstevel@tonic-gate 	 */
1637*0Sstevel@tonic-gate 	if (type == SBD_COMP_CPU) {
1638*0Sstevel@tonic-gate 		nunits = MAX_CMP_UNITS_PER_BOARD;
1639*0Sstevel@tonic-gate 	}
1640*0Sstevel@tonic-gate 
1641*0Sstevel@tonic-gate 	/* populate list */
1642*0Sstevel@tonic-gate 	for (wp = list, unum = 0; unum < nunits; unum++) {
1643*0Sstevel@tonic-gate 
1644*0Sstevel@tonic-gate 		dr_dev_unit_t	*dp;
1645*0Sstevel@tonic-gate 		int		core;
1646*0Sstevel@tonic-gate 		int		cunum;
1647*0Sstevel@tonic-gate 
1648*0Sstevel@tonic-gate 		dp = DR_GET_BOARD_DEVUNIT(bp, type, unum);
1649*0Sstevel@tonic-gate 		if (dr_dev_is_target(dp, present_only, uset)) {
1650*0Sstevel@tonic-gate 			*wp++ = &dp->du_common;
1651*0Sstevel@tonic-gate 		}
1652*0Sstevel@tonic-gate 
1653*0Sstevel@tonic-gate 		/* further processing is only required for CPUs */
1654*0Sstevel@tonic-gate 		if (type != SBD_COMP_CPU) {
1655*0Sstevel@tonic-gate 			continue;
1656*0Sstevel@tonic-gate 		}
1657*0Sstevel@tonic-gate 
1658*0Sstevel@tonic-gate 		/*
1659*0Sstevel@tonic-gate 		 * Add any additional cores from the current CPU
1660*0Sstevel@tonic-gate 		 * device. This is to ensure that all the cores
1661*0Sstevel@tonic-gate 		 * are grouped together in the device list, and
1662*0Sstevel@tonic-gate 		 * consequently sequenced together during the actual
1663*0Sstevel@tonic-gate 		 * operation.
1664*0Sstevel@tonic-gate 		 */
1665*0Sstevel@tonic-gate 		for (core = 1; core < MAX_CORES_PER_CMP; core++) {
1666*0Sstevel@tonic-gate 
1667*0Sstevel@tonic-gate 			cunum = DR_CMP_CORE_UNUM(unum, core);
1668*0Sstevel@tonic-gate 			dp = DR_GET_BOARD_DEVUNIT(bp, type, cunum);
1669*0Sstevel@tonic-gate 
1670*0Sstevel@tonic-gate 			if (dr_dev_is_target(dp, present_only, uset)) {
1671*0Sstevel@tonic-gate 				*wp++ = &dp->du_common;
1672*0Sstevel@tonic-gate 			}
1673*0Sstevel@tonic-gate 		}
1674*0Sstevel@tonic-gate 	}
1675*0Sstevel@tonic-gate 
1676*0Sstevel@tonic-gate 	/* calculate number of units in list, return result and list pointer */
1677*0Sstevel@tonic-gate 	*devnum = wp - list;
1678*0Sstevel@tonic-gate 	*devlist = list;
1679*0Sstevel@tonic-gate }
1680*0Sstevel@tonic-gate 
1681*0Sstevel@tonic-gate static void
1682*0Sstevel@tonic-gate dr_dev_clean_up(dr_handle_t *hp, dr_common_unit_t **list, int devnum)
1683*0Sstevel@tonic-gate {
1684*0Sstevel@tonic-gate 	int len;
1685*0Sstevel@tonic-gate 	int n = 0;
1686*0Sstevel@tonic-gate 	dr_common_unit_t *cp, **rp = list;
1687*0Sstevel@tonic-gate 
1688*0Sstevel@tonic-gate 	/*
1689*0Sstevel@tonic-gate 	 * move first encountered unit error to handle if handle
1690*0Sstevel@tonic-gate 	 * does not yet have a recorded error.
1691*0Sstevel@tonic-gate 	 */
1692*0Sstevel@tonic-gate 	if (hp->h_err == NULL) {
1693*0Sstevel@tonic-gate 		while (n++ < devnum) {
1694*0Sstevel@tonic-gate 			cp = *rp++;
1695*0Sstevel@tonic-gate 			if (cp->sbdev_error != NULL) {
1696*0Sstevel@tonic-gate 				hp->h_err = cp->sbdev_error;
1697*0Sstevel@tonic-gate 				cp->sbdev_error = NULL;
1698*0Sstevel@tonic-gate 				break;
1699*0Sstevel@tonic-gate 			}
1700*0Sstevel@tonic-gate 		}
1701*0Sstevel@tonic-gate 	}
1702*0Sstevel@tonic-gate 
1703*0Sstevel@tonic-gate 	/* free remaining unit errors */
1704*0Sstevel@tonic-gate 	while (n++ < devnum) {
1705*0Sstevel@tonic-gate 		cp = *rp++;
1706*0Sstevel@tonic-gate 		if (cp->sbdev_error != NULL) {
1707*0Sstevel@tonic-gate 			sbd_err_clear(&cp->sbdev_error);
1708*0Sstevel@tonic-gate 			cp->sbdev_error = NULL;
1709*0Sstevel@tonic-gate 		}
1710*0Sstevel@tonic-gate 	}
1711*0Sstevel@tonic-gate 
1712*0Sstevel@tonic-gate 	/* free list */
1713*0Sstevel@tonic-gate 	list -= 1;
1714*0Sstevel@tonic-gate 	len = (int)list[0];
1715*0Sstevel@tonic-gate 	kmem_free(list, len);
1716*0Sstevel@tonic-gate }
1717*0Sstevel@tonic-gate 
1718*0Sstevel@tonic-gate static int
1719*0Sstevel@tonic-gate dr_dev_walk(dr_handle_t *hp, sbd_comp_type_t type, int present_only,
1720*0Sstevel@tonic-gate 		int (*pre_op)(dr_handle_t *, dr_common_unit_t **, int),
1721*0Sstevel@tonic-gate 		void (*op)(dr_handle_t *, dr_common_unit_t *),
1722*0Sstevel@tonic-gate 		int (*post_op)(dr_handle_t *, dr_common_unit_t **, int),
1723*0Sstevel@tonic-gate 		void (*board_op)(dr_handle_t *, dr_common_unit_t **, int))
1724*0Sstevel@tonic-gate {
1725*0Sstevel@tonic-gate 	int			  devnum, rv;
1726*0Sstevel@tonic-gate 	dr_common_unit_t	**devlist;
1727*0Sstevel@tonic-gate 
1728*0Sstevel@tonic-gate 	dr_dev_make_list(hp, type, present_only, &devlist, &devnum);
1729*0Sstevel@tonic-gate 
1730*0Sstevel@tonic-gate 	rv = 0;
1731*0Sstevel@tonic-gate 	if (devnum > 0) {
1732*0Sstevel@tonic-gate 		rv = (*pre_op)(hp, devlist, devnum);
1733*0Sstevel@tonic-gate 		if (rv == 0) {
1734*0Sstevel@tonic-gate 			int n;
1735*0Sstevel@tonic-gate 
1736*0Sstevel@tonic-gate 			for (n = 0; n < devnum; n++)
1737*0Sstevel@tonic-gate 				(*op)(hp, devlist[n]);
1738*0Sstevel@tonic-gate 
1739*0Sstevel@tonic-gate 			rv = (*post_op)(hp, devlist, devnum);
1740*0Sstevel@tonic-gate 
1741*0Sstevel@tonic-gate 			(*board_op)(hp, devlist, devnum);
1742*0Sstevel@tonic-gate 		}
1743*0Sstevel@tonic-gate 	}
1744*0Sstevel@tonic-gate 
1745*0Sstevel@tonic-gate 	dr_dev_clean_up(hp, devlist, devnum);
1746*0Sstevel@tonic-gate 	return (rv);
1747*0Sstevel@tonic-gate }
1748*0Sstevel@tonic-gate 
1749*0Sstevel@tonic-gate /*ARGSUSED*/
1750*0Sstevel@tonic-gate static int
1751*0Sstevel@tonic-gate dr_dev_noop(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
1752*0Sstevel@tonic-gate {
1753*0Sstevel@tonic-gate 	return (0);
1754*0Sstevel@tonic-gate }
1755*0Sstevel@tonic-gate 
1756*0Sstevel@tonic-gate static void
1757*0Sstevel@tonic-gate dr_attach_update_state(dr_handle_t *hp,
1758*0Sstevel@tonic-gate 	dr_common_unit_t **devlist, int devnum)
1759*0Sstevel@tonic-gate {
1760*0Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
1761*0Sstevel@tonic-gate 	int		i;
1762*0Sstevel@tonic-gate 	dr_devset_t	devs_unattached, devs_present;
1763*0Sstevel@tonic-gate 	static fn_t	f = "dr_post_attach_devlist";
1764*0Sstevel@tonic-gate 
1765*0Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
1766*0Sstevel@tonic-gate 		dr_common_unit_t *cp = devlist[i];
1767*0Sstevel@tonic-gate 
1768*0Sstevel@tonic-gate 		if (dr_check_unit_attached(cp) == -1) {
1769*0Sstevel@tonic-gate 			PR_ALL("%s: ERROR %s not attached\n",
1770*0Sstevel@tonic-gate 				f, cp->sbdev_path);
1771*0Sstevel@tonic-gate 			continue;
1772*0Sstevel@tonic-gate 		}
1773*0Sstevel@tonic-gate 
1774*0Sstevel@tonic-gate 		DR_DEV_SET_ATTACHED(cp);
1775*0Sstevel@tonic-gate 
1776*0Sstevel@tonic-gate 		dr_device_transition(cp, DR_STATE_CONFIGURED);
1777*0Sstevel@tonic-gate 		cp->sbdev_cond = SBD_COND_OK;
1778*0Sstevel@tonic-gate 	}
1779*0Sstevel@tonic-gate 
1780*0Sstevel@tonic-gate 	devs_present = DR_DEVS_PRESENT(bp);
1781*0Sstevel@tonic-gate 	devs_unattached = DR_DEVS_UNATTACHED(bp);
1782*0Sstevel@tonic-gate 
1783*0Sstevel@tonic-gate 	switch (bp->b_state) {
1784*0Sstevel@tonic-gate 	case DR_STATE_CONNECTED:
1785*0Sstevel@tonic-gate 	case DR_STATE_UNCONFIGURED:
1786*0Sstevel@tonic-gate 		ASSERT(devs_present);
1787*0Sstevel@tonic-gate 
1788*0Sstevel@tonic-gate 		if (devs_unattached == 0) {
1789*0Sstevel@tonic-gate 			/*
1790*0Sstevel@tonic-gate 			 * All devices finally attached.
1791*0Sstevel@tonic-gate 			 */
1792*0Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_CONFIGURED);
1793*0Sstevel@tonic-gate 			hp->h_bd->b_ostate = SBD_STAT_CONFIGURED;
1794*0Sstevel@tonic-gate 			hp->h_bd->b_rstate = SBD_STAT_CONNECTED;
1795*0Sstevel@tonic-gate 			hp->h_bd->b_cond = SBD_COND_OK;
1796*0Sstevel@tonic-gate 			hp->h_bd->b_busy = 0;
1797*0Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
1798*0Sstevel@tonic-gate 		} else if (devs_present != devs_unattached) {
1799*0Sstevel@tonic-gate 			/*
1800*0Sstevel@tonic-gate 			 * Only some devices are fully attached.
1801*0Sstevel@tonic-gate 			 */
1802*0Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_PARTIAL);
1803*0Sstevel@tonic-gate 			hp->h_bd->b_rstate = SBD_STAT_CONNECTED;
1804*0Sstevel@tonic-gate 			hp->h_bd->b_ostate = SBD_STAT_CONFIGURED;
1805*0Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
1806*0Sstevel@tonic-gate 		}
1807*0Sstevel@tonic-gate 		break;
1808*0Sstevel@tonic-gate 
1809*0Sstevel@tonic-gate 	case DR_STATE_PARTIAL:
1810*0Sstevel@tonic-gate 		ASSERT(devs_present);
1811*0Sstevel@tonic-gate 		/*
1812*0Sstevel@tonic-gate 		 * All devices finally attached.
1813*0Sstevel@tonic-gate 		 */
1814*0Sstevel@tonic-gate 		if (devs_unattached == 0) {
1815*0Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_CONFIGURED);
1816*0Sstevel@tonic-gate 			hp->h_bd->b_rstate = SBD_STAT_CONNECTED;
1817*0Sstevel@tonic-gate 			hp->h_bd->b_ostate = SBD_STAT_CONFIGURED;
1818*0Sstevel@tonic-gate 			hp->h_bd->b_cond = SBD_COND_OK;
1819*0Sstevel@tonic-gate 			hp->h_bd->b_busy = 0;
1820*0Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
1821*0Sstevel@tonic-gate 		}
1822*0Sstevel@tonic-gate 		break;
1823*0Sstevel@tonic-gate 
1824*0Sstevel@tonic-gate 	default:
1825*0Sstevel@tonic-gate 		break;
1826*0Sstevel@tonic-gate 	}
1827*0Sstevel@tonic-gate }
1828*0Sstevel@tonic-gate 
1829*0Sstevel@tonic-gate static void
1830*0Sstevel@tonic-gate dr_dev_configure(dr_handle_t *hp)
1831*0Sstevel@tonic-gate {
1832*0Sstevel@tonic-gate 	int rv;
1833*0Sstevel@tonic-gate 
1834*0Sstevel@tonic-gate 	rv = dr_dev_walk(hp, SBD_COMP_CPU, 1,
1835*0Sstevel@tonic-gate 		dr_pre_attach_cpu,
1836*0Sstevel@tonic-gate 		dr_attach_cpu,
1837*0Sstevel@tonic-gate 		dr_post_attach_cpu,
1838*0Sstevel@tonic-gate 		dr_attach_update_state);
1839*0Sstevel@tonic-gate 
1840*0Sstevel@tonic-gate 	if (rv >= 0) {
1841*0Sstevel@tonic-gate 		rv = dr_dev_walk(hp, SBD_COMP_MEM, 1,
1842*0Sstevel@tonic-gate 			dr_pre_attach_mem,
1843*0Sstevel@tonic-gate 			dr_attach_mem,
1844*0Sstevel@tonic-gate 			dr_post_attach_mem,
1845*0Sstevel@tonic-gate 			dr_attach_update_state);
1846*0Sstevel@tonic-gate 	}
1847*0Sstevel@tonic-gate 
1848*0Sstevel@tonic-gate 	if (rv >= 0) {
1849*0Sstevel@tonic-gate 		(void) dr_dev_walk(hp, SBD_COMP_IO, 1,
1850*0Sstevel@tonic-gate 			dr_pre_attach_io,
1851*0Sstevel@tonic-gate 			dr_attach_io,
1852*0Sstevel@tonic-gate 			dr_post_attach_io,
1853*0Sstevel@tonic-gate 			dr_attach_update_state);
1854*0Sstevel@tonic-gate 	}
1855*0Sstevel@tonic-gate }
1856*0Sstevel@tonic-gate 
1857*0Sstevel@tonic-gate static void
1858*0Sstevel@tonic-gate dr_release_update_state(dr_handle_t *hp,
1859*0Sstevel@tonic-gate 	dr_common_unit_t **devlist, int devnum)
1860*0Sstevel@tonic-gate {
1861*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(devlist))
1862*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(devnum))
1863*0Sstevel@tonic-gate 
1864*0Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
1865*0Sstevel@tonic-gate 
1866*0Sstevel@tonic-gate 	/*
1867*0Sstevel@tonic-gate 	 * If the entire board was released and all components
1868*0Sstevel@tonic-gate 	 * unreferenced then transfer it to the UNREFERENCED state.
1869*0Sstevel@tonic-gate 	 */
1870*0Sstevel@tonic-gate 	if ((bp->b_state != DR_STATE_RELEASE) &&
1871*0Sstevel@tonic-gate 		(DR_DEVS_RELEASED(bp) == DR_DEVS_ATTACHED(bp))) {
1872*0Sstevel@tonic-gate 		dr_board_transition(bp, DR_STATE_RELEASE);
1873*0Sstevel@tonic-gate 		hp->h_bd->b_busy = 1;
1874*0Sstevel@tonic-gate 	}
1875*0Sstevel@tonic-gate }
1876*0Sstevel@tonic-gate 
1877*0Sstevel@tonic-gate /* called by dr_release_done [below] and dr_release_mem_done [dr_mem.c] */
1878*0Sstevel@tonic-gate int
1879*0Sstevel@tonic-gate dr_release_dev_done(dr_common_unit_t *cp)
1880*0Sstevel@tonic-gate {
1881*0Sstevel@tonic-gate 	if (cp->sbdev_state == DR_STATE_RELEASE) {
1882*0Sstevel@tonic-gate 		ASSERT(DR_DEV_IS_RELEASED(cp));
1883*0Sstevel@tonic-gate 
1884*0Sstevel@tonic-gate 		DR_DEV_SET_UNREFERENCED(cp);
1885*0Sstevel@tonic-gate 
1886*0Sstevel@tonic-gate 		dr_device_transition(cp, DR_STATE_UNREFERENCED);
1887*0Sstevel@tonic-gate 
1888*0Sstevel@tonic-gate 		return (0);
1889*0Sstevel@tonic-gate 	} else {
1890*0Sstevel@tonic-gate 		return (-1);
1891*0Sstevel@tonic-gate 	}
1892*0Sstevel@tonic-gate }
1893*0Sstevel@tonic-gate 
1894*0Sstevel@tonic-gate static void
1895*0Sstevel@tonic-gate dr_release_done(dr_handle_t *hp, dr_common_unit_t *cp)
1896*0Sstevel@tonic-gate {
1897*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(hp))
1898*0Sstevel@tonic-gate 
1899*0Sstevel@tonic-gate 	dr_board_t		*bp;
1900*0Sstevel@tonic-gate 	static fn_t		f = "dr_release_done";
1901*0Sstevel@tonic-gate 
1902*0Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
1903*0Sstevel@tonic-gate 
1904*0Sstevel@tonic-gate 	/* get board pointer & sanity check */
1905*0Sstevel@tonic-gate 	bp = cp->sbdev_bp;
1906*0Sstevel@tonic-gate 	ASSERT(bp == hp->h_bd);
1907*0Sstevel@tonic-gate 
1908*0Sstevel@tonic-gate 	/*
1909*0Sstevel@tonic-gate 	 * Transfer the device which just completed its release
1910*0Sstevel@tonic-gate 	 * to the UNREFERENCED state.
1911*0Sstevel@tonic-gate 	 */
1912*0Sstevel@tonic-gate 	switch (cp->sbdev_type) {
1913*0Sstevel@tonic-gate 	case SBD_COMP_MEM:
1914*0Sstevel@tonic-gate 		dr_release_mem_done(cp);
1915*0Sstevel@tonic-gate 		break;
1916*0Sstevel@tonic-gate 
1917*0Sstevel@tonic-gate 	default:
1918*0Sstevel@tonic-gate 		DR_DEV_SET_RELEASED(cp);
1919*0Sstevel@tonic-gate 
1920*0Sstevel@tonic-gate 		dr_device_transition(cp, DR_STATE_RELEASE);
1921*0Sstevel@tonic-gate 
1922*0Sstevel@tonic-gate 		(void) dr_release_dev_done(cp);
1923*0Sstevel@tonic-gate 		break;
1924*0Sstevel@tonic-gate 	}
1925*0Sstevel@tonic-gate 
1926*0Sstevel@tonic-gate 	/*
1927*0Sstevel@tonic-gate 	 * If we're not already in the RELEASE state for this
1928*0Sstevel@tonic-gate 	 * board and we now have released all that were previously
1929*0Sstevel@tonic-gate 	 * attached, then transfer the board to the RELEASE state.
1930*0Sstevel@tonic-gate 	 */
1931*0Sstevel@tonic-gate 	if ((bp->b_state == DR_STATE_RELEASE) &&
1932*0Sstevel@tonic-gate 		(DR_DEVS_RELEASED(bp) == DR_DEVS_UNREFERENCED(bp))) {
1933*0Sstevel@tonic-gate 		dr_board_transition(bp, DR_STATE_UNREFERENCED);
1934*0Sstevel@tonic-gate 		bp->b_busy = 1;
1935*0Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&bp->b_time);
1936*0Sstevel@tonic-gate 	}
1937*0Sstevel@tonic-gate }
1938*0Sstevel@tonic-gate 
1939*0Sstevel@tonic-gate static void
1940*0Sstevel@tonic-gate dr_dev_release_mem(dr_handle_t *hp, dr_common_unit_t *dv)
1941*0Sstevel@tonic-gate {
1942*0Sstevel@tonic-gate 	dr_release_mem(dv);
1943*0Sstevel@tonic-gate 	dr_release_done(hp, dv);
1944*0Sstevel@tonic-gate }
1945*0Sstevel@tonic-gate 
1946*0Sstevel@tonic-gate static void
1947*0Sstevel@tonic-gate dr_dev_release(dr_handle_t *hp)
1948*0Sstevel@tonic-gate {
1949*0Sstevel@tonic-gate 	int rv;
1950*0Sstevel@tonic-gate 
1951*0Sstevel@tonic-gate 	hp->h_bd->b_busy = 1;
1952*0Sstevel@tonic-gate 
1953*0Sstevel@tonic-gate 	rv = dr_dev_walk(hp, SBD_COMP_CPU, 0,
1954*0Sstevel@tonic-gate 		dr_pre_release_cpu,
1955*0Sstevel@tonic-gate 		dr_release_done,
1956*0Sstevel@tonic-gate 		dr_dev_noop,
1957*0Sstevel@tonic-gate 		dr_release_update_state);
1958*0Sstevel@tonic-gate 
1959*0Sstevel@tonic-gate 	if (rv >= 0) {
1960*0Sstevel@tonic-gate 		rv = dr_dev_walk(hp, SBD_COMP_MEM, 0,
1961*0Sstevel@tonic-gate 			dr_pre_release_mem,
1962*0Sstevel@tonic-gate 			dr_dev_release_mem,
1963*0Sstevel@tonic-gate 			dr_dev_noop,
1964*0Sstevel@tonic-gate 			dr_release_update_state);
1965*0Sstevel@tonic-gate 	}
1966*0Sstevel@tonic-gate 
1967*0Sstevel@tonic-gate 	if (rv >= 0) {
1968*0Sstevel@tonic-gate 		rv = dr_dev_walk(hp, SBD_COMP_IO, 0,
1969*0Sstevel@tonic-gate 			dr_pre_release_io,
1970*0Sstevel@tonic-gate 			dr_release_done,
1971*0Sstevel@tonic-gate 			dr_dev_noop,
1972*0Sstevel@tonic-gate 			dr_release_update_state);
1973*0Sstevel@tonic-gate 
1974*0Sstevel@tonic-gate 	}
1975*0Sstevel@tonic-gate 
1976*0Sstevel@tonic-gate 	if (rv < 0)
1977*0Sstevel@tonic-gate 		hp->h_bd->b_busy = 0;
1978*0Sstevel@tonic-gate 	/* else, b_busy will be cleared in dr_detach_update_state() */
1979*0Sstevel@tonic-gate }
1980*0Sstevel@tonic-gate 
1981*0Sstevel@tonic-gate static void
1982*0Sstevel@tonic-gate dr_detach_update_state(dr_handle_t *hp,
1983*0Sstevel@tonic-gate 	dr_common_unit_t **devlist, int devnum)
1984*0Sstevel@tonic-gate {
1985*0Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
1986*0Sstevel@tonic-gate 	int		i;
1987*0Sstevel@tonic-gate 	dr_state_t	bstate;
1988*0Sstevel@tonic-gate 	static fn_t	f = "dr_detach_update_state";
1989*0Sstevel@tonic-gate 
1990*0Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
1991*0Sstevel@tonic-gate 		dr_common_unit_t *cp = devlist[i];
1992*0Sstevel@tonic-gate 
1993*0Sstevel@tonic-gate 		if (dr_check_unit_attached(cp) >= 0) {
1994*0Sstevel@tonic-gate 			/*
1995*0Sstevel@tonic-gate 			 * Device is still attached probably due
1996*0Sstevel@tonic-gate 			 * to an error.  Need to keep track of it.
1997*0Sstevel@tonic-gate 			 */
1998*0Sstevel@tonic-gate 			PR_ALL("%s: ERROR %s not detached\n",
1999*0Sstevel@tonic-gate 				f, cp->sbdev_path);
2000*0Sstevel@tonic-gate 
2001*0Sstevel@tonic-gate 			continue;
2002*0Sstevel@tonic-gate 		}
2003*0Sstevel@tonic-gate 
2004*0Sstevel@tonic-gate 		DR_DEV_CLR_ATTACHED(cp);
2005*0Sstevel@tonic-gate 		DR_DEV_CLR_RELEASED(cp);
2006*0Sstevel@tonic-gate 		DR_DEV_CLR_UNREFERENCED(cp);
2007*0Sstevel@tonic-gate 		dr_device_transition(cp, DR_STATE_UNCONFIGURED);
2008*0Sstevel@tonic-gate 	}
2009*0Sstevel@tonic-gate 
2010*0Sstevel@tonic-gate 	bstate = bp->b_state;
2011*0Sstevel@tonic-gate 	if (bstate != DR_STATE_UNCONFIGURED) {
2012*0Sstevel@tonic-gate 		if (DR_DEVS_PRESENT(bp) == DR_DEVS_UNATTACHED(bp)) {
2013*0Sstevel@tonic-gate 			/*
2014*0Sstevel@tonic-gate 			 * All devices are finally detached.
2015*0Sstevel@tonic-gate 			 */
2016*0Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_UNCONFIGURED);
2017*0Sstevel@tonic-gate 			hp->h_bd->b_ostate = SBD_STAT_UNCONFIGURED;
2018*0Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
2019*0Sstevel@tonic-gate 		} else if ((bp->b_state != DR_STATE_PARTIAL) &&
2020*0Sstevel@tonic-gate 				(DR_DEVS_ATTACHED(bp) !=
2021*0Sstevel@tonic-gate 					DR_DEVS_PRESENT(bp))) {
2022*0Sstevel@tonic-gate 			/*
2023*0Sstevel@tonic-gate 			 * Some devices remain attached.
2024*0Sstevel@tonic-gate 			 */
2025*0Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_PARTIAL);
2026*0Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
2027*0Sstevel@tonic-gate 		}
2028*0Sstevel@tonic-gate 
2029*0Sstevel@tonic-gate 		if ((hp->h_devset & DR_DEVS_UNATTACHED(bp)) == hp->h_devset)
2030*0Sstevel@tonic-gate 			hp->h_bd->b_busy = 0;
2031*0Sstevel@tonic-gate 	}
2032*0Sstevel@tonic-gate }
2033*0Sstevel@tonic-gate 
2034*0Sstevel@tonic-gate static int
2035*0Sstevel@tonic-gate dr_dev_unconfigure(dr_handle_t *hp)
2036*0Sstevel@tonic-gate {
2037*0Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
2038*0Sstevel@tonic-gate 
2039*0Sstevel@tonic-gate 	/*
2040*0Sstevel@tonic-gate 	 * Block out status during IO unconfig.
2041*0Sstevel@tonic-gate 	 */
2042*0Sstevel@tonic-gate 	mutex_enter(&bp->b_slock);
2043*0Sstevel@tonic-gate 	while (bp->b_sflags & DR_BSLOCK) {
2044*0Sstevel@tonic-gate 		if (cv_wait_sig(&bp->b_scv, &bp->b_slock) == 0) {
2045*0Sstevel@tonic-gate 			mutex_exit(&bp->b_slock);
2046*0Sstevel@tonic-gate 			return (EINTR);
2047*0Sstevel@tonic-gate 		}
2048*0Sstevel@tonic-gate 	}
2049*0Sstevel@tonic-gate 	bp->b_sflags |= DR_BSLOCK;
2050*0Sstevel@tonic-gate 	mutex_exit(&bp->b_slock);
2051*0Sstevel@tonic-gate 
2052*0Sstevel@tonic-gate 	(void) dr_dev_walk(hp, SBD_COMP_IO, 0,
2053*0Sstevel@tonic-gate 		dr_pre_detach_io,
2054*0Sstevel@tonic-gate 		dr_detach_io,
2055*0Sstevel@tonic-gate 		dr_post_detach_io,
2056*0Sstevel@tonic-gate 		dr_detach_update_state);
2057*0Sstevel@tonic-gate 
2058*0Sstevel@tonic-gate 	dr_unlock_status(bp);
2059*0Sstevel@tonic-gate 
2060*0Sstevel@tonic-gate 	(void) dr_dev_walk(hp, SBD_COMP_CPU, 0,
2061*0Sstevel@tonic-gate 		dr_pre_detach_cpu,
2062*0Sstevel@tonic-gate 		dr_detach_cpu,
2063*0Sstevel@tonic-gate 		dr_post_detach_cpu,
2064*0Sstevel@tonic-gate 		dr_detach_update_state);
2065*0Sstevel@tonic-gate 
2066*0Sstevel@tonic-gate 	(void) dr_dev_walk(hp, SBD_COMP_MEM, 0,
2067*0Sstevel@tonic-gate 		dr_pre_detach_mem,
2068*0Sstevel@tonic-gate 		dr_detach_mem,
2069*0Sstevel@tonic-gate 		dr_post_detach_mem,
2070*0Sstevel@tonic-gate 		dr_detach_update_state);
2071*0Sstevel@tonic-gate 
2072*0Sstevel@tonic-gate 	return (0);
2073*0Sstevel@tonic-gate }
2074*0Sstevel@tonic-gate 
2075*0Sstevel@tonic-gate static void
2076*0Sstevel@tonic-gate dr_dev_cancel(dr_handle_t *hp)
2077*0Sstevel@tonic-gate {
2078*0Sstevel@tonic-gate 	int		i;
2079*0Sstevel@tonic-gate 	dr_devset_t	devset;
2080*0Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
2081*0Sstevel@tonic-gate 	static fn_t	f = "dr_dev_cancel";
2082*0Sstevel@tonic-gate 
2083*0Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
2084*0Sstevel@tonic-gate 
2085*0Sstevel@tonic-gate 	/*
2086*0Sstevel@tonic-gate 	 * Only devices which have been "released" are
2087*0Sstevel@tonic-gate 	 * subject to cancellation.
2088*0Sstevel@tonic-gate 	 */
2089*0Sstevel@tonic-gate 	devset = hp->h_devset & DR_DEVS_RELEASED(bp);
2090*0Sstevel@tonic-gate 
2091*0Sstevel@tonic-gate 	/*
2092*0Sstevel@tonic-gate 	 * Nothing to do for CPUs or IO other than change back
2093*0Sstevel@tonic-gate 	 * their state.
2094*0Sstevel@tonic-gate 	 */
2095*0Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
2096*0Sstevel@tonic-gate 		dr_cpu_unit_t	*cp;
2097*0Sstevel@tonic-gate 		dr_state_t	nstate;
2098*0Sstevel@tonic-gate 
2099*0Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_CPU, i))
2100*0Sstevel@tonic-gate 			continue;
2101*0Sstevel@tonic-gate 
2102*0Sstevel@tonic-gate 		cp = dr_get_cpu_unit(bp, i);
2103*0Sstevel@tonic-gate 		if (dr_cancel_cpu(cp) == 0)
2104*0Sstevel@tonic-gate 			nstate = DR_STATE_CONFIGURED;
2105*0Sstevel@tonic-gate 		else
2106*0Sstevel@tonic-gate 			nstate = DR_STATE_FATAL;
2107*0Sstevel@tonic-gate 
2108*0Sstevel@tonic-gate 		dr_device_transition(&cp->sbc_cm, nstate);
2109*0Sstevel@tonic-gate 	}
2110*0Sstevel@tonic-gate 
2111*0Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
2112*0Sstevel@tonic-gate 		dr_io_unit_t *ip;
2113*0Sstevel@tonic-gate 
2114*0Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_IO, i))
2115*0Sstevel@tonic-gate 			continue;
2116*0Sstevel@tonic-gate 		ip = dr_get_io_unit(bp, i);
2117*0Sstevel@tonic-gate 		dr_device_transition(&ip->sbi_cm, DR_STATE_CONFIGURED);
2118*0Sstevel@tonic-gate 	}
2119*0Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
2120*0Sstevel@tonic-gate 		dr_mem_unit_t	*mp;
2121*0Sstevel@tonic-gate 		dr_state_t	nstate;
2122*0Sstevel@tonic-gate 
2123*0Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_MEM, i))
2124*0Sstevel@tonic-gate 			continue;
2125*0Sstevel@tonic-gate 
2126*0Sstevel@tonic-gate 		mp = dr_get_mem_unit(bp, i);
2127*0Sstevel@tonic-gate 		if (dr_cancel_mem(mp) == 0)
2128*0Sstevel@tonic-gate 			nstate = DR_STATE_CONFIGURED;
2129*0Sstevel@tonic-gate 		else
2130*0Sstevel@tonic-gate 			nstate = DR_STATE_FATAL;
2131*0Sstevel@tonic-gate 
2132*0Sstevel@tonic-gate 		dr_device_transition(&mp->sbm_cm, nstate);
2133*0Sstevel@tonic-gate 	}
2134*0Sstevel@tonic-gate 
2135*0Sstevel@tonic-gate 	PR_ALL("%s: unreleasing devset (0x%x)\n", f, (uint_t)devset);
2136*0Sstevel@tonic-gate 
2137*0Sstevel@tonic-gate 	DR_DEVS_CANCEL(bp, devset);
2138*0Sstevel@tonic-gate 
2139*0Sstevel@tonic-gate 	if (DR_DEVS_RELEASED(bp) == 0) {
2140*0Sstevel@tonic-gate 		dr_state_t	new_state;
2141*0Sstevel@tonic-gate 		/*
2142*0Sstevel@tonic-gate 		 * If the board no longer has any released devices
2143*0Sstevel@tonic-gate 		 * than transfer it back to the CONFIG/PARTIAL state.
2144*0Sstevel@tonic-gate 		 */
2145*0Sstevel@tonic-gate 		if (DR_DEVS_ATTACHED(bp) == DR_DEVS_PRESENT(bp))
2146*0Sstevel@tonic-gate 			new_state = DR_STATE_CONFIGURED;
2147*0Sstevel@tonic-gate 		else
2148*0Sstevel@tonic-gate 			new_state = DR_STATE_PARTIAL;
2149*0Sstevel@tonic-gate 		if (bp->b_state != new_state) {
2150*0Sstevel@tonic-gate 			dr_board_transition(bp, new_state);
2151*0Sstevel@tonic-gate 		}
2152*0Sstevel@tonic-gate 		hp->h_bd->b_ostate = SBD_STAT_CONFIGURED;
2153*0Sstevel@tonic-gate 		hp->h_bd->b_busy = 0;
2154*0Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
2155*0Sstevel@tonic-gate 	}
2156*0Sstevel@tonic-gate }
2157*0Sstevel@tonic-gate 
2158*0Sstevel@tonic-gate static int
2159*0Sstevel@tonic-gate dr_dev_status(dr_handle_t *hp)
2160*0Sstevel@tonic-gate {
2161*0Sstevel@tonic-gate 	int		nstat, mode, ncm, sz, pbsz, pnstat;
2162*0Sstevel@tonic-gate 	dr_handle_t	*shp;
2163*0Sstevel@tonic-gate 	dr_devset_t	devset = 0;
2164*0Sstevel@tonic-gate 	sbd_stat_t	*dstatp = NULL;
2165*0Sstevel@tonic-gate 	sbd_dev_stat_t	*devstatp;
2166*0Sstevel@tonic-gate 	dr_board_t	*bp;
2167*0Sstevel@tonic-gate 	drmach_status_t	 pstat;
2168*0Sstevel@tonic-gate 	int		rv = 0;
2169*0Sstevel@tonic-gate 
2170*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
2171*0Sstevel@tonic-gate 	int sz32 = 0;
2172*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
2173*0Sstevel@tonic-gate 
2174*0Sstevel@tonic-gate 	static fn_t	f = "dr_status";
2175*0Sstevel@tonic-gate 
2176*0Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
2177*0Sstevel@tonic-gate 
2178*0Sstevel@tonic-gate 	mode = hp->h_mode;
2179*0Sstevel@tonic-gate 	shp = hp;
2180*0Sstevel@tonic-gate 	devset = shp->h_devset;
2181*0Sstevel@tonic-gate 	bp = hp->h_bd;
2182*0Sstevel@tonic-gate 
2183*0Sstevel@tonic-gate 	/*
2184*0Sstevel@tonic-gate 	 * Block out disconnect, unassign, IO unconfigure and
2185*0Sstevel@tonic-gate 	 * devinfo branch creation during status.
2186*0Sstevel@tonic-gate 	 */
2187*0Sstevel@tonic-gate 	mutex_enter(&bp->b_slock);
2188*0Sstevel@tonic-gate 	while (bp->b_sflags & DR_BSLOCK) {
2189*0Sstevel@tonic-gate 		if (cv_wait_sig(&bp->b_scv, &bp->b_slock) == 0) {
2190*0Sstevel@tonic-gate 			mutex_exit(&bp->b_slock);
2191*0Sstevel@tonic-gate 			return (EINTR);
2192*0Sstevel@tonic-gate 		}
2193*0Sstevel@tonic-gate 	}
2194*0Sstevel@tonic-gate 	bp->b_sflags |= DR_BSLOCK;
2195*0Sstevel@tonic-gate 	mutex_exit(&bp->b_slock);
2196*0Sstevel@tonic-gate 
2197*0Sstevel@tonic-gate 	ncm = 1;
2198*0Sstevel@tonic-gate 	if (hp->h_sbdcmd.cmd_cm.c_id.c_type == SBD_COMP_NONE) {
2199*0Sstevel@tonic-gate 		if (dr_cmd_flags(hp) & SBD_FLAG_ALLCMP) {
2200*0Sstevel@tonic-gate 		/*
2201*0Sstevel@tonic-gate 		 * Calculate the maximum number of components possible
2202*0Sstevel@tonic-gate 		 * for a board.  This number will be used to size the
2203*0Sstevel@tonic-gate 		 * status scratch buffer used by board and component
2204*0Sstevel@tonic-gate 		 * status functions.
2205*0Sstevel@tonic-gate 		 * This buffer may differ in size from what is provided
2206*0Sstevel@tonic-gate 		 * by the plugin, since the known component set on the
2207*0Sstevel@tonic-gate 		 * board may change between the plugin's GETNCM call, and
2208*0Sstevel@tonic-gate 		 * the status call.  Sizing will be adjusted to the plugin's
2209*0Sstevel@tonic-gate 		 * receptacle buffer at copyout time.
2210*0Sstevel@tonic-gate 		 */
2211*0Sstevel@tonic-gate 			ncm = MAX_CPU_UNITS_PER_BOARD +
2212*0Sstevel@tonic-gate 				MAX_MEM_UNITS_PER_BOARD +
2213*0Sstevel@tonic-gate 				MAX_IO_UNITS_PER_BOARD;
2214*0Sstevel@tonic-gate 
2215*0Sstevel@tonic-gate 		} else {
2216*0Sstevel@tonic-gate 			/*
2217*0Sstevel@tonic-gate 			 * In the case of c_type == SBD_COMP_NONE, and
2218*0Sstevel@tonic-gate 			 * SBD_FLAG_ALLCMP not specified, only the board
2219*0Sstevel@tonic-gate 			 * info is to be returned, no components.
2220*0Sstevel@tonic-gate 			 */
2221*0Sstevel@tonic-gate 			ncm = 0;
2222*0Sstevel@tonic-gate 			devset = 0;
2223*0Sstevel@tonic-gate 		}
2224*0Sstevel@tonic-gate 	}
2225*0Sstevel@tonic-gate 
2226*0Sstevel@tonic-gate 	sz = sizeof (sbd_stat_t);
2227*0Sstevel@tonic-gate 	if (ncm > 1)
2228*0Sstevel@tonic-gate 		sz += sizeof (sbd_dev_stat_t) * (ncm - 1);
2229*0Sstevel@tonic-gate 
2230*0Sstevel@tonic-gate 
2231*0Sstevel@tonic-gate 	pbsz = (int)hp->h_sbdcmd.cmd_stat.s_nbytes;
2232*0Sstevel@tonic-gate 	pnstat = (pbsz - sizeof (sbd_stat_t))/sizeof (sbd_dev_stat_t);
2233*0Sstevel@tonic-gate 
2234*0Sstevel@tonic-gate 	/*
2235*0Sstevel@tonic-gate 	 * s_nbytes describes the size of the preallocated user
2236*0Sstevel@tonic-gate 	 * buffer into which the application is execting to
2237*0Sstevel@tonic-gate 	 * receive the sbd_stat_t and sbd_dev_stat_t structures.
2238*0Sstevel@tonic-gate 	 */
2239*0Sstevel@tonic-gate 
2240*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
2241*0Sstevel@tonic-gate 
2242*0Sstevel@tonic-gate 	/*
2243*0Sstevel@tonic-gate 	 * More buffer space is required for the 64bit to 32bit
2244*0Sstevel@tonic-gate 	 * conversion of data structures.
2245*0Sstevel@tonic-gate 	 */
2246*0Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2247*0Sstevel@tonic-gate 		sz32 = sizeof (sbd_stat32_t);
2248*0Sstevel@tonic-gate 		if (ncm > 1)
2249*0Sstevel@tonic-gate 			sz32  += sizeof (sbd_dev_stat32_t) * (ncm - 1);
2250*0Sstevel@tonic-gate 		pnstat = (pbsz - sizeof (sbd_stat32_t))/
2251*0Sstevel@tonic-gate 				sizeof (sbd_dev_stat32_t);
2252*0Sstevel@tonic-gate 	}
2253*0Sstevel@tonic-gate 
2254*0Sstevel@tonic-gate 	sz += sz32;
2255*0Sstevel@tonic-gate #endif
2256*0Sstevel@tonic-gate 	/*
2257*0Sstevel@tonic-gate 	 * Since one sbd_dev_stat_t is included in the sbd_stat_t,
2258*0Sstevel@tonic-gate 	 * increment the plugin's nstat count.
2259*0Sstevel@tonic-gate 	 */
2260*0Sstevel@tonic-gate 	++pnstat;
2261*0Sstevel@tonic-gate 
2262*0Sstevel@tonic-gate 	if (bp->b_id == 0) {
2263*0Sstevel@tonic-gate 		bzero(&pstat, sizeof (pstat));
2264*0Sstevel@tonic-gate 	} else {
2265*0Sstevel@tonic-gate 		sbd_error_t *err;
2266*0Sstevel@tonic-gate 
2267*0Sstevel@tonic-gate 		err = drmach_status(bp->b_id, &pstat);
2268*0Sstevel@tonic-gate 		if (err) {
2269*0Sstevel@tonic-gate 			DRERR_SET_C(&hp->h_err, &err);
2270*0Sstevel@tonic-gate 			rv = EIO;
2271*0Sstevel@tonic-gate 			goto status_done;
2272*0Sstevel@tonic-gate 		}
2273*0Sstevel@tonic-gate 	}
2274*0Sstevel@tonic-gate 
2275*0Sstevel@tonic-gate 	dstatp = (sbd_stat_t *)GETSTRUCT(char, sz);
2276*0Sstevel@tonic-gate 
2277*0Sstevel@tonic-gate 	devstatp = &dstatp->s_stat[0];
2278*0Sstevel@tonic-gate 
2279*0Sstevel@tonic-gate 	dstatp->s_board = bp->b_num;
2280*0Sstevel@tonic-gate 
2281*0Sstevel@tonic-gate 	/*
2282*0Sstevel@tonic-gate 	 * Detect transitions between empty and disconnected.
2283*0Sstevel@tonic-gate 	 */
2284*0Sstevel@tonic-gate 	if (!pstat.empty && (bp->b_rstate == SBD_STAT_EMPTY))
2285*0Sstevel@tonic-gate 		bp->b_rstate = SBD_STAT_DISCONNECTED;
2286*0Sstevel@tonic-gate 	else if (pstat.empty && (bp->b_rstate == SBD_STAT_DISCONNECTED))
2287*0Sstevel@tonic-gate 		bp->b_rstate = SBD_STAT_EMPTY;
2288*0Sstevel@tonic-gate 
2289*0Sstevel@tonic-gate 	dstatp->s_rstate = bp->b_rstate;
2290*0Sstevel@tonic-gate 	dstatp->s_ostate = bp->b_ostate;
2291*0Sstevel@tonic-gate 	dstatp->s_cond = bp->b_cond = pstat.cond;
2292*0Sstevel@tonic-gate 	dstatp->s_busy = bp->b_busy | pstat.busy;
2293*0Sstevel@tonic-gate 	dstatp->s_time = bp->b_time;
2294*0Sstevel@tonic-gate 	dstatp->s_power = pstat.powered;
2295*0Sstevel@tonic-gate 	dstatp->s_assigned = bp->b_assigned = pstat.assigned;
2296*0Sstevel@tonic-gate 	dstatp->s_nstat = nstat = 0;
2297*0Sstevel@tonic-gate 	bcopy(&pstat.type[0], &dstatp->s_type[0], SBD_TYPE_LEN);
2298*0Sstevel@tonic-gate 	bcopy(&pstat.info[0], &dstatp->s_info[0], SBD_MAX_INFO);
2299*0Sstevel@tonic-gate 
2300*0Sstevel@tonic-gate 	devset &= DR_DEVS_PRESENT(bp);
2301*0Sstevel@tonic-gate 	if (devset == 0) {
2302*0Sstevel@tonic-gate 		/*
2303*0Sstevel@tonic-gate 		 * No device chosen.
2304*0Sstevel@tonic-gate 		 */
2305*0Sstevel@tonic-gate 		PR_ALL("%s: no device present\n", f);
2306*0Sstevel@tonic-gate 	}
2307*0Sstevel@tonic-gate 
2308*0Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT))
2309*0Sstevel@tonic-gate 		if ((nstat = dr_cpu_status(hp, devset, devstatp)) > 0) {
2310*0Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
2311*0Sstevel@tonic-gate 			devstatp += nstat;
2312*0Sstevel@tonic-gate 		}
2313*0Sstevel@tonic-gate 
2314*0Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT))
2315*0Sstevel@tonic-gate 		if ((nstat = dr_mem_status(hp, devset, devstatp)) > 0) {
2316*0Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
2317*0Sstevel@tonic-gate 			devstatp += nstat;
2318*0Sstevel@tonic-gate 		}
2319*0Sstevel@tonic-gate 
2320*0Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT))
2321*0Sstevel@tonic-gate 		if ((nstat = dr_io_status(hp, devset, devstatp)) > 0) {
2322*0Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
2323*0Sstevel@tonic-gate 			devstatp += nstat;
2324*0Sstevel@tonic-gate 		}
2325*0Sstevel@tonic-gate 
2326*0Sstevel@tonic-gate 	/*
2327*0Sstevel@tonic-gate 	 * Due to a possible change in number of components between
2328*0Sstevel@tonic-gate 	 * the time of plugin's GETNCM call and now, there may be
2329*0Sstevel@tonic-gate 	 * more or less components than the plugin's buffer can
2330*0Sstevel@tonic-gate 	 * hold.  Adjust s_nstat accordingly.
2331*0Sstevel@tonic-gate 	 */
2332*0Sstevel@tonic-gate 
2333*0Sstevel@tonic-gate 	dstatp->s_nstat = dstatp->s_nstat > pnstat ? pnstat : dstatp->s_nstat;
2334*0Sstevel@tonic-gate 
2335*0Sstevel@tonic-gate 
2336*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
2337*0Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2338*0Sstevel@tonic-gate 		int		i, j;
2339*0Sstevel@tonic-gate 		sbd_stat32_t	*dstat32p;
2340*0Sstevel@tonic-gate 
2341*0Sstevel@tonic-gate 		dstat32p = (sbd_stat32_t *)devstatp;
2342*0Sstevel@tonic-gate 
2343*0Sstevel@tonic-gate 		/* Alignment Paranoia */
2344*0Sstevel@tonic-gate 		if ((ulong_t)dstat32p & 0x1) {
2345*0Sstevel@tonic-gate 			PR_ALL("%s: alignment: sz=0x%x dstat32p=0x%x\n",
2346*0Sstevel@tonic-gate 				f, sizeof (sbd_stat32_t), dstat32p);
2347*0Sstevel@tonic-gate 			DR_OP_INTERNAL_ERROR(hp);
2348*0Sstevel@tonic-gate 			rv = EINVAL;
2349*0Sstevel@tonic-gate 			goto status_done;
2350*0Sstevel@tonic-gate 		}
2351*0Sstevel@tonic-gate 
2352*0Sstevel@tonic-gate 		/* paranoia: detect buffer overrun */
2353*0Sstevel@tonic-gate 		if ((caddr_t)&dstat32p->s_stat[dstatp->s_nstat] >
2354*0Sstevel@tonic-gate 				((caddr_t)dstatp) + sz) {
2355*0Sstevel@tonic-gate 			DR_OP_INTERNAL_ERROR(hp);
2356*0Sstevel@tonic-gate 			rv = EINVAL;
2357*0Sstevel@tonic-gate 			goto status_done;
2358*0Sstevel@tonic-gate 		}
2359*0Sstevel@tonic-gate 
2360*0Sstevel@tonic-gate 		/* copy sbd_stat_t structure members */
2361*0Sstevel@tonic-gate #define	_SBD_STAT(t, m) dstat32p->m = (t)dstatp->m
2362*0Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_board);
2363*0Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_rstate);
2364*0Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_ostate);
2365*0Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_cond);
2366*0Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_busy);
2367*0Sstevel@tonic-gate 		_SBD_STAT(time32_t, s_time);
2368*0Sstevel@tonic-gate 		_SBD_STAT(uint32_t, s_power);
2369*0Sstevel@tonic-gate 		_SBD_STAT(uint32_t, s_assigned);
2370*0Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_nstat);
2371*0Sstevel@tonic-gate 		bcopy(&dstatp->s_type[0], &dstat32p->s_type[0],
2372*0Sstevel@tonic-gate 			SBD_TYPE_LEN);
2373*0Sstevel@tonic-gate 		bcopy(&dstatp->s_info[0], &dstat32p->s_info[0],
2374*0Sstevel@tonic-gate 			SBD_MAX_INFO);
2375*0Sstevel@tonic-gate #undef _SBD_STAT
2376*0Sstevel@tonic-gate 
2377*0Sstevel@tonic-gate 		for (i = 0; i < dstatp->s_nstat; i++) {
2378*0Sstevel@tonic-gate 			sbd_dev_stat_t		*dsp = &dstatp->s_stat[i];
2379*0Sstevel@tonic-gate 			sbd_dev_stat32_t	*ds32p = &dstat32p->s_stat[i];
2380*0Sstevel@tonic-gate #define	_SBD_DEV_STAT(t, m) ds32p->m = (t)dsp->m
2381*0Sstevel@tonic-gate 
2382*0Sstevel@tonic-gate 			/* copy sbd_cm_stat_t structure members */
2383*0Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_type);
2384*0Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_unit);
2385*0Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_ostate);
2386*0Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_cond);
2387*0Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_busy);
2388*0Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_suspend);
2389*0Sstevel@tonic-gate 			_SBD_DEV_STAT(time32_t, ds_time);
2390*0Sstevel@tonic-gate 			bcopy(&dsp->ds_name[0], &ds32p->ds_name[0],
2391*0Sstevel@tonic-gate 			    OBP_MAXPROPNAME);
2392*0Sstevel@tonic-gate 
2393*0Sstevel@tonic-gate 			switch (dsp->ds_type) {
2394*0Sstevel@tonic-gate 			case SBD_COMP_CPU:
2395*0Sstevel@tonic-gate 				/* copy sbd_cpu_stat_t structure members */
2396*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cpu.cs_isbootproc);
2397*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cpu.cs_cpuid);
2398*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cpu.cs_speed);
2399*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cpu.cs_ecache);
2400*0Sstevel@tonic-gate 				break;
2401*0Sstevel@tonic-gate 
2402*0Sstevel@tonic-gate 			case SBD_COMP_MEM:
2403*0Sstevel@tonic-gate 				/* copy sbd_mem_stat_t structure members */
2404*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_mem.ms_interleave);
2405*0Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_basepfn);
2406*0Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_totpages);
2407*0Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_detpages);
2408*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_mem.ms_pageslost);
2409*0Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_managed_pages);
2410*0Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_noreloc_pages);
2411*0Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_noreloc_first);
2412*0Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_noreloc_last);
2413*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_mem.ms_cage_enabled);
2414*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_mem.ms_peer_is_target);
2415*0Sstevel@tonic-gate 				bcopy(&dsp->d_mem.ms_peer_ap_id[0],
2416*0Sstevel@tonic-gate 					&ds32p->d_mem.ms_peer_ap_id[0],
2417*0Sstevel@tonic-gate 					sizeof (ds32p->d_mem.ms_peer_ap_id));
2418*0Sstevel@tonic-gate 				break;
2419*0Sstevel@tonic-gate 
2420*0Sstevel@tonic-gate 			case SBD_COMP_IO:
2421*0Sstevel@tonic-gate 				/* copy sbd_io_stat_t structure members */
2422*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_io.is_referenced);
2423*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_io.is_unsafe_count);
2424*0Sstevel@tonic-gate 
2425*0Sstevel@tonic-gate 				for (j = 0; j < SBD_MAX_UNSAFE; j++)
2426*0Sstevel@tonic-gate 					_SBD_DEV_STAT(int32_t,
2427*0Sstevel@tonic-gate 						d_io.is_unsafe_list[j]);
2428*0Sstevel@tonic-gate 
2429*0Sstevel@tonic-gate 				bcopy(&dsp->d_io.is_pathname[0],
2430*0Sstevel@tonic-gate 				    &ds32p->d_io.is_pathname[0], MAXPATHLEN);
2431*0Sstevel@tonic-gate 				break;
2432*0Sstevel@tonic-gate 
2433*0Sstevel@tonic-gate 			case SBD_COMP_CMP:
2434*0Sstevel@tonic-gate 				/* copy sbd_cmp_stat_t structure members */
2435*0Sstevel@tonic-gate 				bcopy(&dsp->d_cmp.ps_cpuid[0],
2436*0Sstevel@tonic-gate 					&ds32p->d_cmp.ps_cpuid[0],
2437*0Sstevel@tonic-gate 					sizeof (ds32p->d_cmp.ps_cpuid));
2438*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cmp.ps_ncores);
2439*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cmp.ps_speed);
2440*0Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cmp.ps_ecache);
2441*0Sstevel@tonic-gate 				break;
2442*0Sstevel@tonic-gate 
2443*0Sstevel@tonic-gate 			default:
2444*0Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s: unknown dev type (%d)",
2445*0Sstevel@tonic-gate 				    f, (int)dsp->ds_type);
2446*0Sstevel@tonic-gate 				rv = EFAULT;
2447*0Sstevel@tonic-gate 				goto status_done;
2448*0Sstevel@tonic-gate 			}
2449*0Sstevel@tonic-gate #undef _SBD_DEV_STAT
2450*0Sstevel@tonic-gate 		}
2451*0Sstevel@tonic-gate 
2452*0Sstevel@tonic-gate 
2453*0Sstevel@tonic-gate 		if (ddi_copyout((void *)dstat32p,
2454*0Sstevel@tonic-gate 			hp->h_sbdcmd.cmd_stat.s_statp, pbsz, mode) != 0) {
2455*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
2456*0Sstevel@tonic-gate 				"%s: failed to copyout status "
2457*0Sstevel@tonic-gate 				"for board %d", f, bp->b_num);
2458*0Sstevel@tonic-gate 			rv = EFAULT;
2459*0Sstevel@tonic-gate 			goto status_done;
2460*0Sstevel@tonic-gate 		}
2461*0Sstevel@tonic-gate 	} else
2462*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
2463*0Sstevel@tonic-gate 
2464*0Sstevel@tonic-gate 	if (ddi_copyout((void *)dstatp, hp->h_sbdcmd.cmd_stat.s_statp,
2465*0Sstevel@tonic-gate 		pbsz, mode) != 0) {
2466*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
2467*0Sstevel@tonic-gate 			"%s: failed to copyout status for board %d",
2468*0Sstevel@tonic-gate 			f, bp->b_num);
2469*0Sstevel@tonic-gate 		rv = EFAULT;
2470*0Sstevel@tonic-gate 		goto status_done;
2471*0Sstevel@tonic-gate 	}
2472*0Sstevel@tonic-gate 
2473*0Sstevel@tonic-gate status_done:
2474*0Sstevel@tonic-gate 	if (dstatp != NULL)
2475*0Sstevel@tonic-gate 		FREESTRUCT(dstatp, char, sz);
2476*0Sstevel@tonic-gate 
2477*0Sstevel@tonic-gate 	dr_unlock_status(bp);
2478*0Sstevel@tonic-gate 
2479*0Sstevel@tonic-gate 	return (rv);
2480*0Sstevel@tonic-gate }
2481*0Sstevel@tonic-gate 
2482*0Sstevel@tonic-gate static int
2483*0Sstevel@tonic-gate dr_get_ncm(dr_handle_t *hp)
2484*0Sstevel@tonic-gate {
2485*0Sstevel@tonic-gate 	int		i;
2486*0Sstevel@tonic-gate 	int		ncm = 0;
2487*0Sstevel@tonic-gate 	dr_devset_t	devset;
2488*0Sstevel@tonic-gate 
2489*0Sstevel@tonic-gate 	devset = DR_DEVS_PRESENT(hp->h_bd);
2490*0Sstevel@tonic-gate 	if (hp->h_sbdcmd.cmd_cm.c_id.c_type != SBD_COMP_NONE)
2491*0Sstevel@tonic-gate 		devset &= DEVSET(hp->h_sbdcmd.cmd_cm.c_id.c_type,
2492*0Sstevel@tonic-gate 				DEVSET_ANYUNIT);
2493*0Sstevel@tonic-gate 
2494*0Sstevel@tonic-gate 	/*
2495*0Sstevel@tonic-gate 	 * Handle CPUs first to deal with possible CMP
2496*0Sstevel@tonic-gate 	 * devices. If the CPU is a CMP, we need to only
2497*0Sstevel@tonic-gate 	 * increment ncm once even if there are multiple
2498*0Sstevel@tonic-gate 	 * cores for that CMP present in the devset.
2499*0Sstevel@tonic-gate 	 */
2500*0Sstevel@tonic-gate 	for (i = 0; i < MAX_CMP_UNITS_PER_BOARD; i++) {
2501*0Sstevel@tonic-gate 		if (devset & DEVSET(SBD_COMP_CMP, i)) {
2502*0Sstevel@tonic-gate 			ncm++;
2503*0Sstevel@tonic-gate 		}
2504*0Sstevel@tonic-gate 	}
2505*0Sstevel@tonic-gate 
2506*0Sstevel@tonic-gate 	/* eliminate the CPU information from the devset */
2507*0Sstevel@tonic-gate 	devset &= ~(DEVSET(SBD_COMP_CMP, DEVSET_ANYUNIT));
2508*0Sstevel@tonic-gate 
2509*0Sstevel@tonic-gate 	for (i = 0; i < (sizeof (dr_devset_t) * 8); i++) {
2510*0Sstevel@tonic-gate 		ncm += devset & 0x1;
2511*0Sstevel@tonic-gate 		devset >>= 1;
2512*0Sstevel@tonic-gate 	}
2513*0Sstevel@tonic-gate 
2514*0Sstevel@tonic-gate 	return (ncm);
2515*0Sstevel@tonic-gate }
2516*0Sstevel@tonic-gate 
2517*0Sstevel@tonic-gate /* used by dr_mem.c */
2518*0Sstevel@tonic-gate /* TODO: eliminate dr_boardlist */
2519*0Sstevel@tonic-gate dr_board_t *
2520*0Sstevel@tonic-gate dr_lookup_board(int board_num)
2521*0Sstevel@tonic-gate {
2522*0Sstevel@tonic-gate 	dr_board_t *bp;
2523*0Sstevel@tonic-gate 
2524*0Sstevel@tonic-gate 	ASSERT(board_num >= 0 && board_num < MAX_BOARDS);
2525*0Sstevel@tonic-gate 
2526*0Sstevel@tonic-gate 	bp = &dr_boardlist[board_num];
2527*0Sstevel@tonic-gate 	ASSERT(bp->b_num == board_num);
2528*0Sstevel@tonic-gate 
2529*0Sstevel@tonic-gate 	return (bp);
2530*0Sstevel@tonic-gate }
2531*0Sstevel@tonic-gate 
2532*0Sstevel@tonic-gate static dr_dev_unit_t *
2533*0Sstevel@tonic-gate dr_get_dev_unit(dr_board_t *bp, sbd_comp_type_t nt, int unit_num)
2534*0Sstevel@tonic-gate {
2535*0Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
2536*0Sstevel@tonic-gate 
2537*0Sstevel@tonic-gate 	dp = DR_GET_BOARD_DEVUNIT(bp, nt, unit_num);
2538*0Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_bp == bp);
2539*0Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_unum == unit_num);
2540*0Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_type == nt);
2541*0Sstevel@tonic-gate 
2542*0Sstevel@tonic-gate 	return (dp);
2543*0Sstevel@tonic-gate }
2544*0Sstevel@tonic-gate 
2545*0Sstevel@tonic-gate dr_cpu_unit_t *
2546*0Sstevel@tonic-gate dr_get_cpu_unit(dr_board_t *bp, int unit_num)
2547*0Sstevel@tonic-gate {
2548*0Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
2549*0Sstevel@tonic-gate 
2550*0Sstevel@tonic-gate 	ASSERT(unit_num >= 0 && unit_num < MAX_CPU_UNITS_PER_BOARD);
2551*0Sstevel@tonic-gate 
2552*0Sstevel@tonic-gate 	dp = dr_get_dev_unit(bp, SBD_COMP_CPU, unit_num);
2553*0Sstevel@tonic-gate 	return (&dp->du_cpu);
2554*0Sstevel@tonic-gate }
2555*0Sstevel@tonic-gate 
2556*0Sstevel@tonic-gate dr_mem_unit_t *
2557*0Sstevel@tonic-gate dr_get_mem_unit(dr_board_t *bp, int unit_num)
2558*0Sstevel@tonic-gate {
2559*0Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
2560*0Sstevel@tonic-gate 
2561*0Sstevel@tonic-gate 	ASSERT(unit_num >= 0 && unit_num < MAX_MEM_UNITS_PER_BOARD);
2562*0Sstevel@tonic-gate 
2563*0Sstevel@tonic-gate 	dp = dr_get_dev_unit(bp, SBD_COMP_MEM, unit_num);
2564*0Sstevel@tonic-gate 	return (&dp->du_mem);
2565*0Sstevel@tonic-gate }
2566*0Sstevel@tonic-gate 
2567*0Sstevel@tonic-gate dr_io_unit_t *
2568*0Sstevel@tonic-gate dr_get_io_unit(dr_board_t *bp, int unit_num)
2569*0Sstevel@tonic-gate {
2570*0Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
2571*0Sstevel@tonic-gate 
2572*0Sstevel@tonic-gate 	ASSERT(unit_num >= 0 && unit_num < MAX_IO_UNITS_PER_BOARD);
2573*0Sstevel@tonic-gate 
2574*0Sstevel@tonic-gate 	dp = dr_get_dev_unit(bp, SBD_COMP_IO, unit_num);
2575*0Sstevel@tonic-gate 	return (&dp->du_io);
2576*0Sstevel@tonic-gate }
2577*0Sstevel@tonic-gate 
2578*0Sstevel@tonic-gate dr_common_unit_t *
2579*0Sstevel@tonic-gate dr_get_common_unit(dr_board_t *bp, sbd_comp_type_t nt, int unum)
2580*0Sstevel@tonic-gate {
2581*0Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
2582*0Sstevel@tonic-gate 
2583*0Sstevel@tonic-gate 	dp = dr_get_dev_unit(bp, nt, unum);
2584*0Sstevel@tonic-gate 	return (&dp->du_common);
2585*0Sstevel@tonic-gate }
2586*0Sstevel@tonic-gate 
2587*0Sstevel@tonic-gate static dr_devset_t
2588*0Sstevel@tonic-gate dr_dev2devset(sbd_comp_id_t *cid)
2589*0Sstevel@tonic-gate {
2590*0Sstevel@tonic-gate 	static fn_t	f = "dr_dev2devset";
2591*0Sstevel@tonic-gate 
2592*0Sstevel@tonic-gate 	dr_devset_t	devset;
2593*0Sstevel@tonic-gate 	int		unit = cid->c_unit;
2594*0Sstevel@tonic-gate 
2595*0Sstevel@tonic-gate 	switch (cid->c_type) {
2596*0Sstevel@tonic-gate 		case SBD_COMP_NONE:
2597*0Sstevel@tonic-gate 			devset =  DEVSET(SBD_COMP_CPU, DEVSET_ANYUNIT);
2598*0Sstevel@tonic-gate 			devset |= DEVSET(SBD_COMP_MEM, DEVSET_ANYUNIT);
2599*0Sstevel@tonic-gate 			devset |= DEVSET(SBD_COMP_IO,  DEVSET_ANYUNIT);
2600*0Sstevel@tonic-gate 			PR_ALL("%s: COMP_NONE devset = 0x%x\n", f, devset);
2601*0Sstevel@tonic-gate 			break;
2602*0Sstevel@tonic-gate 
2603*0Sstevel@tonic-gate 		case SBD_COMP_CPU:
2604*0Sstevel@tonic-gate 			if ((unit > MAX_CPU_UNITS_PER_BOARD) || (unit < 0)) {
2605*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
2606*0Sstevel@tonic-gate 					"%s: invalid cpu unit# = %d",
2607*0Sstevel@tonic-gate 					f, unit);
2608*0Sstevel@tonic-gate 				devset = 0;
2609*0Sstevel@tonic-gate 			} else {
2610*0Sstevel@tonic-gate 				/*
2611*0Sstevel@tonic-gate 				 * Generate a devset that includes all the
2612*0Sstevel@tonic-gate 				 * cores of a CMP device. If this is not a
2613*0Sstevel@tonic-gate 				 * CMP, the extra cores will be eliminated
2614*0Sstevel@tonic-gate 				 * later since they are not present. This is
2615*0Sstevel@tonic-gate 				 * also true for CMP devices that do not have
2616*0Sstevel@tonic-gate 				 * all cores active.
2617*0Sstevel@tonic-gate 				 */
2618*0Sstevel@tonic-gate 				devset = DEVSET(SBD_COMP_CMP, unit);
2619*0Sstevel@tonic-gate 			}
2620*0Sstevel@tonic-gate 
2621*0Sstevel@tonic-gate 			PR_ALL("%s: CPU devset = 0x%x\n", f, devset);
2622*0Sstevel@tonic-gate 			break;
2623*0Sstevel@tonic-gate 
2624*0Sstevel@tonic-gate 		case SBD_COMP_MEM:
2625*0Sstevel@tonic-gate 			if (unit == SBD_NULL_UNIT) {
2626*0Sstevel@tonic-gate 				unit = 0;
2627*0Sstevel@tonic-gate 				cid->c_unit = 0;
2628*0Sstevel@tonic-gate 			}
2629*0Sstevel@tonic-gate 
2630*0Sstevel@tonic-gate 			if ((unit > MAX_MEM_UNITS_PER_BOARD) || (unit < 0)) {
2631*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
2632*0Sstevel@tonic-gate 					"%s: invalid mem unit# = %d",
2633*0Sstevel@tonic-gate 					f, unit);
2634*0Sstevel@tonic-gate 				devset = 0;
2635*0Sstevel@tonic-gate 			} else
2636*0Sstevel@tonic-gate 				devset = DEVSET(cid->c_type, unit);
2637*0Sstevel@tonic-gate 
2638*0Sstevel@tonic-gate 			PR_ALL("%s: MEM devset = 0x%x\n", f, devset);
2639*0Sstevel@tonic-gate 			break;
2640*0Sstevel@tonic-gate 
2641*0Sstevel@tonic-gate 		case SBD_COMP_IO:
2642*0Sstevel@tonic-gate 			if ((unit > MAX_IO_UNITS_PER_BOARD) || (unit < 0)) {
2643*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
2644*0Sstevel@tonic-gate 					"%s: invalid io unit# = %d",
2645*0Sstevel@tonic-gate 					f, unit);
2646*0Sstevel@tonic-gate 				devset = 0;
2647*0Sstevel@tonic-gate 			} else
2648*0Sstevel@tonic-gate 				devset = DEVSET(cid->c_type, unit);
2649*0Sstevel@tonic-gate 
2650*0Sstevel@tonic-gate 			PR_ALL("%s: IO devset = 0x%x\n", f, devset);
2651*0Sstevel@tonic-gate 			break;
2652*0Sstevel@tonic-gate 
2653*0Sstevel@tonic-gate 		default:
2654*0Sstevel@tonic-gate 		case SBD_COMP_UNKNOWN:
2655*0Sstevel@tonic-gate 			devset = 0;
2656*0Sstevel@tonic-gate 			break;
2657*0Sstevel@tonic-gate 	}
2658*0Sstevel@tonic-gate 
2659*0Sstevel@tonic-gate 	return (devset);
2660*0Sstevel@tonic-gate }
2661*0Sstevel@tonic-gate 
2662*0Sstevel@tonic-gate /*
2663*0Sstevel@tonic-gate  * Converts a dynamic attachment point name to a SBD_COMP_* type.
2664*0Sstevel@tonic-gate  * Returns SDB_COMP_UNKNOWN if name is not recognized.
2665*0Sstevel@tonic-gate  */
2666*0Sstevel@tonic-gate static int
2667*0Sstevel@tonic-gate dr_dev_type_to_nt(char *type)
2668*0Sstevel@tonic-gate {
2669*0Sstevel@tonic-gate 	int i;
2670*0Sstevel@tonic-gate 
2671*0Sstevel@tonic-gate 	for (i = 0; dr_devattr[i].s_nodetype != SBD_COMP_UNKNOWN; i++)
2672*0Sstevel@tonic-gate 		if (strcmp(dr_devattr[i].s_devtype, type) == 0)
2673*0Sstevel@tonic-gate 			break;
2674*0Sstevel@tonic-gate 
2675*0Sstevel@tonic-gate 	return (dr_devattr[i].s_nodetype);
2676*0Sstevel@tonic-gate }
2677*0Sstevel@tonic-gate 
2678*0Sstevel@tonic-gate /*
2679*0Sstevel@tonic-gate  * Converts a SBD_COMP_* type to a dynamic attachment point name.
2680*0Sstevel@tonic-gate  * Return NULL if SBD_COMP_ type is not recognized.
2681*0Sstevel@tonic-gate  */
2682*0Sstevel@tonic-gate char *
2683*0Sstevel@tonic-gate dr_nt_to_dev_type(int nt)
2684*0Sstevel@tonic-gate {
2685*0Sstevel@tonic-gate 	int i;
2686*0Sstevel@tonic-gate 
2687*0Sstevel@tonic-gate 	for (i = 0; dr_devattr[i].s_nodetype != SBD_COMP_UNKNOWN; i++)
2688*0Sstevel@tonic-gate 		if (dr_devattr[i].s_nodetype == nt)
2689*0Sstevel@tonic-gate 			break;
2690*0Sstevel@tonic-gate 
2691*0Sstevel@tonic-gate 	return (dr_devattr[i].s_devtype);
2692*0Sstevel@tonic-gate }
2693*0Sstevel@tonic-gate 
2694*0Sstevel@tonic-gate 
2695*0Sstevel@tonic-gate /*
2696*0Sstevel@tonic-gate  * State transition policy is that if there is some component for which
2697*0Sstevel@tonic-gate  * the state transition is valid, then let it through. The exception is
2698*0Sstevel@tonic-gate  * SBD_CMD_DISCONNECT. On disconnect, the state transition must be valid
2699*0Sstevel@tonic-gate  * for ALL components.
2700*0Sstevel@tonic-gate  * Returns the state that is in error, if any.
2701*0Sstevel@tonic-gate  */
2702*0Sstevel@tonic-gate static int
2703*0Sstevel@tonic-gate dr_check_transition(dr_board_t *bp, dr_devset_t *devsetp,
2704*0Sstevel@tonic-gate 			struct dr_state_trans *transp, int cmd)
2705*0Sstevel@tonic-gate {
2706*0Sstevel@tonic-gate 	int			s, ut;
2707*0Sstevel@tonic-gate 	int			state_err = 0;
2708*0Sstevel@tonic-gate 	dr_devset_t		devset;
2709*0Sstevel@tonic-gate 	dr_common_unit_t	*cp;
2710*0Sstevel@tonic-gate 	static fn_t		f = "dr_check_transition";
2711*0Sstevel@tonic-gate 
2712*0Sstevel@tonic-gate 	devset = *devsetp;
2713*0Sstevel@tonic-gate 
2714*0Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) {
2715*0Sstevel@tonic-gate 		for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) {
2716*0Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_CPU, ut) == 0)
2717*0Sstevel@tonic-gate 				continue;
2718*0Sstevel@tonic-gate 
2719*0Sstevel@tonic-gate 			cp = dr_get_common_unit(bp, SBD_COMP_CPU, ut);
2720*0Sstevel@tonic-gate 			s = (int)cp->sbdev_state;
2721*0Sstevel@tonic-gate 			if (!DR_DEV_IS_PRESENT(cp)) {
2722*0Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_CPU, ut);
2723*0Sstevel@tonic-gate 			} else {
2724*0Sstevel@tonic-gate 				if (transp->x_op[s].x_rv) {
2725*0Sstevel@tonic-gate 					if (!state_err)
2726*0Sstevel@tonic-gate 						state_err = s;
2727*0Sstevel@tonic-gate 					DEVSET_DEL(devset, SBD_COMP_CPU, ut);
2728*0Sstevel@tonic-gate 				}
2729*0Sstevel@tonic-gate 			}
2730*0Sstevel@tonic-gate 		}
2731*0Sstevel@tonic-gate 	}
2732*0Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) {
2733*0Sstevel@tonic-gate 		for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) {
2734*0Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_MEM, ut) == 0)
2735*0Sstevel@tonic-gate 				continue;
2736*0Sstevel@tonic-gate 
2737*0Sstevel@tonic-gate 			cp = dr_get_common_unit(bp, SBD_COMP_MEM, ut);
2738*0Sstevel@tonic-gate 			s = (int)cp->sbdev_state;
2739*0Sstevel@tonic-gate 			if (!DR_DEV_IS_PRESENT(cp)) {
2740*0Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_MEM, ut);
2741*0Sstevel@tonic-gate 			} else {
2742*0Sstevel@tonic-gate 				if (transp->x_op[s].x_rv) {
2743*0Sstevel@tonic-gate 					if (!state_err)
2744*0Sstevel@tonic-gate 						state_err = s;
2745*0Sstevel@tonic-gate 					DEVSET_DEL(devset, SBD_COMP_MEM, ut);
2746*0Sstevel@tonic-gate 				}
2747*0Sstevel@tonic-gate 			}
2748*0Sstevel@tonic-gate 		}
2749*0Sstevel@tonic-gate 	}
2750*0Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) {
2751*0Sstevel@tonic-gate 		for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) {
2752*0Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_IO, ut) == 0)
2753*0Sstevel@tonic-gate 				continue;
2754*0Sstevel@tonic-gate 
2755*0Sstevel@tonic-gate 			cp = dr_get_common_unit(bp, SBD_COMP_IO, ut);
2756*0Sstevel@tonic-gate 			s = (int)cp->sbdev_state;
2757*0Sstevel@tonic-gate 			if (!DR_DEV_IS_PRESENT(cp)) {
2758*0Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_IO, ut);
2759*0Sstevel@tonic-gate 			} else {
2760*0Sstevel@tonic-gate 				if (transp->x_op[s].x_rv) {
2761*0Sstevel@tonic-gate 					if (!state_err)
2762*0Sstevel@tonic-gate 						state_err = s;
2763*0Sstevel@tonic-gate 					DEVSET_DEL(devset, SBD_COMP_IO, ut);
2764*0Sstevel@tonic-gate 				}
2765*0Sstevel@tonic-gate 			}
2766*0Sstevel@tonic-gate 		}
2767*0Sstevel@tonic-gate 	}
2768*0Sstevel@tonic-gate 
2769*0Sstevel@tonic-gate 	PR_ALL("%s: requested devset = 0x%x, final devset = 0x%x\n",
2770*0Sstevel@tonic-gate 		f, (uint_t)*devsetp, (uint_t)devset);
2771*0Sstevel@tonic-gate 
2772*0Sstevel@tonic-gate 	*devsetp = devset;
2773*0Sstevel@tonic-gate 	/*
2774*0Sstevel@tonic-gate 	 * If there are some remaining components for which
2775*0Sstevel@tonic-gate 	 * this state transition is valid, then allow them
2776*0Sstevel@tonic-gate 	 * through, otherwise if none are left then return
2777*0Sstevel@tonic-gate 	 * the state error. The exception is SBD_CMD_DISCONNECT.
2778*0Sstevel@tonic-gate 	 * On disconnect, the state transition must be valid for ALL
2779*0Sstevel@tonic-gate 	 * components.
2780*0Sstevel@tonic-gate 	 */
2781*0Sstevel@tonic-gate 	if (cmd == SBD_CMD_DISCONNECT)
2782*0Sstevel@tonic-gate 		return (state_err);
2783*0Sstevel@tonic-gate 	return (devset ? 0 : state_err);
2784*0Sstevel@tonic-gate }
2785*0Sstevel@tonic-gate 
2786*0Sstevel@tonic-gate void
2787*0Sstevel@tonic-gate dr_device_transition(dr_common_unit_t *cp, dr_state_t st)
2788*0Sstevel@tonic-gate {
2789*0Sstevel@tonic-gate 	PR_STATE("%s STATE %s(%d) -> %s(%d)\n",
2790*0Sstevel@tonic-gate 		cp->sbdev_path,
2791*0Sstevel@tonic-gate 		state_str[cp->sbdev_state], cp->sbdev_state,
2792*0Sstevel@tonic-gate 		state_str[st], st);
2793*0Sstevel@tonic-gate 
2794*0Sstevel@tonic-gate 	cp->sbdev_state = st;
2795*0Sstevel@tonic-gate 	if (st == DR_STATE_CONFIGURED) {
2796*0Sstevel@tonic-gate 		cp->sbdev_ostate = SBD_STAT_CONFIGURED;
2797*0Sstevel@tonic-gate 		if (cp->sbdev_bp->b_ostate != SBD_STAT_CONFIGURED) {
2798*0Sstevel@tonic-gate 			cp->sbdev_bp->b_ostate = SBD_STAT_CONFIGURED;
2799*0Sstevel@tonic-gate 			(void) drv_getparm(TIME,
2800*0Sstevel@tonic-gate 				(void *) &cp->sbdev_bp->b_time);
2801*0Sstevel@tonic-gate 		}
2802*0Sstevel@tonic-gate 	} else
2803*0Sstevel@tonic-gate 		cp->sbdev_ostate = SBD_STAT_UNCONFIGURED;
2804*0Sstevel@tonic-gate 
2805*0Sstevel@tonic-gate 	(void) drv_getparm(TIME, (void *) &cp->sbdev_time);
2806*0Sstevel@tonic-gate }
2807*0Sstevel@tonic-gate 
2808*0Sstevel@tonic-gate static void
2809*0Sstevel@tonic-gate dr_board_transition(dr_board_t *bp, dr_state_t st)
2810*0Sstevel@tonic-gate {
2811*0Sstevel@tonic-gate 	PR_STATE("BOARD %d STATE: %s(%d) -> %s(%d)\n",
2812*0Sstevel@tonic-gate 		bp->b_num,
2813*0Sstevel@tonic-gate 		state_str[bp->b_state], bp->b_state,
2814*0Sstevel@tonic-gate 		state_str[st], st);
2815*0Sstevel@tonic-gate 
2816*0Sstevel@tonic-gate 	bp->b_state = st;
2817*0Sstevel@tonic-gate }
2818*0Sstevel@tonic-gate 
2819*0Sstevel@tonic-gate void
2820*0Sstevel@tonic-gate dr_op_err(int ce, dr_handle_t *hp, int code, char *fmt, ...)
2821*0Sstevel@tonic-gate {
2822*0Sstevel@tonic-gate 	sbd_error_t	*err;
2823*0Sstevel@tonic-gate 	va_list		args;
2824*0Sstevel@tonic-gate 
2825*0Sstevel@tonic-gate 	va_start(args, fmt);
2826*0Sstevel@tonic-gate 	err = drerr_new_v(code, fmt, args);
2827*0Sstevel@tonic-gate 	va_end(args);
2828*0Sstevel@tonic-gate 
2829*0Sstevel@tonic-gate 	if (ce != CE_IGNORE)
2830*0Sstevel@tonic-gate 		sbd_err_log(err, ce);
2831*0Sstevel@tonic-gate 
2832*0Sstevel@tonic-gate 	DRERR_SET_C(&hp->h_err, &err);
2833*0Sstevel@tonic-gate }
2834*0Sstevel@tonic-gate 
2835*0Sstevel@tonic-gate void
2836*0Sstevel@tonic-gate dr_dev_err(int ce, dr_common_unit_t *cp, int code)
2837*0Sstevel@tonic-gate {
2838*0Sstevel@tonic-gate 	sbd_error_t	*err;
2839*0Sstevel@tonic-gate 
2840*0Sstevel@tonic-gate 	err = drerr_new(0, code, cp->sbdev_path, NULL);
2841*0Sstevel@tonic-gate 
2842*0Sstevel@tonic-gate 	if (ce != CE_IGNORE)
2843*0Sstevel@tonic-gate 		sbd_err_log(err, ce);
2844*0Sstevel@tonic-gate 
2845*0Sstevel@tonic-gate 	DRERR_SET_C(&cp->sbdev_error, &err);
2846*0Sstevel@tonic-gate }
2847*0Sstevel@tonic-gate 
2848*0Sstevel@tonic-gate /*
2849*0Sstevel@tonic-gate  * A callback routine.  Called from the drmach layer as a result of
2850*0Sstevel@tonic-gate  * call to drmach_board_find_devices from dr_init_devlists.
2851*0Sstevel@tonic-gate  */
2852*0Sstevel@tonic-gate static sbd_error_t *
2853*0Sstevel@tonic-gate dr_dev_found(void *data, const char *name, int unum, drmachid_t id)
2854*0Sstevel@tonic-gate {
2855*0Sstevel@tonic-gate 	dr_board_t	*bp = data;
2856*0Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
2857*0Sstevel@tonic-gate 	int		 nt;
2858*0Sstevel@tonic-gate 	static fn_t	f = "dr_dev_found";
2859*0Sstevel@tonic-gate 
2860*0Sstevel@tonic-gate 	PR_ALL("%s (board = %d, name = %s, unum = %d, id = %p)...\n",
2861*0Sstevel@tonic-gate 		f, bp->b_num, name, unum, id);
2862*0Sstevel@tonic-gate 
2863*0Sstevel@tonic-gate 	nt = dr_dev_type_to_nt((char *)name);
2864*0Sstevel@tonic-gate 	if (nt == SBD_COMP_UNKNOWN) {
2865*0Sstevel@tonic-gate 		/*
2866*0Sstevel@tonic-gate 		 * this should not happen.  When it does, it indicates
2867*0Sstevel@tonic-gate 		 * a missmatch in devices supported by the drmach layer
2868*0Sstevel@tonic-gate 		 * vs devices supported by this layer.
2869*0Sstevel@tonic-gate 		 */
2870*0Sstevel@tonic-gate 		return (DR_INTERNAL_ERROR());
2871*0Sstevel@tonic-gate 	}
2872*0Sstevel@tonic-gate 
2873*0Sstevel@tonic-gate 	dp = DR_GET_BOARD_DEVUNIT(bp, nt, unum);
2874*0Sstevel@tonic-gate 
2875*0Sstevel@tonic-gate 	/* sanity check */
2876*0Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_bp == bp);
2877*0Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_unum == unum);
2878*0Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_type == nt);
2879*0Sstevel@tonic-gate 
2880*0Sstevel@tonic-gate 	/* render dynamic attachment point path of this unit */
2881*0Sstevel@tonic-gate 	(void) snprintf(dp->du_common.sbdev_path,
2882*0Sstevel@tonic-gate 			sizeof (dp->du_common.sbdev_path),
2883*0Sstevel@tonic-gate 			(nt == SBD_COMP_MEM ? "%s::%s" : "%s::%s%d"),
2884*0Sstevel@tonic-gate 			bp->b_path, name, DR_UNUM2SBD_UNUM(unum));
2885*0Sstevel@tonic-gate 
2886*0Sstevel@tonic-gate 	dp->du_common.sbdev_id = id;
2887*0Sstevel@tonic-gate 	DR_DEV_SET_PRESENT(&dp->du_common);
2888*0Sstevel@tonic-gate 
2889*0Sstevel@tonic-gate 	bp->b_ndev++;
2890*0Sstevel@tonic-gate 
2891*0Sstevel@tonic-gate 	return (NULL);
2892*0Sstevel@tonic-gate }
2893*0Sstevel@tonic-gate 
2894*0Sstevel@tonic-gate static sbd_error_t *
2895*0Sstevel@tonic-gate dr_init_devlists(dr_board_t *bp)
2896*0Sstevel@tonic-gate {
2897*0Sstevel@tonic-gate 	int		i;
2898*0Sstevel@tonic-gate 	sbd_error_t	*err;
2899*0Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
2900*0Sstevel@tonic-gate 	static fn_t	f = "dr_init_devlists";
2901*0Sstevel@tonic-gate 
2902*0Sstevel@tonic-gate 	PR_ALL("%s (%s)...\n", f, bp->b_path);
2903*0Sstevel@tonic-gate 
2904*0Sstevel@tonic-gate 	/* sanity check */
2905*0Sstevel@tonic-gate 	ASSERT(bp->b_ndev == 0);
2906*0Sstevel@tonic-gate 
2907*0Sstevel@tonic-gate 	DR_DEVS_DISCONNECT(bp, (uint_t)-1);
2908*0Sstevel@tonic-gate 
2909*0Sstevel@tonic-gate 	/*
2910*0Sstevel@tonic-gate 	 * This routine builds the board's devlist and initializes
2911*0Sstevel@tonic-gate 	 * the common portion of the unit data structures.
2912*0Sstevel@tonic-gate 	 * Note: because the common portion is considered
2913*0Sstevel@tonic-gate 	 * uninitialized, the dr_get_*_unit() routines can not
2914*0Sstevel@tonic-gate 	 * be used.
2915*0Sstevel@tonic-gate 	 */
2916*0Sstevel@tonic-gate 
2917*0Sstevel@tonic-gate 	/*
2918*0Sstevel@tonic-gate 	 * Clear out old entries, if any.
2919*0Sstevel@tonic-gate 	 */
2920*0Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
2921*0Sstevel@tonic-gate 		dp = DR_GET_BOARD_DEVUNIT(bp, SBD_COMP_CPU, i);
2922*0Sstevel@tonic-gate 
2923*0Sstevel@tonic-gate 		bzero(dp, sizeof (*dp));
2924*0Sstevel@tonic-gate 		dp->du_common.sbdev_bp = bp;
2925*0Sstevel@tonic-gate 		dp->du_common.sbdev_unum = i;
2926*0Sstevel@tonic-gate 		dp->du_common.sbdev_type = SBD_COMP_CPU;
2927*0Sstevel@tonic-gate 	}
2928*0Sstevel@tonic-gate 
2929*0Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
2930*0Sstevel@tonic-gate 		dp = DR_GET_BOARD_DEVUNIT(bp, SBD_COMP_MEM, i);
2931*0Sstevel@tonic-gate 
2932*0Sstevel@tonic-gate 		bzero(dp, sizeof (*dp));
2933*0Sstevel@tonic-gate 		dp->du_common.sbdev_bp = bp;
2934*0Sstevel@tonic-gate 		dp->du_common.sbdev_unum = i;
2935*0Sstevel@tonic-gate 		dp->du_common.sbdev_type = SBD_COMP_MEM;
2936*0Sstevel@tonic-gate 	}
2937*0Sstevel@tonic-gate 
2938*0Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
2939*0Sstevel@tonic-gate 		dp = DR_GET_BOARD_DEVUNIT(bp, SBD_COMP_IO, i);
2940*0Sstevel@tonic-gate 
2941*0Sstevel@tonic-gate 		bzero(dp, sizeof (*dp));
2942*0Sstevel@tonic-gate 		dp->du_common.sbdev_bp = bp;
2943*0Sstevel@tonic-gate 		dp->du_common.sbdev_unum = i;
2944*0Sstevel@tonic-gate 		dp->du_common.sbdev_type = SBD_COMP_IO;
2945*0Sstevel@tonic-gate 	}
2946*0Sstevel@tonic-gate 
2947*0Sstevel@tonic-gate 	err = NULL;
2948*0Sstevel@tonic-gate 	if (bp->b_id) {
2949*0Sstevel@tonic-gate 		/* find devices on this board */
2950*0Sstevel@tonic-gate 		err = drmach_board_find_devices(
2951*0Sstevel@tonic-gate 			bp->b_id, bp, dr_dev_found);
2952*0Sstevel@tonic-gate 	}
2953*0Sstevel@tonic-gate 
2954*0Sstevel@tonic-gate 	return (err);
2955*0Sstevel@tonic-gate }
2956*0Sstevel@tonic-gate 
2957*0Sstevel@tonic-gate /*
2958*0Sstevel@tonic-gate  * Return the unit number of the respective drmachid if
2959*0Sstevel@tonic-gate  * it's found to be attached.
2960*0Sstevel@tonic-gate  */
2961*0Sstevel@tonic-gate static int
2962*0Sstevel@tonic-gate dr_check_unit_attached(dr_common_unit_t *cp)
2963*0Sstevel@tonic-gate {
2964*0Sstevel@tonic-gate 	int		rv = 0;
2965*0Sstevel@tonic-gate 	processorid_t	cpuid;
2966*0Sstevel@tonic-gate 	uint64_t	basepa, endpa;
2967*0Sstevel@tonic-gate 	struct memlist	*ml;
2968*0Sstevel@tonic-gate 	extern struct memlist	*phys_install;
2969*0Sstevel@tonic-gate 	sbd_error_t	*err;
2970*0Sstevel@tonic-gate 	int		yes;
2971*0Sstevel@tonic-gate 	static fn_t	f = "dr_check_unit_attached";
2972*0Sstevel@tonic-gate 
2973*0Sstevel@tonic-gate 	switch (cp->sbdev_type) {
2974*0Sstevel@tonic-gate 	case SBD_COMP_CPU:
2975*0Sstevel@tonic-gate 		err = drmach_cpu_get_id(cp->sbdev_id, &cpuid);
2976*0Sstevel@tonic-gate 		if (err) {
2977*0Sstevel@tonic-gate 			DRERR_SET_C(&cp->sbdev_error, &err);
2978*0Sstevel@tonic-gate 			rv = -1;
2979*0Sstevel@tonic-gate 			break;
2980*0Sstevel@tonic-gate 		}
2981*0Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
2982*0Sstevel@tonic-gate 		if (cpu_get(cpuid) == NULL)
2983*0Sstevel@tonic-gate 			rv = -1;
2984*0Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
2985*0Sstevel@tonic-gate 		break;
2986*0Sstevel@tonic-gate 
2987*0Sstevel@tonic-gate 	case SBD_COMP_MEM:
2988*0Sstevel@tonic-gate 		err = drmach_mem_get_base_physaddr(cp->sbdev_id, &basepa);
2989*0Sstevel@tonic-gate 		if (err) {
2990*0Sstevel@tonic-gate 			DRERR_SET_C(&cp->sbdev_error, &err);
2991*0Sstevel@tonic-gate 			rv = -1;
2992*0Sstevel@tonic-gate 			break;
2993*0Sstevel@tonic-gate 		}
2994*0Sstevel@tonic-gate 
2995*0Sstevel@tonic-gate 		/*
2996*0Sstevel@tonic-gate 		 * basepa may not be on a alignment boundary, make it so.
2997*0Sstevel@tonic-gate 		 */
2998*0Sstevel@tonic-gate 		err = drmach_mem_get_slice_size(cp->sbdev_id, &endpa);
2999*0Sstevel@tonic-gate 		if (err) {
3000*0Sstevel@tonic-gate 			DRERR_SET_C(&cp->sbdev_error, &err);
3001*0Sstevel@tonic-gate 			rv = -1;
3002*0Sstevel@tonic-gate 			break;
3003*0Sstevel@tonic-gate 		}
3004*0Sstevel@tonic-gate 
3005*0Sstevel@tonic-gate 		basepa &= ~(endpa - 1);
3006*0Sstevel@tonic-gate 		endpa += basepa;
3007*0Sstevel@tonic-gate 
3008*0Sstevel@tonic-gate 		/*
3009*0Sstevel@tonic-gate 		 * Check if base address is in phys_install.
3010*0Sstevel@tonic-gate 		 */
3011*0Sstevel@tonic-gate 		memlist_read_lock();
3012*0Sstevel@tonic-gate 		for (ml = phys_install; ml; ml = ml->next)
3013*0Sstevel@tonic-gate 			if ((endpa <= ml->address) ||
3014*0Sstevel@tonic-gate 					(basepa >= (ml->address + ml->size)))
3015*0Sstevel@tonic-gate 				continue;
3016*0Sstevel@tonic-gate 			else
3017*0Sstevel@tonic-gate 				break;
3018*0Sstevel@tonic-gate 		memlist_read_unlock();
3019*0Sstevel@tonic-gate 		if (ml == NULL)
3020*0Sstevel@tonic-gate 			rv = -1;
3021*0Sstevel@tonic-gate 		break;
3022*0Sstevel@tonic-gate 
3023*0Sstevel@tonic-gate 	case SBD_COMP_IO:
3024*0Sstevel@tonic-gate 		err = drmach_io_is_attached(cp->sbdev_id, &yes);
3025*0Sstevel@tonic-gate 		if (err) {
3026*0Sstevel@tonic-gate 			DRERR_SET_C(&cp->sbdev_error, &err);
3027*0Sstevel@tonic-gate 			rv = -1;
3028*0Sstevel@tonic-gate 			break;
3029*0Sstevel@tonic-gate 		} else if (!yes)
3030*0Sstevel@tonic-gate 			rv = -1;
3031*0Sstevel@tonic-gate 		break;
3032*0Sstevel@tonic-gate 
3033*0Sstevel@tonic-gate 	default:
3034*0Sstevel@tonic-gate 		PR_ALL("%s: unexpected nodetype(%d) for id 0x%x\n",
3035*0Sstevel@tonic-gate 			f, cp->sbdev_type, cp->sbdev_id);
3036*0Sstevel@tonic-gate 		rv = -1;
3037*0Sstevel@tonic-gate 		break;
3038*0Sstevel@tonic-gate 	}
3039*0Sstevel@tonic-gate 
3040*0Sstevel@tonic-gate 	return (rv);
3041*0Sstevel@tonic-gate }
3042*0Sstevel@tonic-gate 
3043*0Sstevel@tonic-gate /*
3044*0Sstevel@tonic-gate  * See if drmach recognizes the passthru command.  DRMACH expects the
3045*0Sstevel@tonic-gate  * id to identify the thing to which the command is being applied.  Using
3046*0Sstevel@tonic-gate  * nonsense SBD terms, that information has been perversely encoded in the
3047*0Sstevel@tonic-gate  * c_id member of the sbd_cmd_t structure.  This logic reads those tea
3048*0Sstevel@tonic-gate  * leaves, finds the associated drmach id, then calls drmach to process
3049*0Sstevel@tonic-gate  * the passthru command.
3050*0Sstevel@tonic-gate  */
3051*0Sstevel@tonic-gate static int
3052*0Sstevel@tonic-gate dr_pt_try_drmach(dr_handle_t *hp)
3053*0Sstevel@tonic-gate {
3054*0Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
3055*0Sstevel@tonic-gate 	sbd_comp_id_t	*comp_id = &hp->h_sbdcmd.cmd_cm.c_id;
3056*0Sstevel@tonic-gate 	drmachid_t	 id;
3057*0Sstevel@tonic-gate 
3058*0Sstevel@tonic-gate 	if (comp_id->c_type == SBD_COMP_NONE) {
3059*0Sstevel@tonic-gate 		id = bp->b_id;
3060*0Sstevel@tonic-gate 	} else {
3061*0Sstevel@tonic-gate 		sbd_comp_type_t	 nt;
3062*0Sstevel@tonic-gate 
3063*0Sstevel@tonic-gate 		nt = dr_dev_type_to_nt(comp_id->c_name);
3064*0Sstevel@tonic-gate 		if (nt == SBD_COMP_UNKNOWN) {
3065*0Sstevel@tonic-gate 			dr_op_err(CE_IGNORE, hp, ESBD_INVAL, comp_id->c_name);
3066*0Sstevel@tonic-gate 			id = 0;
3067*0Sstevel@tonic-gate 		} else {
3068*0Sstevel@tonic-gate 			/* pt command applied to dynamic attachment point */
3069*0Sstevel@tonic-gate 			dr_common_unit_t *cp;
3070*0Sstevel@tonic-gate 			cp = dr_get_common_unit(bp, nt, comp_id->c_unit);
3071*0Sstevel@tonic-gate 			id = cp->sbdev_id;
3072*0Sstevel@tonic-gate 		}
3073*0Sstevel@tonic-gate 	}
3074*0Sstevel@tonic-gate 
3075*0Sstevel@tonic-gate 	if (hp->h_err == NULL)
3076*0Sstevel@tonic-gate 		hp->h_err = drmach_passthru(id, &hp->h_opts);
3077*0Sstevel@tonic-gate 
3078*0Sstevel@tonic-gate 	return (hp->h_err == NULL ? 0 : -1);
3079*0Sstevel@tonic-gate }
3080*0Sstevel@tonic-gate 
3081*0Sstevel@tonic-gate static int
3082*0Sstevel@tonic-gate dr_pt_ioctl(dr_handle_t *hp)
3083*0Sstevel@tonic-gate {
3084*0Sstevel@tonic-gate 	int		cmd, rv, len;
3085*0Sstevel@tonic-gate 	int32_t		sz;
3086*0Sstevel@tonic-gate 	int		found;
3087*0Sstevel@tonic-gate 	char		*copts;
3088*0Sstevel@tonic-gate 	static fn_t	f = "dr_pt_ioctl";
3089*0Sstevel@tonic-gate 
3090*0Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
3091*0Sstevel@tonic-gate 
3092*0Sstevel@tonic-gate 	sz = hp->h_opts.size;
3093*0Sstevel@tonic-gate 	copts = hp->h_opts.copts;
3094*0Sstevel@tonic-gate 
3095*0Sstevel@tonic-gate 	if (sz == 0 || copts == (char *)NULL) {
3096*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: invalid passthru args", f);
3097*0Sstevel@tonic-gate 		return (EINVAL);
3098*0Sstevel@tonic-gate 	}
3099*0Sstevel@tonic-gate 
3100*0Sstevel@tonic-gate 	found = 0;
3101*0Sstevel@tonic-gate 	for (cmd = 0; cmd < (sizeof (pt_arr) / sizeof (pt_arr[0])); cmd++) {
3102*0Sstevel@tonic-gate 		len = strlen(pt_arr[cmd].pt_name);
3103*0Sstevel@tonic-gate 		found = (strncmp(pt_arr[cmd].pt_name, copts, len) == 0);
3104*0Sstevel@tonic-gate 		if (found)
3105*0Sstevel@tonic-gate 			break;
3106*0Sstevel@tonic-gate 	}
3107*0Sstevel@tonic-gate 
3108*0Sstevel@tonic-gate 	if (found)
3109*0Sstevel@tonic-gate 		rv = (*pt_arr[cmd].pt_func)(hp);
3110*0Sstevel@tonic-gate 	else
3111*0Sstevel@tonic-gate 		rv = dr_pt_try_drmach(hp);
3112*0Sstevel@tonic-gate 
3113*0Sstevel@tonic-gate 	return (rv);
3114*0Sstevel@tonic-gate }
3115*0Sstevel@tonic-gate 
3116*0Sstevel@tonic-gate /*
3117*0Sstevel@tonic-gate  * Called at driver load time to determine the state and condition
3118*0Sstevel@tonic-gate  * of an existing board in the system.
3119*0Sstevel@tonic-gate  */
3120*0Sstevel@tonic-gate static void
3121*0Sstevel@tonic-gate dr_board_discovery(dr_board_t *bp)
3122*0Sstevel@tonic-gate {
3123*0Sstevel@tonic-gate 	int			i;
3124*0Sstevel@tonic-gate 	dr_devset_t		devs_lost, devs_attached = 0;
3125*0Sstevel@tonic-gate 	dr_cpu_unit_t		*cp;
3126*0Sstevel@tonic-gate 	dr_mem_unit_t		*mp;
3127*0Sstevel@tonic-gate 	dr_io_unit_t		*ip;
3128*0Sstevel@tonic-gate 	static fn_t		f = "dr_board_discovery";
3129*0Sstevel@tonic-gate 
3130*0Sstevel@tonic-gate 	if (DR_DEVS_PRESENT(bp) == 0) {
3131*0Sstevel@tonic-gate 		PR_ALL("%s: board %d has no devices present\n",
3132*0Sstevel@tonic-gate 			f, bp->b_num);
3133*0Sstevel@tonic-gate 		return;
3134*0Sstevel@tonic-gate 	}
3135*0Sstevel@tonic-gate 
3136*0Sstevel@tonic-gate 	/*
3137*0Sstevel@tonic-gate 	 * Check for existence of cpus.
3138*0Sstevel@tonic-gate 	 */
3139*0Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
3140*0Sstevel@tonic-gate 		cp = dr_get_cpu_unit(bp, i);
3141*0Sstevel@tonic-gate 
3142*0Sstevel@tonic-gate 		if (!DR_DEV_IS_PRESENT(&cp->sbc_cm))
3143*0Sstevel@tonic-gate 			continue;
3144*0Sstevel@tonic-gate 
3145*0Sstevel@tonic-gate 		if (dr_check_unit_attached(&cp->sbc_cm) >= 0) {
3146*0Sstevel@tonic-gate 			DR_DEV_SET_ATTACHED(&cp->sbc_cm);
3147*0Sstevel@tonic-gate 			DEVSET_ADD(devs_attached, SBD_COMP_CPU, i);
3148*0Sstevel@tonic-gate 			PR_ALL("%s: board %d, cpu-unit %d - attached\n",
3149*0Sstevel@tonic-gate 				f, bp->b_num, i);
3150*0Sstevel@tonic-gate 		}
3151*0Sstevel@tonic-gate 		dr_init_cpu_unit(cp);
3152*0Sstevel@tonic-gate 	}
3153*0Sstevel@tonic-gate 
3154*0Sstevel@tonic-gate 	/*
3155*0Sstevel@tonic-gate 	 * Check for existence of memory.
3156*0Sstevel@tonic-gate 	 */
3157*0Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
3158*0Sstevel@tonic-gate 		mp = dr_get_mem_unit(bp, i);
3159*0Sstevel@tonic-gate 
3160*0Sstevel@tonic-gate 		if (!DR_DEV_IS_PRESENT(&mp->sbm_cm))
3161*0Sstevel@tonic-gate 			continue;
3162*0Sstevel@tonic-gate 
3163*0Sstevel@tonic-gate 		if (dr_check_unit_attached(&mp->sbm_cm) >= 0) {
3164*0Sstevel@tonic-gate 			DR_DEV_SET_ATTACHED(&mp->sbm_cm);
3165*0Sstevel@tonic-gate 			DEVSET_ADD(devs_attached, SBD_COMP_MEM, i);
3166*0Sstevel@tonic-gate 			PR_ALL("%s: board %d, mem-unit %d - attached\n",
3167*0Sstevel@tonic-gate 				f, bp->b_num, i);
3168*0Sstevel@tonic-gate 		}
3169*0Sstevel@tonic-gate 		dr_init_mem_unit(mp);
3170*0Sstevel@tonic-gate 	}
3171*0Sstevel@tonic-gate 
3172*0Sstevel@tonic-gate 	/*
3173*0Sstevel@tonic-gate 	 * Check for i/o state.
3174*0Sstevel@tonic-gate 	 */
3175*0Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
3176*0Sstevel@tonic-gate 		ip = dr_get_io_unit(bp, i);
3177*0Sstevel@tonic-gate 
3178*0Sstevel@tonic-gate 		if (!DR_DEV_IS_PRESENT(&ip->sbi_cm))
3179*0Sstevel@tonic-gate 			continue;
3180*0Sstevel@tonic-gate 
3181*0Sstevel@tonic-gate 		if (dr_check_unit_attached(&ip->sbi_cm) >= 0) {
3182*0Sstevel@tonic-gate 			/*
3183*0Sstevel@tonic-gate 			 * Found it!
3184*0Sstevel@tonic-gate 			 */
3185*0Sstevel@tonic-gate 			DR_DEV_SET_ATTACHED(&ip->sbi_cm);
3186*0Sstevel@tonic-gate 			DEVSET_ADD(devs_attached, SBD_COMP_IO, i);
3187*0Sstevel@tonic-gate 			PR_ALL("%s: board %d, io-unit %d - attached\n",
3188*0Sstevel@tonic-gate 				f, bp->b_num, i);
3189*0Sstevel@tonic-gate 		}
3190*0Sstevel@tonic-gate 		dr_init_io_unit(ip);
3191*0Sstevel@tonic-gate 	}
3192*0Sstevel@tonic-gate 
3193*0Sstevel@tonic-gate 	DR_DEVS_CONFIGURE(bp, devs_attached);
3194*0Sstevel@tonic-gate 	if (devs_attached && ((devs_lost = DR_DEVS_UNATTACHED(bp)) != 0)) {
3195*0Sstevel@tonic-gate 		int		ut;
3196*0Sstevel@tonic-gate 		/*
3197*0Sstevel@tonic-gate 		 * It is not legal on board discovery to have a
3198*0Sstevel@tonic-gate 		 * board that is only partially attached.  A board
3199*0Sstevel@tonic-gate 		 * is either all attached or all connected.  If a
3200*0Sstevel@tonic-gate 		 * board has at least one attached device, then
3201*0Sstevel@tonic-gate 		 * the the remaining devices, if any, must have
3202*0Sstevel@tonic-gate 		 * been lost or disconnected.  These devices can
3203*0Sstevel@tonic-gate 		 * only be recovered by a full attach from scratch.
3204*0Sstevel@tonic-gate 		 * Note that devices previously in the unreferenced
3205*0Sstevel@tonic-gate 		 * state are subsequently lost until the next full
3206*0Sstevel@tonic-gate 		 * attach.  This is necessary since the driver unload
3207*0Sstevel@tonic-gate 		 * that must have occurred would have wiped out the
3208*0Sstevel@tonic-gate 		 * information necessary to re-configure the device
3209*0Sstevel@tonic-gate 		 * back online, e.g. memlist.
3210*0Sstevel@tonic-gate 		 */
3211*0Sstevel@tonic-gate 		PR_ALL("%s: some devices LOST (0x%x)...\n", f, devs_lost);
3212*0Sstevel@tonic-gate 
3213*0Sstevel@tonic-gate 		for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) {
3214*0Sstevel@tonic-gate 			if (!DEVSET_IN_SET(devs_lost, SBD_COMP_CPU, ut))
3215*0Sstevel@tonic-gate 				continue;
3216*0Sstevel@tonic-gate 
3217*0Sstevel@tonic-gate 			cp = dr_get_cpu_unit(bp, ut);
3218*0Sstevel@tonic-gate 			dr_device_transition(&cp->sbc_cm, DR_STATE_EMPTY);
3219*0Sstevel@tonic-gate 		}
3220*0Sstevel@tonic-gate 
3221*0Sstevel@tonic-gate 		for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) {
3222*0Sstevel@tonic-gate 			if (!DEVSET_IN_SET(devs_lost, SBD_COMP_MEM, ut))
3223*0Sstevel@tonic-gate 				continue;
3224*0Sstevel@tonic-gate 
3225*0Sstevel@tonic-gate 			mp = dr_get_mem_unit(bp, ut);
3226*0Sstevel@tonic-gate 			dr_device_transition(&mp->sbm_cm, DR_STATE_EMPTY);
3227*0Sstevel@tonic-gate 		}
3228*0Sstevel@tonic-gate 
3229*0Sstevel@tonic-gate 		for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) {
3230*0Sstevel@tonic-gate 			if (!DEVSET_IN_SET(devs_lost, SBD_COMP_IO, ut))
3231*0Sstevel@tonic-gate 				continue;
3232*0Sstevel@tonic-gate 
3233*0Sstevel@tonic-gate 			ip = dr_get_io_unit(bp, ut);
3234*0Sstevel@tonic-gate 			dr_device_transition(&ip->sbi_cm, DR_STATE_EMPTY);
3235*0Sstevel@tonic-gate 		}
3236*0Sstevel@tonic-gate 
3237*0Sstevel@tonic-gate 		DR_DEVS_DISCONNECT(bp, devs_lost);
3238*0Sstevel@tonic-gate 	}
3239*0Sstevel@tonic-gate }
3240*0Sstevel@tonic-gate 
3241*0Sstevel@tonic-gate static int
3242*0Sstevel@tonic-gate dr_board_init(dr_board_t *bp, dev_info_t *dip, int bd)
3243*0Sstevel@tonic-gate {
3244*0Sstevel@tonic-gate 	sbd_error_t	*err;
3245*0Sstevel@tonic-gate 
3246*0Sstevel@tonic-gate 	mutex_init(&bp->b_lock, NULL, MUTEX_DRIVER, NULL);
3247*0Sstevel@tonic-gate 	mutex_init(&bp->b_slock, NULL, MUTEX_DRIVER, NULL);
3248*0Sstevel@tonic-gate 	cv_init(&bp->b_scv, NULL, CV_DRIVER, NULL);
3249*0Sstevel@tonic-gate 	bp->b_rstate = SBD_STAT_EMPTY;
3250*0Sstevel@tonic-gate 	bp->b_ostate = SBD_STAT_UNCONFIGURED;
3251*0Sstevel@tonic-gate 	bp->b_cond = SBD_COND_UNKNOWN;
3252*0Sstevel@tonic-gate 	(void) drv_getparm(TIME, (void *)&bp->b_time);
3253*0Sstevel@tonic-gate 
3254*0Sstevel@tonic-gate 	(void) drmach_board_lookup(bd, &bp->b_id);
3255*0Sstevel@tonic-gate 	bp->b_num = bd;
3256*0Sstevel@tonic-gate 	bp->b_dip = dip;
3257*0Sstevel@tonic-gate 
3258*0Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_CPU)] = GETSTRUCT(dr_dev_unit_t,
3259*0Sstevel@tonic-gate 						MAX_CPU_UNITS_PER_BOARD);
3260*0Sstevel@tonic-gate 
3261*0Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_MEM)] = GETSTRUCT(dr_dev_unit_t,
3262*0Sstevel@tonic-gate 						MAX_MEM_UNITS_PER_BOARD);
3263*0Sstevel@tonic-gate 
3264*0Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_IO)] = GETSTRUCT(dr_dev_unit_t,
3265*0Sstevel@tonic-gate 						MAX_IO_UNITS_PER_BOARD);
3266*0Sstevel@tonic-gate 
3267*0Sstevel@tonic-gate 	/*
3268*0Sstevel@tonic-gate 	 * Initialize the devlists
3269*0Sstevel@tonic-gate 	 */
3270*0Sstevel@tonic-gate 	err = dr_init_devlists(bp);
3271*0Sstevel@tonic-gate 	if (err) {
3272*0Sstevel@tonic-gate 		sbd_err_clear(&err);
3273*0Sstevel@tonic-gate 		dr_board_destroy(bp);
3274*0Sstevel@tonic-gate 		return (-1);
3275*0Sstevel@tonic-gate 	} else if (bp->b_ndev == 0) {
3276*0Sstevel@tonic-gate 		dr_board_transition(bp, DR_STATE_EMPTY);
3277*0Sstevel@tonic-gate 	} else {
3278*0Sstevel@tonic-gate 		/*
3279*0Sstevel@tonic-gate 		 * Couldn't have made it down here without
3280*0Sstevel@tonic-gate 		 * having found at least one device.
3281*0Sstevel@tonic-gate 		 */
3282*0Sstevel@tonic-gate 		ASSERT(DR_DEVS_PRESENT(bp) != 0);
3283*0Sstevel@tonic-gate 		/*
3284*0Sstevel@tonic-gate 		 * Check the state of any possible devices on the
3285*0Sstevel@tonic-gate 		 * board.
3286*0Sstevel@tonic-gate 		 */
3287*0Sstevel@tonic-gate 		dr_board_discovery(bp);
3288*0Sstevel@tonic-gate 
3289*0Sstevel@tonic-gate 		bp->b_assigned = 1;
3290*0Sstevel@tonic-gate 
3291*0Sstevel@tonic-gate 		if (DR_DEVS_UNATTACHED(bp) == 0) {
3292*0Sstevel@tonic-gate 			/*
3293*0Sstevel@tonic-gate 			 * The board has no unattached devices, therefore
3294*0Sstevel@tonic-gate 			 * by reason of insanity it must be configured!
3295*0Sstevel@tonic-gate 			 */
3296*0Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_CONFIGURED);
3297*0Sstevel@tonic-gate 			bp->b_ostate = SBD_STAT_CONFIGURED;
3298*0Sstevel@tonic-gate 			bp->b_rstate = SBD_STAT_CONNECTED;
3299*0Sstevel@tonic-gate 			bp->b_cond = SBD_COND_OK;
3300*0Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&bp->b_time);
3301*0Sstevel@tonic-gate 		} else if (DR_DEVS_ATTACHED(bp)) {
3302*0Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_PARTIAL);
3303*0Sstevel@tonic-gate 			bp->b_ostate = SBD_STAT_CONFIGURED;
3304*0Sstevel@tonic-gate 			bp->b_rstate = SBD_STAT_CONNECTED;
3305*0Sstevel@tonic-gate 			bp->b_cond = SBD_COND_OK;
3306*0Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&bp->b_time);
3307*0Sstevel@tonic-gate 		} else {
3308*0Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_CONNECTED);
3309*0Sstevel@tonic-gate 			bp->b_rstate = SBD_STAT_CONNECTED;
3310*0Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&bp->b_time);
3311*0Sstevel@tonic-gate 		}
3312*0Sstevel@tonic-gate 	}
3313*0Sstevel@tonic-gate 
3314*0Sstevel@tonic-gate 	return (0);
3315*0Sstevel@tonic-gate }
3316*0Sstevel@tonic-gate 
3317*0Sstevel@tonic-gate static void
3318*0Sstevel@tonic-gate dr_board_destroy(dr_board_t *bp)
3319*0Sstevel@tonic-gate {
3320*0Sstevel@tonic-gate 	PR_ALL("dr_board_destroy: num %d, path %s\n",
3321*0Sstevel@tonic-gate 		bp->b_num, bp->b_path);
3322*0Sstevel@tonic-gate 
3323*0Sstevel@tonic-gate 	dr_board_transition(bp, DR_STATE_EMPTY);
3324*0Sstevel@tonic-gate 	bp->b_rstate = SBD_STAT_EMPTY;
3325*0Sstevel@tonic-gate 	(void) drv_getparm(TIME, (void *)&bp->b_time);
3326*0Sstevel@tonic-gate 
3327*0Sstevel@tonic-gate 	/*
3328*0Sstevel@tonic-gate 	 * Free up MEM unit structs.
3329*0Sstevel@tonic-gate 	 */
3330*0Sstevel@tonic-gate 	FREESTRUCT(bp->b_dev[NIX(SBD_COMP_MEM)],
3331*0Sstevel@tonic-gate 			dr_dev_unit_t, MAX_MEM_UNITS_PER_BOARD);
3332*0Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_MEM)] = NULL;
3333*0Sstevel@tonic-gate 	/*
3334*0Sstevel@tonic-gate 	 * Free up CPU unit structs.
3335*0Sstevel@tonic-gate 	 */
3336*0Sstevel@tonic-gate 	FREESTRUCT(bp->b_dev[NIX(SBD_COMP_CPU)],
3337*0Sstevel@tonic-gate 			dr_dev_unit_t, MAX_CPU_UNITS_PER_BOARD);
3338*0Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_CPU)] = NULL;
3339*0Sstevel@tonic-gate 	/*
3340*0Sstevel@tonic-gate 	 * Free up IO unit structs.
3341*0Sstevel@tonic-gate 	 */
3342*0Sstevel@tonic-gate 	FREESTRUCT(bp->b_dev[NIX(SBD_COMP_IO)],
3343*0Sstevel@tonic-gate 			dr_dev_unit_t, MAX_IO_UNITS_PER_BOARD);
3344*0Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_IO)] = NULL;
3345*0Sstevel@tonic-gate 
3346*0Sstevel@tonic-gate 	mutex_destroy(&bp->b_lock);
3347*0Sstevel@tonic-gate 	mutex_destroy(&bp->b_slock);
3348*0Sstevel@tonic-gate 	cv_destroy(&bp->b_scv);
3349*0Sstevel@tonic-gate }
3350*0Sstevel@tonic-gate 
3351*0Sstevel@tonic-gate void
3352*0Sstevel@tonic-gate dr_lock_status(dr_board_t *bp)
3353*0Sstevel@tonic-gate {
3354*0Sstevel@tonic-gate 	mutex_enter(&bp->b_slock);
3355*0Sstevel@tonic-gate 	while (bp->b_sflags & DR_BSLOCK)
3356*0Sstevel@tonic-gate 		cv_wait(&bp->b_scv, &bp->b_slock);
3357*0Sstevel@tonic-gate 	bp->b_sflags |= DR_BSLOCK;
3358*0Sstevel@tonic-gate 	mutex_exit(&bp->b_slock);
3359*0Sstevel@tonic-gate }
3360*0Sstevel@tonic-gate 
3361*0Sstevel@tonic-gate void
3362*0Sstevel@tonic-gate dr_unlock_status(dr_board_t *bp)
3363*0Sstevel@tonic-gate {
3364*0Sstevel@tonic-gate 	mutex_enter(&bp->b_slock);
3365*0Sstevel@tonic-gate 	bp->b_sflags &= ~DR_BSLOCK;
3366*0Sstevel@tonic-gate 	cv_signal(&bp->b_scv);
3367*0Sstevel@tonic-gate 	mutex_exit(&bp->b_slock);
3368*0Sstevel@tonic-gate }
3369*0Sstevel@tonic-gate 
3370*0Sstevel@tonic-gate /*
3371*0Sstevel@tonic-gate  * Extract flags passed via ioctl.
3372*0Sstevel@tonic-gate  */
3373*0Sstevel@tonic-gate int
3374*0Sstevel@tonic-gate dr_cmd_flags(dr_handle_t *hp)
3375*0Sstevel@tonic-gate {
3376*0Sstevel@tonic-gate 	return (hp->h_sbdcmd.cmd_cm.c_flags);
3377*0Sstevel@tonic-gate }
3378