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