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