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