xref: /illumos-gate/usr/src/uts/sun4u/sunfire/io/sysctrl_dr.c (revision 78a2e113edb6fe0a0382b403b55d92e8f0bba78f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2005 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 #include <sys/types.h>
30 #include <sys/conf.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
33 #include <sys/sunndi.h>
34 #include <sys/ddi_impldefs.h>
35 #include <sys/ndi_impldefs.h>
36 #include <sys/obpdefs.h>
37 #include <sys/cmn_err.h>
38 #include <sys/errno.h>
39 #include <sys/kmem.h>
40 #include <sys/debug.h>
41 #include <sys/sysmacros.h>
42 #include <sys/ivintr.h>
43 #include <sys/autoconf.h>
44 #include <sys/intreg.h>
45 #include <sys/proc.h>
46 #include <sys/machsystm.h>
47 #include <sys/modctl.h>
48 #include <sys/callb.h>
49 #include <sys/file.h>
50 #include <sys/open.h>
51 #include <sys/stat.h>
52 #include <sys/fhc.h>
53 #include <sys/sysctrl.h>
54 #include <sys/jtag.h>
55 #include <sys/ac.h>
56 #include <sys/simmstat.h>
57 #include <sys/clock.h>
58 #include <sys/promif.h>
59 #include <sys/promimpl.h>
60 #include <sys/cpr.h>
61 #include <sys/cpuvar.h>
62 #include <sys/machcpuvar.h>
63 #include <sys/x_call.h>
64 
65 #ifdef DEBUG
66 struct	regs_data {
67 	caddr_t msg;
68 	u_longlong_t physaddr;
69 	uint_t pre_dsct;
70 	uint_t post_dsct;
71 	uint_t eflag;
72 	uint_t oflag;
73 };
74 
75 static	struct regs_data reg_tmpl[] = {
76 	"AC  Control and Status reg = 0x", AC_BCSR(0), 0, 0, 0, 0,
77 	"FHC Control and Status reg = 0x", FHC_CTRL(0), 0, 0, 0, 0,
78 	"JTAG Control reg = 0x", FHC_JTAG_CTRL(0), 0, 0, 0, 0,
79 	"Interrupt Group Number reg = 0x", FHC_IGN(0), 0, 0, 0, 0,
80 	"System Interrupt Mapping reg = 0x", FHC_SIM(0), 0, 0, 0, 0,
81 	"System Interrupt State reg = 0x", FHC_SSM(0), 0, 0, 0, 0,
82 	"UART Interrupt Mapping reg = 0x", FHC_UIM(0), 0, 0, 0, 0,
83 	"UART Interrupt State reg = 0x", FHC_USM(0), 0, 0, 0, 0
84 };
85 
86 #define	NUM_REG  (sizeof (reg_tmpl)/sizeof (reg_tmpl[0]))
87 static	struct regs_data reg_dt[MAX_BOARDS][NUM_REG];
88 
89 int sysctrl_enable_regdump = 0;
90 
91 static void precache_regdump(int board);
92 static void display_regdump(void);
93 static void boardstat_regdump(void);
94 
95 #endif /* DEBUG */
96 
97 extern void bd_remove_poll(struct sysctrl_soft_state *);
98 extern int sysctrl_getsystem_freq(void);
99 extern enum power_state compute_power_state(struct sysctrl_soft_state *, int);
100 extern enum temp_state fhc_env_temp_state(int);
101 extern int sysctrl_hotplug_disabled;
102 /* Let user disable Sunfire Dynamic Reconfiguration */
103 int enable_dynamic_reconfiguration = 1;
104 
105 int enable_redist = 1;
106 
107 static void sysc_dr_err_decode(sysc_dr_handle_t *, dev_info_t *, int);
108 static uint_t
109 sysc_policy_enough_cooling(struct sysctrl_soft_state *softsp,
110 	sysc_cfga_stat_t *sysc_stat, uint_t ps_mutex_is_held);
111 static uint_t
112 sysc_policy_enough_precharge(struct sysctrl_soft_state *softsp,
113 	sysc_cfga_stat_t *sysc_stat);
114 static uint_t
115 sysc_policy_enough_power(struct sysctrl_soft_state *softsp,
116 	int plus_load, uint_t ps_mutex_is_held);
117 static uint_t
118 sysc_policy_hardware_compatible(struct sysctrl_soft_state *softsp,
119 	sysc_cfga_stat_t *sysc_stat, sysc_cfga_pkt_t *pkt);
120 static void sysc_policy_empty_condition(
121 	struct sysctrl_soft_state *softsp,
122 	sysc_cfga_stat_t *sysc_stat, uint_t failure,
123 	uint_t ps_mutex_is_held);
124 static void sysc_policy_disconnected_condition(
125 	struct sysctrl_soft_state *softsp,
126 	sysc_cfga_stat_t *sysc_stat, uint_t failure,
127 	uint_t ps_mutex_is_held);
128 static void sysc_policy_connected_condition(struct sysctrl_soft_state *softsp,
129 		sysc_cfga_stat_t *sysc_stat,
130 		uint_t ps_mutex_is_held);
131 static void sysc_policy_set_condition(void *sp, sysc_cfga_stat_t *sysc_stat,
132 				uint_t ps_mutex_is_held);
133 static void sysc_policy_audit_messages(sysc_audit_evt_t event,
134 		sysc_cfga_stat_t *sysc_stat);
135 
136 static void sysctrl_post_config_change(struct sysctrl_soft_state *softsp);
137 static int sysc_bd_connect(int, sysc_cfga_pkt_t *);
138 static int sysc_bd_disconnect(int, sysc_cfga_pkt_t *);
139 static int sysc_bd_configure(int, sysc_cfga_pkt_t *);
140 static int sysc_bd_unconfigure(int, sysc_cfga_pkt_t *);
141 
142 static void sysc_dr_init(sysc_dr_handle_t *handle);
143 static void sysc_dr_uninit(sysc_dr_handle_t *handle);
144 static int sysc_dr_attach(sysc_dr_handle_t *handle, int board);
145 static int sysc_dr_detach(sysc_dr_handle_t *handle, int board);
146 
147 static int sysc_prom_select(pnode_t pnode, void *arg, uint_t flag);
148 static void sysc_branch_callback(dev_info_t *rdip, void *arg, uint_t flags);
149 
150 static int find_and_setup_cpu(int);
151 
152 static int sysc_board_connect_supported(enum board_type);
153 
154 static int find_and_setup_cpu_start(void *cpuid_arg, int has_changed);
155 /*
156  * This function will basically do a prediction on the power state
157  * based on adding one additional load to the equation implemented
158  * by the function compute_power_state.
159  */
160 /*ARGSUSED*/
161 static uint_t
162 sysc_policy_enough_power(struct sysctrl_soft_state *softsp,
163 	int plus_load, uint_t ps_mutex_is_held)
164 {
165 	int retval = 0;
166 
167 	ASSERT(softsp);
168 
169 	if (!ps_mutex_is_held) {
170 		mutex_enter(&softsp->ps_fail_lock);
171 	}
172 
173 	/*
174 	 * note that we add one more load
175 	 * to the equation in compute_power_state
176 	 * and the answer better be REDUNDANT or
177 	 * MINIMUM before proceeding.
178 	 */
179 	switch (compute_power_state(softsp, plus_load)) {
180 		case REDUNDANT:
181 		case MINIMUM:
182 			retval = 1;
183 			break;
184 		case BELOW_MINIMUM:
185 		default:
186 			break;
187 	}
188 
189 	if (!ps_mutex_is_held) {
190 		mutex_exit(&softsp->ps_fail_lock);
191 	}
192 	return (retval);
193 }
194 
195 /*
196  * This function gropes through the shadow registers in the sysctrl soft_state
197  * for the core power supply status, since fan status for them are ORed into
198  * the same status bit, and all other remaining fans.
199  */
200 static uint_t
201 sysc_policy_enough_cooling(struct sysctrl_soft_state *softsp,
202 	sysc_cfga_stat_t *sysc_stat, uint_t ps_mutex_is_held)
203 {
204 	int	retval = 0;
205 
206 	if (!ps_mutex_is_held) {
207 		mutex_enter(&softsp->ps_fail_lock);
208 	}
209 
210 	/*
211 	 * check the power supply in the slot in question
212 	 * for fans then check all the common fans.
213 	 */
214 	retval = ((softsp->ps_stats[FHC_BOARD2PS(sysc_stat->board)].pshadow ==
215 			PRES_IN) &&
216 		(softsp->ps_stats[FHC_BOARD2PS(sysc_stat->board)].dcshadow ==
217 			PS_OK));
218 	if (!ps_mutex_is_held) {
219 		mutex_exit(&softsp->ps_fail_lock);
220 	}
221 	return (retval);
222 }
223 
224 /*
225  * This function will check all precharge voltage status.
226  */
227 /*ARGSUSED*/
228 static uint_t
229 sysc_policy_enough_precharge(struct sysctrl_soft_state *softsp,
230 	sysc_cfga_stat_t *sysc_stat)
231 {
232 	int	retval = 0;
233 	int	ppsval = 0;
234 
235 	mutex_enter(&softsp->ps_fail_lock);
236 
237 		/*
238 		 *	note that we always have to explicitly check
239 		 *	the peripheral power supply for precharge since it
240 		 *	supplies all of the precharge voltages.
241 		 */
242 	ppsval = (softsp->ps_stats[SYS_PPS0_INDEX].pshadow == PRES_IN) &&
243 		(softsp->ps_stats[SYS_PPS0_INDEX].dcshadow == PS_OK);
244 
245 		/*
246 		 *	check all the precharge status
247 		 */
248 	retval = ((softsp->ps_stats[SYS_V3_PCH_INDEX].pshadow == PRES_IN) &&
249 		(softsp->ps_stats[SYS_V3_PCH_INDEX].dcshadow == PS_OK) &&
250 		(softsp->ps_stats[SYS_V5_PCH_INDEX].pshadow == PRES_IN) &&
251 		(softsp->ps_stats[SYS_V5_PCH_INDEX].dcshadow == PS_OK));
252 
253 	mutex_exit(&softsp->ps_fail_lock);
254 	return (retval&&ppsval);
255 }
256 
257 static int Fsys;
258 
259 /*
260  * This function should only be called once as we may
261  * zero the clock board registers to indicate a configuration change.
262  * The code to calculate the bus frequency has been removed and we
263  * read the eeprom property instead. Another static Fmod (module
264  * frequency may be needed later but so far it is commented out.
265  */
266 void
267 set_clockbrd_info(void)
268 {
269 	uint_t clock_freq = 0;
270 
271 	pnode_t root = prom_nextnode((pnode_t)0);
272 	(void) prom_getprop(root, "clock-frequency", (caddr_t)&clock_freq);
273 	Fsys = clock_freq / 1000000;
274 }
275 
276 #define	abs(x)	((x) < 0 ? -(x) : (x))
277 
278 /*ARGSUSED*/
279 static uint_t
280 sysc_policy_hardware_compatible(struct sysctrl_soft_state *softsp,
281 	sysc_cfga_stat_t *sysc_stat, sysc_cfga_pkt_t *pkt)
282 {
283 	int status;
284 
285 	ASSERT(Fsys > 0);
286 
287 	/* Only allow DR operations on supported hardware */
288 	switch (sysc_stat->type) {
289 	case CPU_BOARD: {
290 #ifdef RFE_4174486
291 		int i;
292 		int cpu_freq;
293 		int sram_mode;
294 
295 		ASSERT(Fmod > 0);
296 
297 		cpu_freq = CPU->cpu_type_info.pi_clock;
298 
299 		if (abs(cpu_freq - Fmod) < 8)
300 			sram_mode = 1;
301 		else
302 			sram_mode = 2;
303 
304 		status = TRUE;
305 		for (i = 0; i < 2; i++) {
306 			/*
307 			 * XXX: Add jtag code which rescans disabled boards.
308 			 * For the time being disabled boards are not
309 			 * checked for compatibility when cpu_speed is 0.
310 			 */
311 			if (sysc_stat->bd.cpu[i].cpu_speed == 0)
312 				continue;
313 
314 			if (sysc_stat->bd.cpu[i].cpu_speed < cpu_freq) {
315 				cmn_err(CE_WARN, "board %d, cpu module %c "
316 					"rated at %d Mhz, system freq %d Mhz",
317 					sysc_stat->board, (i == 0) ? 'A' : 'B',
318 					sysc_stat->bd.cpu[i].cpu_speed,
319 					cpu_freq);
320 				status = FALSE;
321 			}
322 
323 			if (sram_mode != sysc_stat->bd.cpu[i].cpu_sram_mode) {
324 				cmn_err(CE_WARN, "board %d, cpu module %c "
325 					"incompatible sram mode of %dx, "
326 					"system is %dx", sysc_stat->board,
327 					(i == 0) ? 'A' : 'B',
328 					sysc_stat->bd.cpu[i].cpu_sram_mode,
329 					sram_mode);
330 				status = FALSE;
331 			}
332 		}
333 		break;
334 #endif /* RFE_4174486 */
335 	}
336 
337 	case MEM_BOARD:
338 	case IO_2SBUS_BOARD:
339 	case IO_SBUS_FFB_BOARD:
340 	case IO_PCI_BOARD:
341 	case IO_2SBUS_SOCPLUS_BOARD:
342 	case IO_SBUS_FFB_SOCPLUS_BOARD:
343 		status = TRUE;
344 		break;
345 
346 	case CLOCK_BOARD:
347 	case DISK_BOARD:
348 	default:
349 		status = FALSE;		/* default is not supported */
350 		break;
351 	}
352 
353 	if (status == FALSE)
354 		return (status);
355 
356 	/* Check for Sunfire boards in a Sunfire+ system */
357 	if (status == TRUE && Fsys > 84 && !fhc_bd_is_plus(sysc_stat->board)) {
358 		(void) snprintf(pkt->errbuf, SYSC_OUTPUT_LEN,
359 		    "not 100 MHz capable   ");
360 		cmn_err(CE_WARN, "board %d, is not capable of running at "
361 		    "current system clock (%dMhz)", sysc_stat->board, Fsys);
362 
363 		status = FALSE;
364 	}
365 
366 	return (status);
367 }
368 
369 /*
370  * This function is called to check the policy for a request to transition
371  * to the connected state from the disconnected state. The generic policy
372  * is to do sanity checks again before going live.
373  */
374 /*ARGSUSED*/
375 int
376 sysc_policy_connect(struct sysctrl_soft_state *softsp,
377 		sysc_cfga_pkt_t *pkt, sysc_cfga_stat_t *sysc_stat)
378 {
379 	int retval;
380 
381 	ASSERT(fhc_bdlist_locked());
382 
383 	DPRINTF(SYSC_DEBUG, ("Previous RState: %d\n", sysc_stat->rstate));
384 	DPRINTF(SYSC_DEBUG, ("Previous OState: %d\n", sysc_stat->ostate));
385 
386 	switch (sysc_stat->rstate) {
387 	case SYSC_CFGA_RSTATE_DISCONNECTED:
388 		/*
389 		 * Safety policy: only allow connect if board is UNKNOWN cond.
390 		 * cold start board will be demoted to UNKNOWN cond when
391 		 * disconnected
392 		 */
393 		if (sysc_stat->condition != SYSC_CFGA_COND_UNKNOWN) {
394 			SYSC_ERR_SET(pkt, SYSC_ERR_COND);
395 			return (EINVAL);
396 		}
397 
398 		if (!enable_dynamic_reconfiguration) {
399 			SYSC_ERR_SET(pkt, SYSC_ERR_NON_DR_PROM);
400 			return (ENOTSUP);
401 		}
402 
403 		if (sysctrl_hotplug_disabled) {
404 			SYSC_ERR_SET(pkt, SYSC_ERR_HOTPLUG);
405 			return (ENOTSUP);
406 		}
407 
408 		/* Check PROM support. */
409 		if (!sysc_board_connect_supported(sysc_stat->type)) {
410 			cmn_err(CE_WARN, "%s board %d connect"
411 			    " is not supported by firmware.",
412 			    fhc_bd_typestr(sysc_stat->type), sysc_stat->board);
413 			SYSC_ERR_SET(pkt, SYSC_ERR_HW_COMPAT);
414 			return (ENOTSUP);
415 		}
416 
417 		if (!sysc_policy_enough_power(softsp, TRUE, FALSE)) {
418 			SYSC_ERR_SET(pkt, SYSC_ERR_POWER);
419 			return (EAGAIN);
420 		}
421 
422 		if (!sysc_policy_enough_precharge(softsp, sysc_stat)) {
423 			SYSC_ERR_SET(pkt, SYSC_ERR_PRECHARGE);
424 			return (EAGAIN);
425 		}
426 
427 		if (!sysc_policy_enough_cooling(softsp, sysc_stat, FALSE)) {
428 			SYSC_ERR_SET(pkt, SYSC_ERR_COOLING);
429 			return (EAGAIN);
430 		}
431 
432 		if (!sysc_policy_hardware_compatible(softsp, sysc_stat, pkt)) {
433 			SYSC_ERR_SET(pkt, SYSC_ERR_HW_COMPAT);
434 			return (ENOTSUP);
435 		}
436 		sysc_policy_audit_messages(SYSC_AUDIT_RSTATE_CONNECT,
437 			sysc_stat);
438 
439 		retval = sysc_bd_connect(sysc_stat->board, pkt);
440 		if (!retval) {
441 			sysc_stat->rstate = SYSC_CFGA_RSTATE_CONNECTED;
442 			sysc_policy_connected_condition(softsp,
443 				sysc_stat, FALSE);
444 			sysc_policy_audit_messages(SYSC_AUDIT_RSTATE_SUCCEEDED,
445 				sysc_stat);
446 		} else {
447 			uint_t prom_failure;
448 
449 			prom_failure = (retval == EIO &&
450 			    pkt->cmd_cfga.errtype == SYSC_ERR_PROM) ?
451 			    TRUE : FALSE;
452 			sysc_policy_disconnected_condition(softsp,
453 				sysc_stat, prom_failure, FALSE);
454 			sysc_policy_audit_messages(
455 				SYSC_AUDIT_RSTATE_CONNECT_FAILED,
456 				sysc_stat);
457 		}
458 		break;
459 	case SYSC_CFGA_RSTATE_EMPTY:
460 	case SYSC_CFGA_RSTATE_CONNECTED:
461 	default:
462 		SYSC_ERR_SET(pkt, SYSC_ERR_RSTATE);
463 		retval = EINVAL;
464 		break;
465 	}
466 
467 	DPRINTF(SYSC_DEBUG, ("Current RState: %d\n", sysc_stat->rstate));
468 	DPRINTF(SYSC_DEBUG, ("Current OState: %d\n", sysc_stat->ostate));
469 	DPRINTF(SYSC_DEBUG, ("Current Condition: %d\n", sysc_stat->condition));
470 
471 	return (retval);
472 }
473 
474 /*
475  * This function is called to check the policy for a request to transition
476  * to the disconnected state from the connected/unconfigured state only.
477  * All other requests are invalid.
478  */
479 /*ARGSUSED*/
480 int
481 sysc_policy_disconnect(struct sysctrl_soft_state *softsp,
482 			sysc_cfga_pkt_t *pkt, sysc_cfga_stat_t *sysc_stat)
483 {
484 	int retval;
485 
486 	ASSERT(fhc_bdlist_locked());
487 
488 	DPRINTF(SYSC_DEBUG, ("Previous RState: %d\n", sysc_stat->rstate));
489 	DPRINTF(SYSC_DEBUG, ("Previous OState: %d\n", sysc_stat->ostate));
490 
491 	switch (sysc_stat->rstate) {
492 	case SYSC_CFGA_RSTATE_CONNECTED:
493 		switch (sysc_stat->ostate) {
494 		case SYSC_CFGA_OSTATE_UNCONFIGURED:
495 			if (!enable_dynamic_reconfiguration) {
496 				SYSC_ERR_SET(pkt, SYSC_ERR_NON_DR_PROM);
497 				return (ENOTSUP);
498 			}
499 
500 			/* Check PROM support. */
501 			if (!sysc_board_connect_supported(sysc_stat->type)) {
502 				cmn_err(CE_WARN, "%s board %d disconnect"
503 				    " is not supported by firmware.",
504 				    fhc_bd_typestr(sysc_stat->type),
505 				    sysc_stat->board);
506 				SYSC_ERR_SET(pkt, SYSC_ERR_HW_COMPAT);
507 				return (ENOTSUP);
508 			}
509 
510 			if (!sysc_policy_hardware_compatible(softsp,
511 				sysc_stat, pkt)) {
512 				cmn_err(CE_WARN, "%s board %d disconnect"
513 				" is not yet supported.",
514 				fhc_bd_typestr(sysc_stat->type),
515 					sysc_stat->board);
516 				SYSC_ERR_SET(pkt, SYSC_ERR_HW_COMPAT);
517 				return (ENOTSUP);
518 			}
519 
520 			if (fhc_bd_is_jtag_master(sysc_stat->board)) {
521 				sysc_policy_update(softsp, sysc_stat,
522 					SYSC_EVT_BD_CORE_RESOURCE_DISCONNECT);
523 				SYSC_ERR_SET(pkt, SYSC_ERR_CORE_RESOURCE);
524 				return (EINVAL);
525 			}
526 
527 			sysc_policy_audit_messages(SYSC_AUDIT_RSTATE_DISCONNECT,
528 				sysc_stat);
529 
530 			retval = sysc_bd_disconnect(sysc_stat->board, pkt);
531 			if (!retval) {
532 				sysc_stat->rstate =
533 					SYSC_CFGA_RSTATE_DISCONNECTED;
534 				DPRINTF(SYSCTRL_ATTACH_DEBUG,
535 				    ("disconnect starting bd_remove_poll()"));
536 				bd_remove_poll(softsp);
537 				sysc_policy_disconnected_condition(
538 					softsp,
539 					sysc_stat, FALSE, FALSE);
540 				sysc_policy_audit_messages(
541 					SYSC_AUDIT_RSTATE_SUCCEEDED,
542 					sysc_stat);
543 				cmn_err(CE_NOTE,
544 					"board %d is ready to remove",
545 					sysc_stat->board);
546 			} else {
547 				sysc_policy_connected_condition(
548 					softsp, sysc_stat, FALSE);
549 				sysc_policy_audit_messages(
550 					SYSC_AUDIT_RSTATE_DISCONNECT_FAILED,
551 					sysc_stat);
552 			}
553 			break;
554 		case SYSC_CFGA_OSTATE_CONFIGURED:
555 		default:
556 			SYSC_ERR_SET(pkt, SYSC_ERR_OSTATE);
557 			retval = EINVAL;
558 			break;
559 		}
560 		break;
561 	case SYSC_CFGA_RSTATE_EMPTY:
562 	case SYSC_CFGA_RSTATE_DISCONNECTED:
563 	default:
564 		SYSC_ERR_SET(pkt, SYSC_ERR_RSTATE);
565 		retval = EINVAL;
566 		break;
567 	}
568 
569 	DPRINTF(SYSC_DEBUG, ("Current RState: %d\n", sysc_stat->rstate));
570 	DPRINTF(SYSC_DEBUG, ("Current OState: %d\n", sysc_stat->ostate));
571 	DPRINTF(SYSC_DEBUG, ("Current Condition: %d\n", sysc_stat->condition));
572 
573 	return (retval);
574 }
575 
576 /*
577  * This function is called to check the policy for a request to transition
578  * from the connected/configured state to the connected/unconfigured state only.
579  * All other requests are invalid.
580  */
581 /*ARGSUSED*/
582 int
583 sysc_policy_unconfigure(struct sysctrl_soft_state *softsp,
584 			sysc_cfga_pkt_t *pkt, sysc_cfga_stat_t *sysc_stat)
585 {
586 	int retval;
587 
588 	ASSERT(fhc_bdlist_locked());
589 
590 	DPRINTF(SYSC_DEBUG, ("Previous RState: %d\n", sysc_stat->rstate));
591 	DPRINTF(SYSC_DEBUG, ("Previous OState: %d\n", sysc_stat->ostate));
592 
593 	switch (sysc_stat->ostate) {
594 	case SYSC_CFGA_OSTATE_CONFIGURED:
595 		if (!enable_dynamic_reconfiguration) {
596 			SYSC_ERR_SET(pkt, SYSC_ERR_NON_DR_PROM);
597 			return (ENOTSUP);
598 		}
599 
600 		if (!sysc_policy_hardware_compatible(softsp, sysc_stat, pkt)) {
601 			cmn_err(CE_WARN, "%s board %d unconfigure"
602 			" is not yet supported.",
603 			fhc_bd_typestr(sysc_stat->type), sysc_stat->board);
604 			SYSC_ERR_SET(pkt, SYSC_ERR_HW_COMPAT);
605 			return (ENOTSUP);
606 		}
607 
608 		sysc_policy_audit_messages(SYSC_AUDIT_OSTATE_UNCONFIGURE,
609 			sysc_stat);
610 
611 		retval = sysc_bd_unconfigure(sysc_stat->board, pkt);
612 		if (!retval) {
613 		    sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
614 		    sysc_policy_audit_messages(
615 			SYSC_AUDIT_OSTATE_SUCCEEDED,
616 			sysc_stat);
617 		} else {
618 		    sysc_policy_audit_messages(
619 			SYSC_AUDIT_OSTATE_UNCONFIGURE_FAILED,
620 			sysc_stat);
621 		}
622 		sysc_policy_connected_condition(softsp, sysc_stat, FALSE);
623 		break;
624 	case SYSC_CFGA_OSTATE_UNCONFIGURED:
625 	default:
626 		SYSC_ERR_SET(pkt, SYSC_ERR_OSTATE);
627 		retval = EINVAL;
628 		break;
629 	}
630 
631 	DPRINTF(SYSC_DEBUG, ("Current RState: %d\n", sysc_stat->rstate));
632 	DPRINTF(SYSC_DEBUG, ("Current OState: %d\n", sysc_stat->ostate));
633 	DPRINTF(SYSC_DEBUG, ("Current Condition: %d\n", sysc_stat->condition));
634 
635 	return (retval);
636 }
637 
638 /*
639  * This function is called to check the policy for a requested transition
640  * from either the connected/unconfigured state or the connected/configured
641  * state to the connected/configured state.  The redundant state transition
642  * is permitted for partially configured set of devices.  Basically, we
643  * retry the configure.
644  */
645 /*ARGSUSED*/
646 int
647 sysc_policy_configure(struct sysctrl_soft_state *softsp,
648 			sysc_cfga_pkt_t *pkt, sysc_cfga_stat_t *sysc_stat)
649 {
650 	int retval;
651 
652 	ASSERT(fhc_bdlist_locked());
653 
654 	DPRINTF(SYSC_DEBUG, ("Previous RState: %d\n", sysc_stat->rstate));
655 	DPRINTF(SYSC_DEBUG, ("Previous OState: %d\n", sysc_stat->ostate));
656 
657 	switch (sysc_stat->rstate) {
658 	case SYSC_CFGA_RSTATE_CONNECTED:
659 		switch (sysc_stat->ostate) {
660 		case SYSC_CFGA_OSTATE_UNCONFIGURED:
661 			if (sysc_stat->condition != SYSC_CFGA_COND_OK) {
662 				SYSC_ERR_SET(pkt, SYSC_ERR_COND);
663 				return (EINVAL);
664 			}
665 
666 			sysc_policy_audit_messages(SYSC_AUDIT_OSTATE_CONFIGURE,
667 				sysc_stat);
668 			retval = sysc_bd_configure(sysc_stat->board, pkt);
669 			sysc_stat->ostate = SYSC_CFGA_OSTATE_CONFIGURED;
670 			sysc_policy_connected_condition(softsp,
671 				sysc_stat, FALSE);
672 			if (!retval) {
673 				sysc_policy_audit_messages(
674 					SYSC_AUDIT_OSTATE_SUCCEEDED,
675 					sysc_stat);
676 			} else {
677 				sysc_policy_audit_messages(
678 					SYSC_AUDIT_OSTATE_CONFIGURE_FAILED,
679 					sysc_stat);
680 			}
681 			break;
682 		case SYSC_CFGA_OSTATE_CONFIGURED:
683 			SYSC_ERR_SET(pkt, SYSC_ERR_OSTATE);
684 			retval = ENOTSUP;
685 			break;
686 		default:
687 			SYSC_ERR_SET(pkt, SYSC_ERR_OSTATE);
688 			retval = EINVAL;
689 			break;
690 		}
691 		break;
692 	case SYSC_CFGA_RSTATE_EMPTY:
693 	case SYSC_CFGA_RSTATE_DISCONNECTED:
694 	default:
695 		SYSC_ERR_SET(pkt, SYSC_ERR_RSTATE);
696 		retval = EINVAL;
697 		break;
698 	}
699 
700 
701 	DPRINTF(SYSC_DEBUG, ("Current RState: %d\n", sysc_stat->rstate));
702 	DPRINTF(SYSC_DEBUG, ("Current OState: %d\n", sysc_stat->ostate));
703 	DPRINTF(SYSC_DEBUG, ("Current Condition: %d\n", sysc_stat->condition));
704 
705 	return (retval);
706 }
707 
708 /*ARGSUSED*/
709 static void
710 sysc_policy_empty_condition(struct sysctrl_soft_state *softsp,
711 	sysc_cfga_stat_t *sysc_stat, uint_t failure,
712 	uint_t ps_mutex_is_held)
713 {
714 	ASSERT(fhc_bdlist_locked());
715 
716 	switch (sysc_stat->condition) {
717 	case SYSC_CFGA_COND_UNKNOWN:
718 	case SYSC_CFGA_COND_OK:
719 	case SYSC_CFGA_COND_FAILING:
720 	case SYSC_CFGA_COND_FAILED:
721 	/* nothing in the slot so just check power supplies */
722 	case SYSC_CFGA_COND_UNUSABLE:
723 	    if (sysc_policy_enough_cooling(softsp, sysc_stat,
724 		ps_mutex_is_held) &&
725 		sysc_policy_enough_power(softsp, FALSE,
726 		ps_mutex_is_held)) {
727 		sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
728 	    } else {
729 		sysc_stat->condition = SYSC_CFGA_COND_UNUSABLE;
730 	    }
731 	    sysc_stat->last_change = gethrestime_sec();
732 	    break;
733 	default:
734 	    ASSERT(FALSE);
735 	    break;
736 	}
737 }
738 /*ARGSUSED*/
739 static void
740 sysc_policy_disconnected_condition(struct sysctrl_soft_state *softsp,
741 	sysc_cfga_stat_t *sysc_stat, uint_t failure,
742 	uint_t ps_mutex_is_held)
743 {
744 	ASSERT(fhc_bdlist_locked());
745 
746 	if (failure) {
747 		sysc_stat->condition = SYSC_CFGA_COND_FAILED;
748 		sysc_stat->last_change = gethrestime_sec();
749 		return;
750 	}
751 	switch (sysc_stat->condition) {
752 	/*
753 	 * if unknown, we have come from hotplug case so do a quick
754 	 * reevaluation.
755 	 */
756 	case SYSC_CFGA_COND_UNKNOWN:
757 	/*
758 	 * if ok, we have come from connected to disconnected and we stay
759 	 * ok until removed or reevaluate when reconnect.  We might have
760 	 * experienced a ps fail so reevaluate the condition.
761 	 */
762 	case SYSC_CFGA_COND_OK:
763 	/*
764 	 * if unsuable, either power supply was missing or
765 	 * hardware was not compatible.  Check to see if
766 	 * this is still true.
767 	 */
768 	case SYSC_CFGA_COND_UNUSABLE:
769 	/*
770 	 * failing must transition in the disconnected state
771 	 * to either unusable or unknown.  We may have come here
772 	 * from cfgadm -f -c disconnect after a power supply failure
773 	 * in an attempt to protect the board.
774 	 */
775 	case SYSC_CFGA_COND_FAILING:
776 	    if (sysc_policy_enough_cooling(softsp, sysc_stat,
777 		ps_mutex_is_held) &&
778 		sysc_policy_enough_power(softsp, FALSE,
779 		ps_mutex_is_held)) {
780 		sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
781 	    } else {
782 		sysc_stat->condition = SYSC_CFGA_COND_UNUSABLE;
783 	    }
784 	    sysc_stat->last_change = gethrestime_sec();
785 	    break;
786 	/*
787 	 * if failed, we have failed POST and must stay in this
788 	 * condition until the board has been removed
789 	 * before ever coming back into another condition
790 	 */
791 	case SYSC_CFGA_COND_FAILED:
792 		break;
793 	default:
794 		ASSERT(FALSE);
795 		break;
796 	}
797 }
798 
799 /*ARGSUSED*/
800 static void
801 sysc_policy_connected_condition(struct sysctrl_soft_state *softsp,
802 		sysc_cfga_stat_t *sysc_stat,
803 		uint_t ps_mutex_is_held)
804 {
805 	ASSERT(fhc_bdlist_locked());
806 
807 	switch (sysc_stat->condition) {
808 	case SYSC_CFGA_COND_UNKNOWN:
809 	case SYSC_CFGA_COND_OK:
810 	case SYSC_CFGA_COND_FAILING:
811 	case SYSC_CFGA_COND_UNUSABLE:
812 	    if (sysc_policy_enough_cooling(softsp, sysc_stat,
813 		ps_mutex_is_held) &&
814 		sysc_policy_enough_power(softsp, FALSE,
815 		ps_mutex_is_held) &&
816 		(fhc_env_temp_state(sysc_stat->board) == TEMP_OK)) {
817 			sysc_stat->condition = SYSC_CFGA_COND_OK;
818 	    } else {
819 			sysc_stat->condition = SYSC_CFGA_COND_FAILING;
820 	    }
821 	    sysc_stat->last_change = gethrestime_sec();
822 	    break;
823 	case SYSC_CFGA_COND_FAILED:
824 	    break;
825 	default:
826 	    ASSERT(FALSE);
827 	    break;
828 	}
829 }
830 
831 static void
832 sysc_policy_set_condition(void *sp, sysc_cfga_stat_t *sysc_stat,
833 		uint_t ps_mutex_is_held)
834 {
835 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)sp;
836 
837 	ASSERT(fhc_bdlist_locked());
838 
839 	switch (sysc_stat->rstate) {
840 	case SYSC_CFGA_RSTATE_EMPTY:
841 		sysc_policy_empty_condition(softsp, sysc_stat,
842 			FALSE, ps_mutex_is_held);
843 		break;
844 	case SYSC_CFGA_RSTATE_DISCONNECTED:
845 		sysc_policy_disconnected_condition(softsp, sysc_stat,
846 			FALSE, ps_mutex_is_held);
847 		break;
848 	case SYSC_CFGA_RSTATE_CONNECTED:
849 		sysc_policy_connected_condition(softsp, sysc_stat,
850 			ps_mutex_is_held);
851 		break;
852 	default:
853 		ASSERT(FALSE);
854 		break;
855 	}
856 }
857 
858 void
859 sysc_policy_update(void *softsp, sysc_cfga_stat_t *sysc_stat,
860 	sysc_evt_t event)
861 {
862 	fhc_bd_t *list;
863 
864 	ASSERT(event == SYSC_EVT_BD_HP_DISABLED || fhc_bdlist_locked());
865 
866 	switch (event) {
867 	case SYSC_EVT_BD_EMPTY:
868 		sysc_stat->rstate = SYSC_CFGA_RSTATE_EMPTY;
869 		sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
870 		sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
871 		sysc_policy_empty_condition(softsp, sysc_stat, FALSE, FALSE);
872 		break;
873 	case SYSC_EVT_BD_PRESENT:
874 		if (sysc_stat->type == DISK_BOARD) {
875 			sysc_stat->rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
876 			sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
877 			sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
878 		} else {
879 			sysc_stat->rstate = SYSC_CFGA_RSTATE_CONNECTED;
880 			sysc_stat->ostate = SYSC_CFGA_OSTATE_CONFIGURED;
881 			sysc_stat->condition = SYSC_CFGA_COND_OK;
882 		}
883 		sysc_stat->last_change = gethrestime_sec();
884 		break;
885 	case SYSC_EVT_BD_DISABLED:
886 		sysc_stat->rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
887 		sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
888 		sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
889 		sysc_policy_disconnected_condition(softsp,
890 			sysc_stat, FALSE, FALSE);
891 		cmn_err(CE_NOTE,
892 			"disabled %s board in slot %d",
893 			fhc_bd_typestr(sysc_stat->type),
894 			sysc_stat->board);
895 		break;
896 	case SYSC_EVT_BD_FAILED:
897 		sysc_stat->rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
898 		sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
899 		sysc_stat->condition = SYSC_CFGA_COND_UNUSABLE;
900 		sysc_policy_disconnected_condition(softsp, sysc_stat,
901 			TRUE, FALSE);
902 		cmn_err(CE_WARN,
903 			"failed %s board in slot %d",
904 			fhc_bd_typestr(sysc_stat->type),
905 			sysc_stat->board);
906 		break;
907 	case SYSC_EVT_BD_OVERTEMP:
908 	case SYSC_EVT_BD_TEMP_OK:
909 		sysc_policy_set_condition((void *)softsp, sysc_stat, FALSE);
910 		break;
911 	case SYSC_EVT_BD_PS_CHANGE:
912 		for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) {
913 			sysc_stat = &(list->sc);
914 			sysc_policy_set_condition((void *)softsp,
915 				sysc_stat, TRUE);
916 		}
917 		break;
918 	case SYSC_EVT_BD_INS_FAILED:
919 		cmn_err(CE_WARN, "powerdown of board %d failed",
920 			sysc_stat->board);
921 		break;
922 	case SYSC_EVT_BD_INSERTED:
923 		sysc_stat->rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
924 		sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
925 		sysctrl_post_config_change(softsp);
926 		sysc_policy_disconnected_condition(softsp,
927 			sysc_stat, FALSE, FALSE);
928 		cmn_err(CE_NOTE, "%s board has been inserted into slot %d",
929 			fhc_bd_typestr(sysc_stat->type), sysc_stat->board);
930 		cmn_err(CE_NOTE,
931 			"board %d can be removed", sysc_stat->board);
932 		break;
933 	case SYSC_EVT_BD_REMOVED:
934 		sysc_stat->rstate = SYSC_CFGA_RSTATE_EMPTY;
935 		sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
936 		sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
937 
938 		/* now it is ok to free the ac pa memory database */
939 		fhc_del_memloc(sysc_stat->board);
940 
941 		/* reinitialize sysc_cfga_stat structure */
942 		sysc_stat->type = UNKNOWN_BOARD;
943 		sysc_stat->fhc_compid = 0;
944 		sysc_stat->ac_compid = 0;
945 		(void) bzero(&(sysc_stat->prom_rev),
946 			sizeof (sysc_stat->prom_rev));
947 		(void) bzero(&(sysc_stat->bd),
948 			sizeof (union bd_un));
949 		sysc_stat->no_detach = sysc_stat->plus_board = 0;
950 		sysc_policy_disconnected_condition(softsp,
951 			sysc_stat, FALSE, FALSE);
952 		cmn_err(CE_NOTE, "board %d has been removed",
953 			sysc_stat->board);
954 		break;
955 	case SYSC_EVT_BD_HP_DISABLED:
956 		cmn_err(CE_NOTE, "Hot Plug not supported in this system");
957 		break;
958 	case SYSC_EVT_BD_CORE_RESOURCE_DISCONNECT:
959 		cmn_err(CE_WARN, "board %d cannot be disconnected because it"
960 			" is a core system resource", sysc_stat->board);
961 		break;
962 	default:
963 		ASSERT(FALSE);
964 		break;
965 	}
966 
967 }
968 
969 /*
970  * signal to POST that the system has been reconfigured and that
971  * the system configuration status information should be invalidated
972  * the next time through POST
973  */
974 static void
975 sysctrl_post_config_change(struct sysctrl_soft_state *softsp)
976 {
977 	/*
978 	 * We are heading into a configuration change!
979 	 * Tell post to invalidate its notion of the system configuration.
980 	 * This is done by clearing the clock registers...
981 	 */
982 	*softsp->clk_freq1 = 0;
983 	*softsp->clk_freq2 &=
984 		~(CLOCK_FREQ_8 | CLOCK_DIV_1 | CLOCK_RANGE | CLOCK_DIV_0);
985 }
986 
987 static int
988 sysc_attach_board(void *arg)
989 {
990 	int board = *(int *)arg;
991 
992 	return (prom_sunfire_attach_board((uint_t)board));
993 }
994 
995 static int
996 sysc_bd_connect(int board, sysc_cfga_pkt_t *pkt)
997 {
998 	int error = 0;
999 	fhc_bd_t *bdp;
1000 	sysc_dr_handle_t *sh;
1001 	uint64_t mempa;
1002 	int del_kstat = 0;
1003 
1004 	ASSERT(fhc_bd_busy(board));
1005 
1006 	bdp = fhc_bd(board);
1007 
1008 	/* find gap for largest supported simm in advance */
1009 #define	MAX_BANK_SIZE_MB	(2 * 1024)
1010 #define	BANKS_PER_BOARD		2
1011 	mempa = fhc_find_memloc_gap(BANKS_PER_BOARD * MAX_BANK_SIZE_MB);
1012 
1013 	fhc_bdlist_unlock();
1014 
1015 	/* TODO: Is mempa vulnerable to re-use here? */
1016 
1017 	sysctrl_suspend_prepare();
1018 
1019 	if ((error = sysctrl_suspend(pkt)) == DDI_SUCCESS) {
1020 		/* ASSERT(jtag not held) */
1021 		error = prom_tree_update(sysc_attach_board, &board);
1022 		if (error) {
1023 			error = EIO;
1024 			SYSC_ERR_SET(pkt, SYSC_ERR_PROM);
1025 		} else {
1026 			/* attempt to program the memory while frozen */
1027 			fhc_program_memory(board, mempa);
1028 		}
1029 		sysctrl_resume(pkt);
1030 	}
1031 
1032 	if (error) {
1033 		goto done;
1034 	}
1035 
1036 	/*
1037 	 * Must not delete kstat used by prtdiag until the PROM
1038 	 * has successfully connected to board.
1039 	 */
1040 	del_kstat = 1;
1041 
1042 	sh = &bdp->sh[SYSC_DR_HANDLE_FHC];
1043 	sh->flags |= SYSC_DR_FHC;
1044 	sh->errstr = pkt->errbuf;
1045 
1046 	sysc_dr_init(sh);
1047 
1048 	error = sysc_dr_attach(sh, board);
1049 	if (error)
1050 		SYSC_ERR_SET(pkt, SYSC_ERR_NDI_ATTACH);
1051 
1052 	sysc_dr_uninit(sh);
1053 
1054 	if (enable_redist) {
1055 		mutex_enter(&cpu_lock);
1056 		intr_redist_all_cpus();
1057 		mutex_exit(&cpu_lock);
1058 	}
1059 done:
1060 	if (del_kstat && bdp->ksp) {
1061 		kstat_delete(bdp->ksp);
1062 		bdp->ksp = NULL;
1063 	}
1064 
1065 	(void) fhc_bdlist_lock(-1);
1066 
1067 	return (error);
1068 }
1069 
1070 static int
1071 sysc_detach_board(void * arg)
1072 {
1073 	int rt;
1074 	cpuset_t xcset;
1075 	struct jt_mstr *jtm;
1076 	int board = *(int *)arg;
1077 
1078 	(void) fhc_bdlist_lock(-1);
1079 
1080 #ifdef DEBUG
1081 	/* it is important to have fhc_bdlist_lock() earlier */
1082 	if (sysctrl_enable_regdump)
1083 		precache_regdump(board);
1084 #endif /* DEBUG */
1085 
1086 	jtm = jtag_master_lock();
1087 	CPUSET_ALL(xcset);
1088 	promsafe_xc_attention(xcset);
1089 
1090 #ifdef DEBUG
1091 	if (sysctrl_enable_regdump)
1092 		boardstat_regdump();
1093 #endif /* DEBUG */
1094 
1095 	rt =  prom_sunfire_detach_board((uint_t)board);
1096 
1097 #ifdef DEBUG
1098 	if (sysctrl_enable_regdump)
1099 		display_regdump();
1100 #endif /* DEBUG */
1101 
1102 	xc_dismissed(xcset);
1103 	jtag_master_unlock(jtm);
1104 	fhc_bdlist_unlock();
1105 	return (rt);
1106 }
1107 
1108 static int
1109 sysc_bd_disconnect(int board, sysc_cfga_pkt_t *pkt)
1110 {
1111 	int error;
1112 	fhc_bd_t *bdp;
1113 	sysc_dr_handle_t *sh;
1114 	void fhc_bd_ks_alloc(fhc_bd_t *);
1115 
1116 	ASSERT(fhc_bd_busy(board));
1117 	ASSERT(!fhc_bd_is_jtag_master(board));
1118 
1119 
1120 	bdp = fhc_bd(board);
1121 
1122 	bdp->flags |= BDF_DETACH;
1123 
1124 	fhc_bdlist_unlock();
1125 
1126 	sh = &bdp->sh[SYSC_DR_HANDLE_FHC];
1127 	sh->errstr = pkt->errbuf;
1128 
1129 	ASSERT(sh->dip_list == NULL);
1130 
1131 	sh->flags |= SYSC_DR_FHC;
1132 	sysc_dr_init(sh);
1133 
1134 	error = sysc_dr_detach(sh, board);
1135 	sh->flags &= ~SYSC_DR_REMOVE;
1136 
1137 	sysc_dr_uninit(sh);
1138 	if (error) {
1139 		SYSC_ERR_SET(pkt, SYSC_ERR_NDI_DETACH);
1140 		goto done;
1141 	}
1142 	error = prom_tree_update(sysc_detach_board, &board);
1143 
1144 	if (error) {
1145 		error = EIO;
1146 		SYSC_ERR_SET(pkt, SYSC_ERR_PROM);
1147 		goto done;
1148 	}
1149 
1150 	if (enable_redist) {
1151 		mutex_enter(&cpu_lock);
1152 		intr_redist_all_cpus();
1153 		mutex_exit(&cpu_lock);
1154 	}
1155 
1156 	fhc_bd_ks_alloc(bdp);
1157 done:
1158 	(void) fhc_bdlist_lock(-1);
1159 
1160 	return (error);
1161 }
1162 
1163 static int
1164 sysc_bd_configure(int board, sysc_cfga_pkt_t *pkt)
1165 {
1166 	int error = 0;
1167 	fhc_bd_t *bdp;
1168 	sysc_dr_handle_t *sh;
1169 
1170 	ASSERT(fhc_bd_busy(board));
1171 
1172 	bdp = fhc_bd(board);
1173 
1174 	fhc_bdlist_unlock();
1175 
1176 
1177 	sh = &bdp->sh[SYSC_DR_HANDLE_DEVS];
1178 	sh->errstr = pkt->errbuf;
1179 
1180 	ASSERT(sh->dip_list == NULL);
1181 
1182 	sysc_dr_init(sh);
1183 
1184 	sh->flags |= SYSC_DR_DEVS;
1185 	error = sysc_dr_attach(sh, board);
1186 	if (error) {
1187 		SYSC_ERR_SET(pkt, SYSC_ERR_NDI_ATTACH);
1188 		sysc_dr_uninit(sh);
1189 		goto done;
1190 	}
1191 
1192 	sysc_dr_uninit(sh);
1193 
1194 	if (enable_redist) {
1195 		mutex_enter(&cpu_lock);
1196 		intr_redist_all_cpus();
1197 		mutex_exit(&cpu_lock);
1198 	}
1199 done:
1200 	if (bdp->sc.type == CPU_BOARD) {
1201 		/*
1202 		 * Value of error gets lost for CPU boards.
1203 		 */
1204 		mutex_enter(&cpu_lock);
1205 
1206 		error = find_and_setup_cpu(FHC_BOARD2CPU_A(board));
1207 		if ((error == 0) || (error == ENODEV)) {
1208 			int retval_b;
1209 
1210 			retval_b = find_and_setup_cpu(FHC_BOARD2CPU_B(board));
1211 			if (retval_b != ENODEV)
1212 				error = retval_b;
1213 		}
1214 
1215 		mutex_exit(&cpu_lock);
1216 	}
1217 
1218 	(void) fhc_bdlist_lock(-1);
1219 
1220 	return (error);
1221 }
1222 
1223 static int
1224 sysc_bd_unconfigure(int board, sysc_cfga_pkt_t *pkt)
1225 {
1226 	int error;
1227 	fhc_bd_t *bdp;
1228 	sysc_dr_handle_t *sh;
1229 
1230 	ASSERT(fhc_bdlist_locked());
1231 	ASSERT(fhc_bd_busy(board));
1232 
1233 	bdp = fhc_bd(board);
1234 
1235 	if (bdp->sc.type == CPU_BOARD || bdp->sc.type == MEM_BOARD) {
1236 		struct ac_soft_state *acsp;
1237 
1238 		/*
1239 		 * Check that any memory on board is not in use.
1240 		 * This must be done while the board list lock is held
1241 		 * as memory state can change while fhc_bd_busy() is true
1242 		 * even though a memory operation cannot be started
1243 		 * if fhc_bd_busy() is true.
1244 		 */
1245 		if ((acsp = (struct ac_soft_state *)bdp->ac_softsp) != NULL) {
1246 			if (acsp->bank[Bank0].busy != 0 ||
1247 			    acsp->bank[Bank0].ostate ==
1248 			    SYSC_CFGA_OSTATE_CONFIGURED) {
1249 				cmn_err(CE_WARN, "memory bank %d in "
1250 				    "slot %d is in use.", Bank0, board);
1251 				(void) snprintf(pkt->errbuf,
1252 				    SYSC_OUTPUT_LEN,
1253 				    "memory bank %d in use",
1254 				    Bank0);
1255 				return (EBUSY);
1256 			}
1257 
1258 			if (acsp->bank[Bank1].busy != 0 ||
1259 			    acsp->bank[Bank1].ostate ==
1260 			    SYSC_CFGA_OSTATE_CONFIGURED) {
1261 				cmn_err(CE_WARN, "memory bank %d in "
1262 				    "slot %d is in use.", Bank1, board);
1263 				(void) snprintf(pkt->errbuf,
1264 				    SYSC_OUTPUT_LEN,
1265 				    "memory bank %d in use",
1266 				    Bank1);
1267 				return (EBUSY);
1268 			}
1269 			/*
1270 			 * Nothing more to do here. The memory interface
1271 			 * will not make any transitions while
1272 			 * fhc_bd_busy() is true. Once the ostate
1273 			 * becomes unconfigured, the memory becomes
1274 			 * invisible.
1275 			 */
1276 		}
1277 		error = 0;
1278 		if (bdp->sc.type == CPU_BOARD) {
1279 			struct cpu *cpua, *cpub;
1280 			int cpu_flags = 0;
1281 
1282 			if (pkt->cmd_cfga.force)
1283 				cpu_flags = CPU_FORCED;
1284 
1285 			fhc_bdlist_unlock();
1286 
1287 			mutex_enter(&cpu_lock);	/* protects CPU states */
1288 
1289 			error = fhc_board_poweroffcpus(board, pkt->errbuf,
1290 			    cpu_flags);
1291 
1292 			cpua = cpu_get(FHC_BOARD2CPU_A(board));
1293 			cpub = cpu_get(FHC_BOARD2CPU_B(board));
1294 
1295 			if ((error == 0) && (cpua != NULL)) {
1296 				error = cpu_unconfigure(cpua->cpu_id);
1297 				if (error != 0) {
1298 					(void) snprintf(pkt->errbuf,
1299 					    SYSC_OUTPUT_LEN,
1300 					    "processor %d unconfigure failed",
1301 					    cpua->cpu_id);
1302 				}
1303 			}
1304 			if ((error == 0) && (cpub != NULL)) {
1305 				error = cpu_unconfigure(cpub->cpu_id);
1306 				if (error != 0) {
1307 					(void) snprintf(pkt->errbuf,
1308 					    SYSC_OUTPUT_LEN,
1309 					    "processor %d unconfigure failed",
1310 					    cpub->cpu_id);
1311 				}
1312 			}
1313 
1314 			mutex_exit(&cpu_lock);
1315 
1316 			(void) fhc_bdlist_lock(-1);
1317 		}
1318 
1319 		if (error != 0)
1320 			return (error);
1321 	}
1322 
1323 	fhc_bdlist_unlock();
1324 
1325 	sh = &bdp->sh[SYSC_DR_HANDLE_DEVS];
1326 	sh->errstr = pkt->errbuf;
1327 
1328 	ASSERT(sh->dip_list == NULL);
1329 
1330 	sysc_dr_init(sh);
1331 
1332 	sh->flags |= SYSC_DR_DEVS;
1333 	error = sysc_dr_detach(sh, board);
1334 	sh->flags &= ~SYSC_DR_REMOVE;
1335 	if (error) {
1336 		SYSC_ERR_SET(pkt, SYSC_ERR_NDI_DETACH);
1337 		sysc_dr_uninit(sh);
1338 		goto done;
1339 	}
1340 
1341 	sysc_dr_uninit(sh);
1342 
1343 	if (enable_redist) {
1344 		mutex_enter(&cpu_lock);
1345 		intr_redist_all_cpus();
1346 		mutex_exit(&cpu_lock);
1347 	}
1348 
1349 done:
1350 	(void) fhc_bdlist_lock(-1);
1351 
1352 	return (error);
1353 }
1354 
1355 
1356 typedef struct sysc_prom {
1357 	sysc_dr_handle_t *handle;	/* DR handle			*/
1358 	int board;			/* board id			*/
1359 	dev_info_t **dipp;		/* next slot for storing dip	*/
1360 } sysc_prom_t;
1361 
1362 /*
1363  * Attaching devices on a board.
1364  */
1365 static int
1366 sysc_dr_attach(sysc_dr_handle_t  *handle, int board)
1367 {
1368 	int			i;
1369 	int			err;
1370 	sysc_prom_t		arg;
1371 	devi_branch_t		b = {0};
1372 
1373 	arg.handle = handle;
1374 	arg.board = board;
1375 	arg.dipp = handle->dip_list;
1376 
1377 	b.arg = &arg;
1378 	b.type = DEVI_BRANCH_PROM;
1379 	b.create.prom_branch_select = sysc_prom_select;
1380 	b.devi_branch_callback = sysc_branch_callback;
1381 
1382 	handle->error = e_ddi_branch_create(ddi_root_node(), &b,
1383 	    NULL, DEVI_BRANCH_CHILD);
1384 
1385 	if (handle->error)
1386 		return (handle->error);
1387 
1388 	for (i = 0, arg.dipp = handle->dip_list;
1389 	    i < handle->dip_list_len; i++, arg.dipp++) {
1390 
1391 		err = e_ddi_branch_configure(*arg.dipp, NULL, 0);
1392 		/*
1393 		 * Error only if we fail for fhc dips
1394 		 */
1395 		if (err && (handle->flags & SYSC_DR_FHC)) {
1396 			handle->error = err;
1397 			sysc_dr_err_decode(handle, *arg.dipp, TRUE);
1398 			return (handle->error);
1399 		}
1400 	}
1401 
1402 	return (0);
1403 }
1404 
1405 /*ARGSUSED*/
1406 static int
1407 sysc_make_list(void *arg, int has_changed)
1408 {
1409 	dev_info_t *rdip;
1410 	sysc_prom_t *wp = (sysc_prom_t *)arg;
1411 	pnode_t nid = prom_childnode(prom_rootnode());
1412 
1413 	if (wp == NULL)
1414 		return (EINVAL);
1415 
1416 	for (; nid != OBP_NONODE && nid != OBP_BADNODE;
1417 	    nid = prom_nextnode(nid)) {
1418 		if (sysc_prom_select(nid, arg, 0) != DDI_SUCCESS)
1419 			continue;
1420 		if (wp->handle->dip_list_len < SYSC_DR_MAX_NODE) {
1421 			rdip = wp->handle->dip_list[wp->handle->dip_list_len] =
1422 			    e_ddi_nodeid_to_dip(nid);
1423 			if (rdip != NULL) {
1424 				wp->handle->dip_list_len++;
1425 				/*
1426 				 * Branch rooted at dip already held, so
1427 				 * release hold acquired in e_ddi_nodeid_to_dip
1428 				 */
1429 				ddi_release_devi(rdip);
1430 				ASSERT(e_ddi_branch_held(rdip));
1431 #ifdef	DEBUG
1432 			} else {
1433 				DPRINTF(SYSC_DEBUG, ("sysc_make_list:"
1434 				    " e_ddi_nodeid_to_dip() failed for"
1435 				    " nodeid: %d\n", nid));
1436 #endif
1437 			}
1438 		} else {
1439 #ifdef	DEBUG
1440 			cmn_err(CE_WARN, "sysc_make_list: list overflow\n");
1441 #endif
1442 			return (EFAULT);
1443 		}
1444 	}
1445 
1446 	return (0);
1447 }
1448 
1449 /*
1450  * Detaching devices on a board.
1451  */
1452 static int
1453 sysc_dr_detach(sysc_dr_handle_t *handle, int board)
1454 {
1455 	int		i;
1456 	uint_t		flags;
1457 	sysc_prom_t	arg;
1458 
1459 	ASSERT(handle->dip_list);
1460 	ASSERT(handle->dip_list_len == 0);
1461 	ASSERT(*handle->dip_list == NULL);
1462 
1463 	arg.handle = handle;
1464 	arg.board = board;
1465 	arg.dipp = NULL;
1466 
1467 	handle->error = prom_tree_access(sysc_make_list, &arg, NULL);
1468 	if (handle->error)
1469 		return (handle->error);
1470 
1471 	flags = DEVI_BRANCH_DESTROY | DEVI_BRANCH_EVENT;
1472 
1473 	for (i = handle->dip_list_len; i > 0; i--) {
1474 		ASSERT(e_ddi_branch_held(handle->dip_list[i - 1]));
1475 		handle->error = e_ddi_branch_unconfigure(
1476 		    handle->dip_list[i - 1], NULL, flags);
1477 		if (handle->error)
1478 			return (handle->error);
1479 	}
1480 
1481 	return (0);
1482 }
1483 
1484 static void
1485 sysc_dr_init(sysc_dr_handle_t *handle)
1486 {
1487 	handle->dip_list = kmem_zalloc(sizeof (dev_info_t *) * SYSC_DR_MAX_NODE,
1488 	    KM_SLEEP);
1489 	handle->dip_list_len = 0;
1490 }
1491 
1492 /*ARGSUSED2*/
1493 static int
1494 sysc_prom_select(pnode_t pnode, void *arg, uint_t flag)
1495 {
1496 	int		bd_id;
1497 	char		name[OBP_MAXDRVNAME];
1498 	int		len;
1499 	int		*regp;
1500 	sysc_prom_t	*wp = (sysc_prom_t *)arg;
1501 
1502 	bd_id = -1;
1503 	len = prom_getproplen(pnode, OBP_REG);
1504 	if (len > 0) {
1505 		regp = kmem_alloc(len, KM_SLEEP);
1506 		(void) prom_getprop(pnode, OBP_REG, (caddr_t)regp);
1507 		/*
1508 		 * Get board id for EXXXX platforms where
1509 		 * 0x1c0 is EXXXX platform specific data to
1510 		 * acquire board id.
1511 		 */
1512 		bd_id = (*regp - 0x1c0) >> 2;
1513 		kmem_free(regp, len);
1514 	}
1515 
1516 	(void) prom_getprop(pnode, OBP_NAME, (caddr_t)name);
1517 	if ((bd_id == wp->board) &&
1518 	    ((wp->handle->flags & SYSC_DR_FHC) ?
1519 	    (strcmp(name, "fhc") == 0):
1520 	    (strcmp(name, "fhc") != 0)) &&
1521 	    (strcmp(name, "central") != 0)) {
1522 		return (DDI_SUCCESS);
1523 	}
1524 
1525 	return (DDI_FAILURE);
1526 }
1527 
1528 /*ARGSUSED*/
1529 static void
1530 sysc_branch_callback(dev_info_t *rdip, void *arg, uint_t flags)
1531 {
1532 	sysc_prom_t *wp = (sysc_prom_t *)arg;
1533 
1534 	ASSERT(wp->dipp != NULL);
1535 	ASSERT(*wp->dipp == NULL);
1536 	ASSERT((wp->handle->flags & SYSC_DR_REMOVE) == 0);
1537 
1538 	if (wp->handle->dip_list_len < SYSC_DR_MAX_NODE) {
1539 		*wp->dipp = rdip;
1540 		wp->dipp++;
1541 		wp->handle->dip_list_len++;
1542 	} else {
1543 		cmn_err(CE_PANIC, "sysc_branch_callback: list overflow");
1544 	}
1545 }
1546 
1547 /*
1548  * Uninitialize devices for the state of a board.
1549  */
1550 static void
1551 sysc_dr_uninit(sysc_dr_handle_t *handle)
1552 {
1553 	kmem_free(handle->dip_list,
1554 	    sizeof (dev_info_t *) * SYSC_DR_MAX_NODE);
1555 	handle->dip_list = NULL;
1556 	handle->dip_list_len = 0;
1557 }
1558 
1559 static void
1560 sysc_dr_err_decode(sysc_dr_handle_t *handle, dev_info_t *dip, int attach)
1561 {
1562 	char	*p;
1563 
1564 	ASSERT(handle->error != 0);
1565 
1566 	switch (handle->error) {
1567 	case ENOMEM:
1568 		break;
1569 	case EBUSY:
1570 		(void) ddi_pathname(dip, handle->errstr);
1571 		break;
1572 	default:
1573 		handle->error = EFAULT;
1574 		if (attach)
1575 			(void) ddi_pathname(ddi_get_parent(dip),
1576 			    handle->errstr);
1577 		else
1578 			(void) ddi_pathname(dip, handle->errstr);
1579 		if (attach) {
1580 			p = "/";
1581 			(void) strcat(handle->errstr, p);
1582 			(void) strcat(handle->errstr, ddi_node_name(dip));
1583 		}
1584 		break;
1585 	}
1586 }
1587 
1588 static char *
1589 sysc_rstate_typestr(sysc_cfga_rstate_t rstate, sysc_audit_evt_t event)
1590 {
1591 	char *type_str;
1592 
1593 	switch (rstate) {
1594 	case SYSC_CFGA_RSTATE_EMPTY:
1595 		switch (event) {
1596 		case SYSC_AUDIT_RSTATE_EMPTY:
1597 			type_str = "emptying";
1598 			break;
1599 		case SYSC_AUDIT_RSTATE_SUCCEEDED:
1600 			type_str = "emptied";
1601 			break;
1602 		case SYSC_AUDIT_RSTATE_EMPTY_FAILED:
1603 			type_str = "empty";
1604 			break;
1605 		default:
1606 			type_str = "empty?";
1607 			break;
1608 		}
1609 		break;
1610 	case SYSC_CFGA_RSTATE_DISCONNECTED:
1611 		switch (event) {
1612 		case SYSC_AUDIT_RSTATE_DISCONNECT:
1613 			type_str = "disconnecting";
1614 			break;
1615 		case SYSC_AUDIT_RSTATE_SUCCEEDED:
1616 			type_str = "disconnected";
1617 			break;
1618 		case SYSC_AUDIT_RSTATE_DISCONNECT_FAILED:
1619 			type_str = "disconnect";
1620 			break;
1621 		default:
1622 			type_str = "disconnect?";
1623 			break;
1624 		}
1625 		break;
1626 	case SYSC_CFGA_RSTATE_CONNECTED:
1627 		switch (event) {
1628 		case SYSC_AUDIT_RSTATE_CONNECT:
1629 			type_str = "connecting";
1630 			break;
1631 		case SYSC_AUDIT_RSTATE_SUCCEEDED:
1632 			type_str = "connected";
1633 			break;
1634 		case SYSC_AUDIT_RSTATE_CONNECT_FAILED:
1635 			type_str = "connect";
1636 			break;
1637 		default:
1638 			type_str = "connect?";
1639 			break;
1640 		}
1641 		break;
1642 	default:
1643 		type_str = "undefined receptacle state";
1644 		break;
1645 	}
1646 	return (type_str);
1647 }
1648 
1649 static char *
1650 sysc_ostate_typestr(sysc_cfga_ostate_t ostate, sysc_audit_evt_t event)
1651 {
1652 	char *type_str;
1653 
1654 	switch (ostate) {
1655 	case SYSC_CFGA_OSTATE_UNCONFIGURED:
1656 		switch (event) {
1657 		case SYSC_AUDIT_OSTATE_UNCONFIGURE:
1658 			type_str = "unconfiguring";
1659 			break;
1660 		case SYSC_AUDIT_OSTATE_SUCCEEDED:
1661 		case SYSC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
1662 			type_str = "unconfigured";
1663 			break;
1664 		default:
1665 			type_str = "unconfigure?";
1666 			break;
1667 		}
1668 		break;
1669 	case SYSC_CFGA_OSTATE_CONFIGURED:
1670 		switch (event) {
1671 		case SYSC_AUDIT_OSTATE_CONFIGURE:
1672 			type_str = "configuring";
1673 			break;
1674 		case SYSC_AUDIT_OSTATE_SUCCEEDED:
1675 		case SYSC_AUDIT_OSTATE_CONFIGURE_FAILED:
1676 			type_str = "configured";
1677 			break;
1678 		default:
1679 			type_str = "configure?";
1680 			break;
1681 		}
1682 		break;
1683 
1684 	default:
1685 		type_str = "undefined occupant state";
1686 		break;
1687 	}
1688 	return (type_str);
1689 }
1690 
1691 static void
1692 sysc_policy_audit_messages(sysc_audit_evt_t event, sysc_cfga_stat_t *sysc_stat)
1693 {
1694 	switch (event) {
1695 		case SYSC_AUDIT_RSTATE_CONNECT:
1696 			cmn_err(CE_NOTE,
1697 				"%s %s board in slot %d",
1698 				sysc_rstate_typestr(SYSC_CFGA_RSTATE_CONNECTED,
1699 				event),
1700 				fhc_bd_typestr(sysc_stat->type),
1701 				sysc_stat->board);
1702 			break;
1703 		case SYSC_AUDIT_RSTATE_DISCONNECT:
1704 			cmn_err(CE_NOTE,
1705 				"%s %s board in slot %d",
1706 				sysc_rstate_typestr(
1707 					SYSC_CFGA_RSTATE_DISCONNECTED,
1708 					event),
1709 				fhc_bd_typestr(sysc_stat->type),
1710 				sysc_stat->board);
1711 			break;
1712 		case SYSC_AUDIT_RSTATE_SUCCEEDED:
1713 			cmn_err(CE_NOTE,
1714 				"%s board in slot %d is %s",
1715 				fhc_bd_typestr(sysc_stat->type),
1716 				sysc_stat->board,
1717 				sysc_rstate_typestr(sysc_stat->rstate,
1718 					event));
1719 			break;
1720 		case SYSC_AUDIT_RSTATE_CONNECT_FAILED:
1721 			cmn_err(CE_NOTE,
1722 				"%s board in slot %d failed to %s",
1723 				fhc_bd_typestr(sysc_stat->type),
1724 				sysc_stat->board,
1725 				sysc_rstate_typestr(SYSC_CFGA_RSTATE_CONNECTED,
1726 					event));
1727 			break;
1728 		case SYSC_AUDIT_RSTATE_DISCONNECT_FAILED:
1729 			cmn_err(CE_NOTE,
1730 				"%s board in slot %d failed to %s",
1731 				fhc_bd_typestr(sysc_stat->type),
1732 				sysc_stat->board,
1733 				sysc_rstate_typestr(
1734 					SYSC_CFGA_RSTATE_DISCONNECTED,
1735 					event));
1736 			break;
1737 		case SYSC_AUDIT_OSTATE_CONFIGURE:
1738 			cmn_err(CE_NOTE,
1739 				"%s %s board in slot %d",
1740 				sysc_ostate_typestr(SYSC_CFGA_OSTATE_CONFIGURED,
1741 				event),
1742 				fhc_bd_typestr(sysc_stat->type),
1743 				sysc_stat->board);
1744 			break;
1745 		case SYSC_AUDIT_OSTATE_UNCONFIGURE:
1746 			cmn_err(CE_NOTE,
1747 				"%s %s board in slot %d",
1748 				sysc_ostate_typestr(
1749 					SYSC_CFGA_OSTATE_UNCONFIGURED,
1750 					event),
1751 				fhc_bd_typestr(sysc_stat->type),
1752 				sysc_stat->board);
1753 			break;
1754 		case SYSC_AUDIT_OSTATE_SUCCEEDED:
1755 			cmn_err(CE_NOTE,
1756 				"%s board in slot %d is %s",
1757 				fhc_bd_typestr(sysc_stat->type),
1758 				sysc_stat->board,
1759 				sysc_ostate_typestr(sysc_stat->ostate,
1760 					event));
1761 			break;
1762 		case SYSC_AUDIT_OSTATE_CONFIGURE_FAILED:
1763 			cmn_err(CE_NOTE,
1764 				"%s board in slot %d partially %s",
1765 				fhc_bd_typestr(sysc_stat->type),
1766 				sysc_stat->board,
1767 				sysc_ostate_typestr(
1768 					SYSC_CFGA_OSTATE_CONFIGURED,
1769 					event));
1770 			break;
1771 		case SYSC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
1772 			cmn_err(CE_NOTE,
1773 				"%s board in slot %d partially %s",
1774 				fhc_bd_typestr(sysc_stat->type),
1775 				sysc_stat->board,
1776 				sysc_ostate_typestr(
1777 					SYSC_CFGA_OSTATE_UNCONFIGURED,
1778 					event));
1779 			break;
1780 		default:
1781 			cmn_err(CE_NOTE,
1782 				"unknown audit of a %s %s board in"
1783 				" slot %d",
1784 				sysc_rstate_typestr(sysc_stat->rstate,
1785 					event),
1786 				fhc_bd_typestr(sysc_stat->type),
1787 				sysc_stat->board);
1788 			break;
1789 	}
1790 }
1791 
1792 #define	MAX_PROP_LEN	33	/* must be > strlen("cpu") */
1793 
1794 static int
1795 find_and_setup_cpu(int cpuid)
1796 {
1797 	return (prom_tree_access(find_and_setup_cpu_start, &cpuid, NULL));
1798 }
1799 
1800 /* ARGSUSED */
1801 static int
1802 find_and_setup_cpu_start(void *cpuid_arg, int has_changed)
1803 {
1804 	pnode_t nodeid;
1805 	int upaid;
1806 	char type[MAX_PROP_LEN];
1807 	int cpuid = *(int *)cpuid_arg;
1808 
1809 	nodeid = prom_childnode(prom_rootnode());
1810 	while (nodeid != OBP_NONODE) {
1811 		if (prom_getproplen(nodeid, "device_type") < MAX_PROP_LEN)
1812 			(void) prom_getprop(nodeid, "device_type",
1813 			    (caddr_t)type);
1814 		else
1815 			type[0] = '\0';
1816 		(void) prom_getprop(nodeid, "upa-portid", (caddr_t)&upaid);
1817 		if ((strcmp(type, "cpu") == 0) && (upaid == cpuid)) {
1818 			return (cpu_configure(cpuid));
1819 		}
1820 		nodeid = prom_nextnode(nodeid);
1821 	}
1822 	return (ENODEV);
1823 }
1824 
1825 #define	MAX_BOARD_TYPE	IO_SBUS_FFB_SOCPLUS_BOARD
1826 
1827 static char sysc_supp_conn[MAX_BOARD_TYPE + 1];
1828 
1829 static int
1830 sysc_board_connect_supported(enum board_type type)
1831 {
1832 	if (type > MAX_BOARD_TYPE)
1833 		return (0);
1834 	return (sysc_supp_conn[type]);
1835 }
1836 
1837 void
1838 sysc_board_connect_supported_init(void)
1839 {
1840 	pnode_t openprom_node;
1841 	char sup_list[16];
1842 	int proplen;
1843 	int i;
1844 	char tstr[3 * 5 + 1];
1845 
1846 	/* Check the firmware for Dynamic Reconfiguration support */
1847 	if (prom_test("SUNW,Ultra-Enterprise,rm-brd") != 0) {
1848 		/* The message was printed in platmod:set_platform_defaults */
1849 		enable_dynamic_reconfiguration = 0;
1850 	}
1851 
1852 	openprom_node = prom_finddevice("/openprom");
1853 	if (openprom_node != OBP_BADNODE) {
1854 		proplen = prom_bounded_getprop(openprom_node,
1855 		    "add-brd-supported-types",
1856 		    sup_list, sizeof (sup_list) - 1);
1857 	} else {
1858 		proplen = -1;
1859 	}
1860 
1861 	if (proplen < 0) {
1862 		/*
1863 		 * This is an old prom which may cause a fatal reset,
1864 		 * so don't allow any DR operations.
1865 		 * If enable_dynamic_reconfiguration is 0
1866 		 * we have already printed a similar message.
1867 		 */
1868 		if (enable_dynamic_reconfiguration) {
1869 			cmn_err(CE_WARN, "Firmware does not support"
1870 			    " Dynamic Reconfiguration");
1871 			enable_dynamic_reconfiguration = 0;
1872 		}
1873 		return;
1874 	}
1875 	for (i = 0; i < proplen; i++) {
1876 		switch (sup_list[i]) {
1877 		case '0':
1878 			sysc_supp_conn[CPU_BOARD] = 1;
1879 			sysc_supp_conn[MEM_BOARD] = 1;
1880 			break;
1881 		case '1':
1882 			sysc_supp_conn[IO_2SBUS_BOARD] = 1;
1883 			break;
1884 		case '2':
1885 			sysc_supp_conn[IO_SBUS_FFB_BOARD] = 1;
1886 			break;
1887 		case '3':
1888 			sysc_supp_conn[IO_PCI_BOARD] = 1;
1889 			break;
1890 		case '4':
1891 			sysc_supp_conn[IO_2SBUS_SOCPLUS_BOARD] = 1;
1892 			break;
1893 		case '5':
1894 			sysc_supp_conn[IO_SBUS_FFB_SOCPLUS_BOARD] = 1;
1895 			break;
1896 		default:
1897 			/* Ignore other characters. */
1898 			break;
1899 		}
1900 	}
1901 	if (sysc_supp_conn[CPU_BOARD]) {
1902 		cmn_err(CE_NOTE, "!Firmware supports Dynamic Reconfiguration"
1903 		    " of CPU/Memory boards.");
1904 	} else {
1905 		cmn_err(CE_NOTE, "Firmware does not support Dynamic"
1906 		    " Reconfiguration of CPU/Memory boards.");
1907 	}
1908 
1909 	tstr[0] = '\0';
1910 	if (sysc_supp_conn[IO_2SBUS_BOARD])
1911 		(void) strcat(tstr, ", 1");
1912 	if (sysc_supp_conn[IO_SBUS_FFB_BOARD])
1913 		(void) strcat(tstr, ", 2");
1914 	if (sysc_supp_conn[IO_PCI_BOARD])
1915 		(void) strcat(tstr, ", 3");
1916 	if (sysc_supp_conn[IO_2SBUS_SOCPLUS_BOARD])
1917 		(void) strcat(tstr, ", 4");
1918 	if (sysc_supp_conn[IO_SBUS_FFB_SOCPLUS_BOARD])
1919 		(void) strcat(tstr, ", 5");
1920 	if (tstr[0] != '\0') {
1921 		/* Skip leading ", " using &tstr[2]. */
1922 		cmn_err(CE_NOTE, "!Firmware supports Dynamic Reconfiguration"
1923 		    " of I/O board types %s.", &tstr[2]);
1924 	} else {
1925 		cmn_err(CE_NOTE, "Firmware does not support Dynamic"
1926 		    " Reconfiguration of I/O boards.");
1927 	}
1928 }
1929 
1930 #ifdef DEBUG
1931 
1932 static void
1933 precache_regdump(int board)
1934 {
1935 	fhc_bd_t *curr_bdp;
1936 	int bd_idx;
1937 	int reg_idx;
1938 
1939 	for (bd_idx = 0; bd_idx < fhc_max_boards(); bd_idx++) {
1940 		bcopy((void *) reg_tmpl, (void *) &reg_dt[bd_idx][0],
1941 		    (sizeof (struct regs_data))*NUM_REG);
1942 		curr_bdp = fhc_bd(bd_idx);
1943 		if (curr_bdp->sc.rstate == SYSC_CFGA_RSTATE_CONNECTED) {
1944 			for (reg_idx = 0; reg_idx < NUM_REG; reg_idx++) {
1945 				reg_dt[bd_idx][reg_idx].eflag = TRUE;
1946 				if (bd_idx != board)
1947 					reg_dt[bd_idx][reg_idx].oflag = TRUE;
1948 				reg_dt[bd_idx][reg_idx].physaddr +=
1949 				    (FHC_BOARD_SPAN*2*bd_idx);
1950 				reg_dt[bd_idx][reg_idx].pre_dsct =
1951 				    ldphysio(reg_dt[bd_idx][reg_idx].physaddr);
1952 			}
1953 		}
1954 	}
1955 
1956 
1957 }
1958 
1959 static void
1960 boardstat_regdump(void)
1961 {
1962 	int bd_idx;
1963 
1964 	prom_printf("\nBoard status before disconnect.\n");
1965 	for (bd_idx = 0; bd_idx < fhc_max_boards(); bd_idx++) {
1966 		if (reg_dt[bd_idx][0].eflag == 0) {
1967 			prom_printf("Board #%d is idle.\n", bd_idx);
1968 		} else {
1969 			prom_printf("Board #%d is on.\n", bd_idx);
1970 		}
1971 	}
1972 
1973 	for (bd_idx = 0; bd_idx < fhc_max_boards(); bd_idx++) {
1974 		if (reg_dt[bd_idx][0].eflag) {
1975 			prom_printf("\nRegisters for Board #%d", bd_idx);
1976 			prom_printf(" (before disconnect).\n");
1977 			prom_printf("AC_BCSR   FHC_CTRL  JTAG      IGN   SIM"
1978 			    "       SISM  UIM       USM\n");
1979 			prom_printf("%08x  %08x  %08x  %04x"
1980 			    "  %08x  %04x  %08x  %04x\n",
1981 			    reg_dt[bd_idx][0].pre_dsct,
1982 			    reg_dt[bd_idx][1].pre_dsct,
1983 			    reg_dt[bd_idx][2].pre_dsct,
1984 			    reg_dt[bd_idx][3].pre_dsct,
1985 			    reg_dt[bd_idx][4].pre_dsct,
1986 			    reg_dt[bd_idx][5].pre_dsct,
1987 			    reg_dt[bd_idx][6].pre_dsct,
1988 			    reg_dt[bd_idx][7].pre_dsct);
1989 		}
1990 	}
1991 
1992 }
1993 
1994 static void
1995 display_regdump(void)
1996 {
1997 	int bd_idx;
1998 	int reg_idx;
1999 
2000 	prom_printf("Board status after disconnect.\n");
2001 	for (bd_idx = 0; bd_idx < fhc_max_boards(); bd_idx++) {
2002 		if (reg_dt[bd_idx][0].oflag == 0) {
2003 			prom_printf("Board #%d is idle.\n", bd_idx);
2004 		} else {
2005 			prom_printf("Board #%d is on.\n", bd_idx);
2006 			for (reg_idx = 0; reg_idx < NUM_REG; reg_idx++)
2007 				reg_dt[bd_idx][reg_idx].post_dsct =
2008 				    ldphysio(reg_dt[bd_idx][reg_idx].physaddr);
2009 		}
2010 	}
2011 
2012 	for (bd_idx = 0; bd_idx < fhc_max_boards(); bd_idx++) {
2013 		if (reg_dt[bd_idx][0].eflag) {
2014 			prom_printf("\nRegisters for Board #%d", bd_idx);
2015 			prom_printf(" (before and after disconnect).\n");
2016 			prom_printf("AC_BCSR   FHC_CTRL  JTAG      IGN   SIM"
2017 			    "       SISM  UIM       USM\n");
2018 			prom_printf("%08x  %08x  %08x  %04x"
2019 			    "  %08x  %04x  %08x  %04x\n",
2020 			    reg_dt[bd_idx][0].pre_dsct,
2021 			    reg_dt[bd_idx][1].pre_dsct,
2022 			    reg_dt[bd_idx][2].pre_dsct,
2023 			    reg_dt[bd_idx][3].pre_dsct,
2024 			    reg_dt[bd_idx][4].pre_dsct,
2025 			    reg_dt[bd_idx][5].pre_dsct,
2026 			    reg_dt[bd_idx][6].pre_dsct,
2027 			    reg_dt[bd_idx][7].pre_dsct);
2028 			if (reg_dt[bd_idx][0].oflag) {
2029 				prom_printf("%08x  %08x  %08x  %04x"
2030 				    "  %08x  %04x  %08x  %04x\n",
2031 				    reg_dt[bd_idx][0].post_dsct,
2032 				    reg_dt[bd_idx][1].post_dsct,
2033 				    reg_dt[bd_idx][2].post_dsct,
2034 				    reg_dt[bd_idx][3].post_dsct,
2035 				    reg_dt[bd_idx][4].post_dsct,
2036 				    reg_dt[bd_idx][5].post_dsct,
2037 				    reg_dt[bd_idx][6].post_dsct,
2038 				    reg_dt[bd_idx][7].post_dsct);
2039 			} else {
2040 				prom_printf("no data (board got"
2041 				    " disconnected)-------------------"
2042 				    "---------------\n");
2043 			}
2044 		}
2045 
2046 	}
2047 
2048 }
2049 
2050 #endif /* DEBUG */
2051