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