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