xref: /illumos-gate/usr/src/uts/sun4u/sunfire/io/sysctrl.c (revision 29949e866e40b95795203f3ee46f44a197c946e4)
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/ddi_impldefs.h>
34*29949e86Sstevel #include <sys/sunndi.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/modctl.h>
47*29949e86Sstevel #include <sys/callb.h>
48*29949e86Sstevel #include <sys/file.h>
49*29949e86Sstevel #include <sys/open.h>
50*29949e86Sstevel #include <sys/stat.h>
51*29949e86Sstevel #include <sys/fhc.h>
52*29949e86Sstevel #include <sys/sysctrl.h>
53*29949e86Sstevel #include <sys/jtag.h>
54*29949e86Sstevel #include <sys/ac.h>
55*29949e86Sstevel #include <sys/simmstat.h>
56*29949e86Sstevel #include <sys/clock.h>
57*29949e86Sstevel #include <sys/promif.h>
58*29949e86Sstevel #include <sys/promimpl.h>
59*29949e86Sstevel #include <sys/sunndi.h>
60*29949e86Sstevel #include <sys/machsystm.h>
61*29949e86Sstevel 
62*29949e86Sstevel /* Useful debugging Stuff */
63*29949e86Sstevel #ifdef DEBUG
64*29949e86Sstevel int sysc_debug_info = 1;
65*29949e86Sstevel int sysc_debug_print_level = 0;
66*29949e86Sstevel #endif
67*29949e86Sstevel 
68*29949e86Sstevel /*
69*29949e86Sstevel  * Function prototypes
70*29949e86Sstevel  */
71*29949e86Sstevel static int sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
72*29949e86Sstevel 		void **result);
73*29949e86Sstevel 
74*29949e86Sstevel static int sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
75*29949e86Sstevel 
76*29949e86Sstevel static int sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
77*29949e86Sstevel 
78*29949e86Sstevel static int sysctrl_open(dev_t *, int, int, cred_t *);
79*29949e86Sstevel 
80*29949e86Sstevel static int sysctrl_close(dev_t, int, int, cred_t *);
81*29949e86Sstevel 
82*29949e86Sstevel static int sysctrl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
83*29949e86Sstevel 
84*29949e86Sstevel static uint_t system_high_handler(caddr_t arg);
85*29949e86Sstevel 
86*29949e86Sstevel static uint_t spur_delay(caddr_t arg);
87*29949e86Sstevel 
88*29949e86Sstevel static void spur_retry(void *);
89*29949e86Sstevel 
90*29949e86Sstevel static uint_t spur_reenable(caddr_t arg);
91*29949e86Sstevel 
92*29949e86Sstevel static void spur_long_timeout(void *);
93*29949e86Sstevel 
94*29949e86Sstevel static uint_t spur_clear_count(caddr_t arg);
95*29949e86Sstevel 
96*29949e86Sstevel static uint_t ac_fail_handler(caddr_t arg);
97*29949e86Sstevel 
98*29949e86Sstevel static void ac_fail_retry(void *);
99*29949e86Sstevel 
100*29949e86Sstevel static uint_t ac_fail_reenable(caddr_t arg);
101*29949e86Sstevel 
102*29949e86Sstevel static uint_t ps_fail_int_handler(caddr_t arg);
103*29949e86Sstevel 
104*29949e86Sstevel static uint_t ps_fail_poll_handler(caddr_t arg);
105*29949e86Sstevel 
106*29949e86Sstevel static uint_t ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint);
107*29949e86Sstevel 
108*29949e86Sstevel enum power_state compute_power_state(struct sysctrl_soft_state *softsp,
109*29949e86Sstevel 					int plus_load);
110*29949e86Sstevel 
111*29949e86Sstevel static void ps_log_state_change(struct sysctrl_soft_state *softsp,
112*29949e86Sstevel 					int index, int present);
113*29949e86Sstevel 
114*29949e86Sstevel static void ps_log_pres_change(struct sysctrl_soft_state *softsp,
115*29949e86Sstevel 					int index, int present);
116*29949e86Sstevel 
117*29949e86Sstevel static void ps_fail_retry(void *);
118*29949e86Sstevel 
119*29949e86Sstevel static uint_t pps_fanfail_handler(caddr_t arg);
120*29949e86Sstevel 
121*29949e86Sstevel static void pps_fanfail_retry(void *);
122*29949e86Sstevel 
123*29949e86Sstevel static uint_t pps_fanfail_reenable(caddr_t arg);
124*29949e86Sstevel 
125*29949e86Sstevel static void pps_fan_poll(void *);
126*29949e86Sstevel 
127*29949e86Sstevel static void pps_fan_state_change(struct sysctrl_soft_state *softsp,
128*29949e86Sstevel 					int index, int fan_ok);
129*29949e86Sstevel 
130*29949e86Sstevel static uint_t bd_insert_handler(caddr_t arg);
131*29949e86Sstevel 
132*29949e86Sstevel static void bd_insert_timeout(void *);
133*29949e86Sstevel 
134*29949e86Sstevel static void bd_remove_timeout(void *);
135*29949e86Sstevel 
136*29949e86Sstevel static uint_t bd_insert_normal(caddr_t arg);
137*29949e86Sstevel 
138*29949e86Sstevel static void sysctrl_add_kstats(struct sysctrl_soft_state *softsp);
139*29949e86Sstevel 
140*29949e86Sstevel static int sysctrl_kstat_update(kstat_t *ksp, int rw);
141*29949e86Sstevel 
142*29949e86Sstevel static int psstat_kstat_update(kstat_t *, int);
143*29949e86Sstevel 
144*29949e86Sstevel static void init_remote_console_uart(struct sysctrl_soft_state *);
145*29949e86Sstevel 
146*29949e86Sstevel static void blink_led_timeout(void *);
147*29949e86Sstevel 
148*29949e86Sstevel static uint_t blink_led_handler(caddr_t arg);
149*29949e86Sstevel 
150*29949e86Sstevel static void sysctrl_thread_wakeup(void *type);
151*29949e86Sstevel 
152*29949e86Sstevel static void sysctrl_overtemp_poll(void);
153*29949e86Sstevel 
154*29949e86Sstevel static void sysctrl_keyswitch_poll(void);
155*29949e86Sstevel 
156*29949e86Sstevel static void update_key_state(struct sysctrl_soft_state *);
157*29949e86Sstevel 
158*29949e86Sstevel static void sysctrl_abort_seq_handler(char *msg);
159*29949e86Sstevel 
160*29949e86Sstevel static void nvram_update_powerfail(struct sysctrl_soft_state *softsp);
161*29949e86Sstevel 
162*29949e86Sstevel static void toggle_board_green_leds(int);
163*29949e86Sstevel 
164*29949e86Sstevel void bd_remove_poll(struct sysctrl_soft_state *);
165*29949e86Sstevel 
166*29949e86Sstevel static void sysc_slot_info(int nslots, int *start, int *limit, int *incr);
167*29949e86Sstevel 
168*29949e86Sstevel extern void sysc_board_connect_supported_init(void);
169*29949e86Sstevel 
170*29949e86Sstevel static void rcons_reinit(struct sysctrl_soft_state *softsp);
171*29949e86Sstevel 
172*29949e86Sstevel /*
173*29949e86Sstevel  * Configuration data structures
174*29949e86Sstevel  */
175*29949e86Sstevel static struct cb_ops sysctrl_cb_ops = {
176*29949e86Sstevel 	sysctrl_open,		/* open */
177*29949e86Sstevel 	sysctrl_close,		/* close */
178*29949e86Sstevel 	nulldev,		/* strategy */
179*29949e86Sstevel 	nulldev,		/* print */
180*29949e86Sstevel 	nulldev,		/* dump */
181*29949e86Sstevel 	nulldev,		/* read */
182*29949e86Sstevel 	nulldev,		/* write */
183*29949e86Sstevel 	sysctrl_ioctl,		/* ioctl */
184*29949e86Sstevel 	nodev,			/* devmap */
185*29949e86Sstevel 	nodev,			/* mmap */
186*29949e86Sstevel 	nodev,			/* segmap */
187*29949e86Sstevel 	nochpoll,		/* poll */
188*29949e86Sstevel 	ddi_prop_op,		/* cb_prop_op */
189*29949e86Sstevel 	0,			/* streamtab */
190*29949e86Sstevel 	D_MP|D_NEW,		/* Driver compatibility flag */
191*29949e86Sstevel 	CB_REV,			/* rev */
192*29949e86Sstevel 	nodev,			/* cb_aread */
193*29949e86Sstevel 	nodev			/* cb_awrite */
194*29949e86Sstevel };
195*29949e86Sstevel 
196*29949e86Sstevel static struct dev_ops sysctrl_ops = {
197*29949e86Sstevel 	DEVO_REV,		/* devo_rev */
198*29949e86Sstevel 	0,			/* refcnt */
199*29949e86Sstevel 	sysctrl_info,		/* getinfo */
200*29949e86Sstevel 	nulldev,		/* identify */
201*29949e86Sstevel 	nulldev,		/* probe */
202*29949e86Sstevel 	sysctrl_attach,		/* attach */
203*29949e86Sstevel 	sysctrl_detach,		/* detach */
204*29949e86Sstevel 	nulldev,		/* reset */
205*29949e86Sstevel 	&sysctrl_cb_ops,	/* cb_ops */
206*29949e86Sstevel 	(struct bus_ops *)0,	/* bus_ops */
207*29949e86Sstevel 	nulldev			/* power */
208*29949e86Sstevel };
209*29949e86Sstevel 
210*29949e86Sstevel void *sysctrlp;				/* sysctrl soft state hook */
211*29949e86Sstevel 
212*29949e86Sstevel /* # of ticks to silence spurious interrupts */
213*29949e86Sstevel static clock_t spur_timeout_hz;
214*29949e86Sstevel 
215*29949e86Sstevel /* # of ticks to count spurious interrupts to print message */
216*29949e86Sstevel static clock_t spur_long_timeout_hz;
217*29949e86Sstevel 
218*29949e86Sstevel /* # of ticks between AC failure polling */
219*29949e86Sstevel static clock_t ac_timeout_hz;
220*29949e86Sstevel 
221*29949e86Sstevel /* # of ticks between Power Supply Failure polling */
222*29949e86Sstevel static clock_t ps_fail_timeout_hz;
223*29949e86Sstevel 
224*29949e86Sstevel /*
225*29949e86Sstevel  * # of ticks between Peripheral Power Supply failure polling
226*29949e86Sstevel  * (used both for interrupt retry timeout and polling function)
227*29949e86Sstevel  */
228*29949e86Sstevel static clock_t pps_fan_timeout_hz;
229*29949e86Sstevel 
230*29949e86Sstevel /* # of ticks delay after board insert interrupt */
231*29949e86Sstevel static clock_t bd_insert_delay_hz;
232*29949e86Sstevel 
233*29949e86Sstevel /* # of secs to wait before restarting poll if we cannot clear interrupts */
234*29949e86Sstevel static clock_t bd_insert_retry_hz;
235*29949e86Sstevel 
236*29949e86Sstevel /* # of secs between Board Removal polling */
237*29949e86Sstevel static clock_t bd_remove_timeout_hz;
238*29949e86Sstevel 
239*29949e86Sstevel /* # of secs between toggle of OS LED */
240*29949e86Sstevel static clock_t blink_led_timeout_hz;
241*29949e86Sstevel 
242*29949e86Sstevel /* overtemp polling routine timeout delay */
243*29949e86Sstevel static clock_t overtemp_timeout_hz;
244*29949e86Sstevel 
245*29949e86Sstevel /* key switch polling routine timeout delay */
246*29949e86Sstevel static clock_t keyswitch_timeout_hz;
247*29949e86Sstevel 
248*29949e86Sstevel /* Specify which system interrupt condition to monitor */
249*29949e86Sstevel int enable_sys_interrupt = SYS_AC_PWR_FAIL_EN | SYS_PPS_FAN_FAIL_EN |
250*29949e86Sstevel 			SYS_PS_FAIL_EN | SYS_SBRD_PRES_EN;
251*29949e86Sstevel 
252*29949e86Sstevel /* Should the overtemp_poll thread be running? */
253*29949e86Sstevel static int sysctrl_do_overtemp_thread = 1;
254*29949e86Sstevel 
255*29949e86Sstevel /* Should the keyswitch_poll thread be running? */
256*29949e86Sstevel static int sysctrl_do_keyswitch_thread = 1;
257*29949e86Sstevel 
258*29949e86Sstevel /*
259*29949e86Sstevel  * This timeout ID is for board remove polling routine. It is
260*29949e86Sstevel  * protected by the fhc_bdlist mutex.
261*29949e86Sstevel  * XXX - This will not work for wildfire. A different scheme must be
262*29949e86Sstevel  * used since there will be multiple sysctrl nodes, each with its
263*29949e86Sstevel  * own list of hotplugged boards to scan.
264*29949e86Sstevel  */
265*29949e86Sstevel static timeout_id_t bd_remove_to_id = 0;
266*29949e86Sstevel 
267*29949e86Sstevel /*
268*29949e86Sstevel  * If this is set, the system will not shutdown when insufficient power
269*29949e86Sstevel  * condition persists.
270*29949e86Sstevel  */
271*29949e86Sstevel int disable_insufficient_power_reboot = 0;
272*29949e86Sstevel 
273*29949e86Sstevel /*
274*29949e86Sstevel  * Set this to enable suspend/resume
275*29949e86Sstevel  */
276*29949e86Sstevel int sysctrl_enable_detach_suspend = 0;
277*29949e86Sstevel 
278*29949e86Sstevel /*
279*29949e86Sstevel  * Set this to reflect the OBP initialized HOTPLUG_DISABLED_PROPERTY and
280*29949e86Sstevel  * during dynamic detection
281*29949e86Sstevel  */
282*29949e86Sstevel int sysctrl_hotplug_disabled = FALSE;
283*29949e86Sstevel 
284*29949e86Sstevel /* Indicates whether or not the overtemp thread has been started */
285*29949e86Sstevel static int sysctrl_overtemp_thread_started = 0;
286*29949e86Sstevel 
287*29949e86Sstevel /* Indicates whether or not the key switch thread has been started */
288*29949e86Sstevel static int sysctrl_keyswitch_thread_started = 0;
289*29949e86Sstevel 
290*29949e86Sstevel /* *Mutex used to protect the soft state list */
291*29949e86Sstevel static kmutex_t sslist_mutex;
292*29949e86Sstevel 
293*29949e86Sstevel /* The CV is used to wakeup the overtemp thread when needed. */
294*29949e86Sstevel static kcondvar_t overtemp_cv;
295*29949e86Sstevel 
296*29949e86Sstevel /* The CV is used to wakeup the key switch thread when needed. */
297*29949e86Sstevel static kcondvar_t keyswitch_cv;
298*29949e86Sstevel 
299*29949e86Sstevel /* This mutex is used to protect the sysctrl_ddi_branch_init variable */
300*29949e86Sstevel static kmutex_t sysctrl_branch_mutex;
301*29949e86Sstevel 
302*29949e86Sstevel /*
303*29949e86Sstevel  * This variable is set after all existing branches in the system have
304*29949e86Sstevel  * been discovered and held via e_ddi_branch_hold(). This happens on
305*29949e86Sstevel  * first open() of any sysctrl minor node.
306*29949e86Sstevel  */
307*29949e86Sstevel static int sysctrl_ddi_branch_init;
308*29949e86Sstevel 
309*29949e86Sstevel /*
310*29949e86Sstevel  * Linked list of all syctrl soft state structures.
311*29949e86Sstevel  * Used for polling sysctrl state changes, i.e. temperature.
312*29949e86Sstevel  */
313*29949e86Sstevel struct sysctrl_soft_state *sys_list = NULL;
314*29949e86Sstevel 
315*29949e86Sstevel extern struct mod_ops mod_driverops;
316*29949e86Sstevel 
317*29949e86Sstevel static struct modldrv modldrv = {
318*29949e86Sstevel 	&mod_driverops,		/* Type of module.  This one is a driver */
319*29949e86Sstevel 	"Clock Board %I%",	/* name of module */
320*29949e86Sstevel 	&sysctrl_ops,		/* driver ops */
321*29949e86Sstevel };
322*29949e86Sstevel 
323*29949e86Sstevel static struct modlinkage modlinkage = {
324*29949e86Sstevel 	MODREV_1,		/* rev */
325*29949e86Sstevel 	(void *)&modldrv,
326*29949e86Sstevel 	NULL
327*29949e86Sstevel };
328*29949e86Sstevel 
329*29949e86Sstevel #ifndef lint
330*29949e86Sstevel static char _depends_on[] = "drv/fhc";
331*29949e86Sstevel #endif /* lint */
332*29949e86Sstevel 
333*29949e86Sstevel /*
334*29949e86Sstevel  * These are the module initialization routines.
335*29949e86Sstevel  */
336*29949e86Sstevel 
337*29949e86Sstevel int
338*29949e86Sstevel _init(void)
339*29949e86Sstevel {
340*29949e86Sstevel 	int error;
341*29949e86Sstevel 
342*29949e86Sstevel 	if ((error = ddi_soft_state_init(&sysctrlp,
343*29949e86Sstevel 	    sizeof (struct sysctrl_soft_state), 1)) != 0)
344*29949e86Sstevel 		return (error);
345*29949e86Sstevel 
346*29949e86Sstevel 	error = mod_install(&modlinkage);
347*29949e86Sstevel 	if (error != 0) {
348*29949e86Sstevel 		ddi_soft_state_fini(&sysctrlp);
349*29949e86Sstevel 		return (error);
350*29949e86Sstevel 	}
351*29949e86Sstevel 
352*29949e86Sstevel 	mutex_init(&sysctrl_branch_mutex, NULL, MUTEX_DRIVER, NULL);
353*29949e86Sstevel 
354*29949e86Sstevel 	return (0);
355*29949e86Sstevel }
356*29949e86Sstevel 
357*29949e86Sstevel int
358*29949e86Sstevel _fini(void)
359*29949e86Sstevel {
360*29949e86Sstevel 	int error;
361*29949e86Sstevel 
362*29949e86Sstevel 	if ((error = mod_remove(&modlinkage)) != 0)
363*29949e86Sstevel 		return (error);
364*29949e86Sstevel 
365*29949e86Sstevel 	ddi_soft_state_fini(&sysctrlp);
366*29949e86Sstevel 
367*29949e86Sstevel 	mutex_destroy(&sysctrl_branch_mutex);
368*29949e86Sstevel 
369*29949e86Sstevel 	return (0);
370*29949e86Sstevel }
371*29949e86Sstevel 
372*29949e86Sstevel int
373*29949e86Sstevel _info(struct modinfo *modinfop)
374*29949e86Sstevel {
375*29949e86Sstevel 	return (mod_info(&modlinkage, modinfop));
376*29949e86Sstevel }
377*29949e86Sstevel 
378*29949e86Sstevel /* ARGSUSED */
379*29949e86Sstevel static int
380*29949e86Sstevel sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
381*29949e86Sstevel {
382*29949e86Sstevel 	dev_t	dev;
383*29949e86Sstevel 	int	instance;
384*29949e86Sstevel 
385*29949e86Sstevel 	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
386*29949e86Sstevel 		dev = (dev_t)arg;
387*29949e86Sstevel 		instance = GETINSTANCE(dev);
388*29949e86Sstevel 		*result = (void *)(uintptr_t)instance;
389*29949e86Sstevel 		return (DDI_SUCCESS);
390*29949e86Sstevel 	}
391*29949e86Sstevel 	return (DDI_FAILURE);
392*29949e86Sstevel }
393*29949e86Sstevel 
394*29949e86Sstevel static int
395*29949e86Sstevel sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
396*29949e86Sstevel {
397*29949e86Sstevel 	struct sysctrl_soft_state *softsp;
398*29949e86Sstevel 	int instance;
399*29949e86Sstevel 	uchar_t tmp_reg;
400*29949e86Sstevel 	dev_info_t *dip;
401*29949e86Sstevel 	char *propval;
402*29949e86Sstevel 	int proplen;
403*29949e86Sstevel 	int slot_num;
404*29949e86Sstevel 	int start;		/* start index for scan loop */
405*29949e86Sstevel 	int limit;		/* board number limit for scan loop */
406*29949e86Sstevel 	int incr;		/* amount to incr each pass thru loop */
407*29949e86Sstevel 	void set_clockbrd_info(void);
408*29949e86Sstevel 
409*29949e86Sstevel 
410*29949e86Sstevel 	switch (cmd) {
411*29949e86Sstevel 	case DDI_ATTACH:
412*29949e86Sstevel 		break;
413*29949e86Sstevel 
414*29949e86Sstevel 	case DDI_RESUME:
415*29949e86Sstevel 		/* XXX see sysctrl:DDI_SUSPEND for special h/w treatment */
416*29949e86Sstevel 		return (DDI_SUCCESS);
417*29949e86Sstevel 
418*29949e86Sstevel 	default:
419*29949e86Sstevel 		return (DDI_FAILURE);
420*29949e86Sstevel 	}
421*29949e86Sstevel 
422*29949e86Sstevel 	instance = ddi_get_instance(devi);
423*29949e86Sstevel 
424*29949e86Sstevel 	if (ddi_soft_state_zalloc(sysctrlp, instance) != DDI_SUCCESS)
425*29949e86Sstevel 		return (DDI_FAILURE);
426*29949e86Sstevel 
427*29949e86Sstevel 	softsp = GETSOFTC(instance);
428*29949e86Sstevel 
429*29949e86Sstevel 	/* Set the dip in the soft state */
430*29949e86Sstevel 	softsp->dip = devi;
431*29949e86Sstevel 
432*29949e86Sstevel 	/* Set up the parent dip */
433*29949e86Sstevel 	softsp->pdip = ddi_get_parent(softsp->dip);
434*29949e86Sstevel 
435*29949e86Sstevel 	DPRINTF(SYSCTRL_ATTACH_DEBUG, ("sysctrl: devi= 0x%p\n, softsp=0x%p\n",
436*29949e86Sstevel 		devi, softsp));
437*29949e86Sstevel 
438*29949e86Sstevel 	/* First set all of the timeout values */
439*29949e86Sstevel 	spur_timeout_hz = drv_usectohz(SPUR_TIMEOUT_USEC);
440*29949e86Sstevel 	spur_long_timeout_hz = drv_usectohz(SPUR_LONG_TIMEOUT_USEC);
441*29949e86Sstevel 	ac_timeout_hz = drv_usectohz(AC_TIMEOUT_USEC);
442*29949e86Sstevel 	ps_fail_timeout_hz = drv_usectohz(PS_FAIL_TIMEOUT_USEC);
443*29949e86Sstevel 	pps_fan_timeout_hz = drv_usectohz(PPS_FAN_TIMEOUT_USEC);
444*29949e86Sstevel 	bd_insert_delay_hz = drv_usectohz(BRD_INSERT_DELAY_USEC);
445*29949e86Sstevel 	bd_insert_retry_hz = drv_usectohz(BRD_INSERT_RETRY_USEC);
446*29949e86Sstevel 	bd_remove_timeout_hz = drv_usectohz(BRD_REMOVE_TIMEOUT_USEC);
447*29949e86Sstevel 	blink_led_timeout_hz = drv_usectohz(BLINK_LED_TIMEOUT_USEC);
448*29949e86Sstevel 	overtemp_timeout_hz = drv_usectohz(OVERTEMP_TIMEOUT_SEC * MICROSEC);
449*29949e86Sstevel 	keyswitch_timeout_hz = drv_usectohz(KEYSWITCH_TIMEOUT_USEC);
450*29949e86Sstevel 
451*29949e86Sstevel 	/*
452*29949e86Sstevel 	 * Map in the registers sets that OBP hands us. According
453*29949e86Sstevel 	 * to the sun4u device tree spec., the register sets are as
454*29949e86Sstevel 	 * follows:
455*29949e86Sstevel 	 *
456*29949e86Sstevel 	 *	0	Clock Frequency Registers (contains the bit
457*29949e86Sstevel 	 *		for enabling the remote console reset)
458*29949e86Sstevel 	 *	1	Misc (has all the registers that we need
459*29949e86Sstevel 	 *	2	Clock Version Register
460*29949e86Sstevel 	 */
461*29949e86Sstevel 	if (ddi_map_regs(softsp->dip, 0,
462*29949e86Sstevel 	    (caddr_t *)&softsp->clk_freq1, 0, 0)) {
463*29949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: unable to map clock frequency "
464*29949e86Sstevel 			"registers", instance);
465*29949e86Sstevel 		goto bad0;
466*29949e86Sstevel 	}
467*29949e86Sstevel 
468*29949e86Sstevel 	if (ddi_map_regs(softsp->dip, 1,
469*29949e86Sstevel 	    (caddr_t *)&softsp->csr, 0, 0)) {
470*29949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: unable to map internal"
471*29949e86Sstevel 			"registers", instance);
472*29949e86Sstevel 		goto bad1;
473*29949e86Sstevel 	}
474*29949e86Sstevel 
475*29949e86Sstevel 	/*
476*29949e86Sstevel 	 * There is a new register for newer vintage clock board nodes,
477*29949e86Sstevel 	 * OBP register set 2 in the clock board node.
478*29949e86Sstevel 	 *
479*29949e86Sstevel 	 */
480*29949e86Sstevel 	(void) ddi_map_regs(softsp->dip, 2, (caddr_t *)&softsp->clk_ver, 0, 0);
481*29949e86Sstevel 
482*29949e86Sstevel 	/*
483*29949e86Sstevel 	 * Fill in the virtual addresses of the registers in the
484*29949e86Sstevel 	 * sysctrl_soft_state structure. We do not want to calculate
485*29949e86Sstevel 	 * them on the fly. This way we waste a little memory, but
486*29949e86Sstevel 	 * avoid bugs down the road.
487*29949e86Sstevel 	 */
488*29949e86Sstevel 	softsp->clk_freq2 = (uchar_t *)((caddr_t)softsp->clk_freq1 +
489*29949e86Sstevel 		SYS_OFF_CLK_FREQ2);
490*29949e86Sstevel 
491*29949e86Sstevel 	softsp->status1 = (uchar_t *)((caddr_t)softsp->csr +
492*29949e86Sstevel 		SYS_OFF_STAT1);
493*29949e86Sstevel 
494*29949e86Sstevel 	softsp->status2 = (uchar_t *)((caddr_t)softsp->csr +
495*29949e86Sstevel 		SYS_OFF_STAT2);
496*29949e86Sstevel 
497*29949e86Sstevel 	softsp->ps_stat = (uchar_t *)((caddr_t)softsp->csr +
498*29949e86Sstevel 		SYS_OFF_PSSTAT);
499*29949e86Sstevel 
500*29949e86Sstevel 	softsp->ps_pres = (uchar_t *)((caddr_t)softsp->csr +
501*29949e86Sstevel 		SYS_OFF_PSPRES);
502*29949e86Sstevel 
503*29949e86Sstevel 	softsp->pppsr = (uchar_t *)((caddr_t)softsp->csr +
504*29949e86Sstevel 		SYS_OFF_PPPSR);
505*29949e86Sstevel 
506*29949e86Sstevel 	softsp->temp_reg = (uchar_t *)((caddr_t)softsp->csr +
507*29949e86Sstevel 		SYS_OFF_TEMP);
508*29949e86Sstevel 
509*29949e86Sstevel 	set_clockbrd_info();
510*29949e86Sstevel 
511*29949e86Sstevel 	/*
512*29949e86Sstevel 	 * Enable the hardware watchdog gate on the clock board if
513*29949e86Sstevel 	 * map_wellknown has detected that watchdog timer is available
514*29949e86Sstevel 	 * and user wants it to be enabled.
515*29949e86Sstevel 	 */
516*29949e86Sstevel 	if (watchdog_available && watchdog_enable)
517*29949e86Sstevel 		*(softsp->clk_freq2) |= TOD_RESET_EN;
518*29949e86Sstevel 	else
519*29949e86Sstevel 		*(softsp->clk_freq2) &= ~TOD_RESET_EN;
520*29949e86Sstevel 
521*29949e86Sstevel 	/* Check for inherited faults from the PROM. */
522*29949e86Sstevel 	if (*softsp->csr & SYS_LED_MID) {
523*29949e86Sstevel 		reg_fault(0, FT_PROM, FT_SYSTEM);
524*29949e86Sstevel 	}
525*29949e86Sstevel 
526*29949e86Sstevel 	/*
527*29949e86Sstevel 	 * calculate and cache the number of slots on this system
528*29949e86Sstevel 	 */
529*29949e86Sstevel 	switch (SYS_TYPE(*softsp->status1)) {
530*29949e86Sstevel 	case SYS_16_SLOT:
531*29949e86Sstevel 		softsp->nslots = 16;
532*29949e86Sstevel 		break;
533*29949e86Sstevel 
534*29949e86Sstevel 	case SYS_8_SLOT:
535*29949e86Sstevel 		softsp->nslots = 8;
536*29949e86Sstevel 		break;
537*29949e86Sstevel 
538*29949e86Sstevel 	case SYS_4_SLOT:
539*29949e86Sstevel 		/* check the clk_version register - if the ptr is valid */
540*29949e86Sstevel 		if ((softsp->clk_ver != NULL) &&
541*29949e86Sstevel 		    (SYS_TYPE2(*softsp->clk_ver) == SYS_PLUS_SYSTEM)) {
542*29949e86Sstevel 			softsp->nslots = 5;
543*29949e86Sstevel 		} else {
544*29949e86Sstevel 			softsp->nslots = 4;
545*29949e86Sstevel 		}
546*29949e86Sstevel 		break;
547*29949e86Sstevel 
548*29949e86Sstevel 	case SYS_TESTBED:
549*29949e86Sstevel 	default:
550*29949e86Sstevel 		softsp->nslots = 0;
551*29949e86Sstevel 		break;
552*29949e86Sstevel 	}
553*29949e86Sstevel 
554*29949e86Sstevel 
555*29949e86Sstevel 	/* create the fault list kstat */
556*29949e86Sstevel 	create_ft_kstats(instance);
557*29949e86Sstevel 
558*29949e86Sstevel 	/*
559*29949e86Sstevel 	 * Do a priming read on the ADC, and throw away the first value
560*29949e86Sstevel 	 * read. This is a feature of the ADC hardware. After a power cycle
561*29949e86Sstevel 	 * it does not contains valid data until a read occurs.
562*29949e86Sstevel 	 */
563*29949e86Sstevel 	tmp_reg = *(softsp->temp_reg);
564*29949e86Sstevel 
565*29949e86Sstevel 	/* Wait 30 usec for ADC hardware to stabilize. */
566*29949e86Sstevel 	DELAY(30);
567*29949e86Sstevel 
568*29949e86Sstevel 	/* shut off all interrupt sources */
569*29949e86Sstevel 	*(softsp->csr) &= ~(SYS_PPS_FAN_FAIL_EN | SYS_PS_FAIL_EN |
570*29949e86Sstevel 				SYS_AC_PWR_FAIL_EN | SYS_SBRD_PRES_EN);
571*29949e86Sstevel 	tmp_reg = *(softsp->csr);
572*29949e86Sstevel #ifdef lint
573*29949e86Sstevel 	tmp_reg = tmp_reg;
574*29949e86Sstevel #endif
575*29949e86Sstevel 
576*29949e86Sstevel 	/*
577*29949e86Sstevel 	 * Now register our high interrupt with the system.
578*29949e86Sstevel 	 */
579*29949e86Sstevel 	if (ddi_add_intr(devi, 0, &softsp->iblock,
580*29949e86Sstevel 	    &softsp->idevice, (uint_t (*)(caddr_t))nulldev, NULL) !=
581*29949e86Sstevel 	    DDI_SUCCESS)
582*29949e86Sstevel 		goto bad2;
583*29949e86Sstevel 
584*29949e86Sstevel 	mutex_init(&softsp->csr_mutex, NULL, MUTEX_DRIVER,
585*29949e86Sstevel 	    (void *)softsp->iblock);
586*29949e86Sstevel 
587*29949e86Sstevel 	ddi_remove_intr(devi, 0, softsp->iblock);
588*29949e86Sstevel 
589*29949e86Sstevel 	if (ddi_add_intr(devi, 0, &softsp->iblock,
590*29949e86Sstevel 	    &softsp->idevice, system_high_handler, (caddr_t)softsp) !=
591*29949e86Sstevel 	    DDI_SUCCESS)
592*29949e86Sstevel 		goto bad3;
593*29949e86Sstevel 
594*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_id,
595*29949e86Sstevel 	    &softsp->spur_int_c, NULL, spur_delay, (caddr_t)softsp) !=
596*29949e86Sstevel 	    DDI_SUCCESS)
597*29949e86Sstevel 		goto bad4;
598*29949e86Sstevel 
599*29949e86Sstevel 	mutex_init(&softsp->spur_int_lock, NULL, MUTEX_DRIVER,
600*29949e86Sstevel 		(void *)softsp->spur_int_c);
601*29949e86Sstevel 
602*29949e86Sstevel 
603*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_high_id,
604*29949e86Sstevel 	    NULL, NULL, spur_reenable, (caddr_t)softsp) != DDI_SUCCESS)
605*29949e86Sstevel 		goto bad5;
606*29949e86Sstevel 
607*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_long_to_id,
608*29949e86Sstevel 	    NULL, NULL, spur_clear_count, (caddr_t)softsp) != DDI_SUCCESS)
609*29949e86Sstevel 		goto bad6;
610*29949e86Sstevel 
611*29949e86Sstevel 	/*
612*29949e86Sstevel 	 * Now register low-level ac fail handler
613*29949e86Sstevel 	 */
614*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ac_fail_id,
615*29949e86Sstevel 	    NULL, NULL, ac_fail_handler, (caddr_t)softsp) != DDI_SUCCESS)
616*29949e86Sstevel 		goto bad7;
617*29949e86Sstevel 
618*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ac_fail_high_id,
619*29949e86Sstevel 	    NULL, NULL, ac_fail_reenable, (caddr_t)softsp) != DDI_SUCCESS)
620*29949e86Sstevel 		goto bad8;
621*29949e86Sstevel 
622*29949e86Sstevel 	/*
623*29949e86Sstevel 	 * Now register low-level ps fail handler
624*29949e86Sstevel 	 */
625*29949e86Sstevel 
626*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ps_fail_int_id,
627*29949e86Sstevel 	    &softsp->ps_fail_c, NULL, ps_fail_int_handler, (caddr_t)softsp) !=
628*29949e86Sstevel 	    DDI_SUCCESS)
629*29949e86Sstevel 		goto bad9;
630*29949e86Sstevel 
631*29949e86Sstevel 	mutex_init(&softsp->ps_fail_lock, NULL, MUTEX_DRIVER,
632*29949e86Sstevel 		(void *)softsp->ps_fail_c);
633*29949e86Sstevel 
634*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ps_fail_poll_id,
635*29949e86Sstevel 	    NULL, NULL, ps_fail_poll_handler, (caddr_t)softsp) !=
636*29949e86Sstevel 	    DDI_SUCCESS)
637*29949e86Sstevel 		goto bad10;
638*29949e86Sstevel 
639*29949e86Sstevel 	/*
640*29949e86Sstevel 	 * Now register low-level pps fan fail handler
641*29949e86Sstevel 	 */
642*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_id,
643*29949e86Sstevel 	    NULL, NULL, pps_fanfail_handler, (caddr_t)softsp) !=
644*29949e86Sstevel 	    DDI_SUCCESS)
645*29949e86Sstevel 		goto bad11;
646*29949e86Sstevel 
647*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_high_id,
648*29949e86Sstevel 	    NULL, NULL, pps_fanfail_reenable, (caddr_t)softsp) !=
649*29949e86Sstevel 	    DDI_SUCCESS)
650*29949e86Sstevel 		goto bad12;
651*29949e86Sstevel 
652*29949e86Sstevel 	/*
653*29949e86Sstevel 	 * Based upon a check for a current share backplane, advise
654*29949e86Sstevel 	 * that system does not support hot plug
655*29949e86Sstevel 	 *
656*29949e86Sstevel 	 */
657*29949e86Sstevel 	if ((*(softsp->pppsr) & SYS_NOT_CURRENT_S) != 0) {
658*29949e86Sstevel 		cmn_err(CE_NOTE, "Hot Plug not supported in this system");
659*29949e86Sstevel 		sysctrl_hotplug_disabled = TRUE;
660*29949e86Sstevel 	}
661*29949e86Sstevel 
662*29949e86Sstevel 	/*
663*29949e86Sstevel 	 * If the trigger circuit is busted or the NOT_BRD_PRES line
664*29949e86Sstevel 	 * is stuck then OBP will publish this property stating that
665*29949e86Sstevel 	 * hot plug is not available.  If this happens we will complain
666*29949e86Sstevel 	 * to the console and register a system fault.  We will also
667*29949e86Sstevel 	 * not enable the board insert interrupt for this session.
668*29949e86Sstevel 	 */
669*29949e86Sstevel 	if (ddi_prop_op(DDI_DEV_T_ANY, softsp->dip, PROP_LEN_AND_VAL_ALLOC,
670*29949e86Sstevel 	    DDI_PROP_DONTPASS, HOTPLUG_DISABLED_PROPERTY,
671*29949e86Sstevel 	    (caddr_t)&propval, &proplen) == DDI_PROP_SUCCESS) {
672*29949e86Sstevel 		cmn_err(CE_WARN, "Hot Plug Unavailable [%s]", propval);
673*29949e86Sstevel 		reg_fault(0, FT_HOT_PLUG, FT_SYSTEM);
674*29949e86Sstevel 		sysctrl_hotplug_disabled = TRUE;
675*29949e86Sstevel 		enable_sys_interrupt &= ~SYS_SBRD_PRES_EN;
676*29949e86Sstevel 		kmem_free(propval, proplen);
677*29949e86Sstevel 	}
678*29949e86Sstevel 
679*29949e86Sstevel 	sysc_board_connect_supported_init();
680*29949e86Sstevel 
681*29949e86Sstevel 	fhc_bd_sc_register(sysc_policy_update, softsp);
682*29949e86Sstevel 
683*29949e86Sstevel 	sysc_slot_info(softsp->nslots, &start, &limit, &incr);
684*29949e86Sstevel 
685*29949e86Sstevel 	/* Prime the board list. */
686*29949e86Sstevel 	fhc_bdlist_prime(start, limit, incr);
687*29949e86Sstevel 
688*29949e86Sstevel 	/*
689*29949e86Sstevel 	 * Set up a board remove timeout call.
690*29949e86Sstevel 	 */
691*29949e86Sstevel 	(void) fhc_bdlist_lock(-1);
692*29949e86Sstevel 
693*29949e86Sstevel 	DPRINTF(SYSCTRL_ATTACH_DEBUG,
694*29949e86Sstevel 		("attach: start bd_remove_poll()..."));
695*29949e86Sstevel 
696*29949e86Sstevel 	bd_remove_poll(softsp);
697*29949e86Sstevel 	fhc_bdlist_unlock();
698*29949e86Sstevel 
699*29949e86Sstevel 	/*
700*29949e86Sstevel 	 * Now register low-level board insert handler
701*29949e86Sstevel 	 */
702*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_pres_id,
703*29949e86Sstevel 	    NULL, NULL, bd_insert_handler, (caddr_t)softsp) != DDI_SUCCESS)
704*29949e86Sstevel 		goto bad13;
705*29949e86Sstevel 
706*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_gone_id,
707*29949e86Sstevel 	    NULL, NULL, bd_insert_normal, (caddr_t)softsp) != DDI_SUCCESS)
708*29949e86Sstevel 		goto bad14;
709*29949e86Sstevel 
710*29949e86Sstevel 	/*
711*29949e86Sstevel 	 * Now register led blink handler (interrupt level)
712*29949e86Sstevel 	 */
713*29949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->blink_led_id,
714*29949e86Sstevel 	    &softsp->sys_led_c, NULL, blink_led_handler, (caddr_t)softsp) !=
715*29949e86Sstevel 	    DDI_SUCCESS)
716*29949e86Sstevel 		goto bad15;
717*29949e86Sstevel 	mutex_init(&softsp->sys_led_lock, NULL, MUTEX_DRIVER,
718*29949e86Sstevel 		(void *)softsp->sys_led_c);
719*29949e86Sstevel 
720*29949e86Sstevel 	/* initialize the bit field for all pps fans to assumed good */
721*29949e86Sstevel 	softsp->pps_fan_saved = softsp->pps_fan_external_state =
722*29949e86Sstevel 		SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK;
723*29949e86Sstevel 
724*29949e86Sstevel 	/* prime the power supply state machines */
725*29949e86Sstevel 	if (enable_sys_interrupt & SYS_PS_FAIL_EN)
726*29949e86Sstevel 		ddi_trigger_softintr(softsp->ps_fail_poll_id);
727*29949e86Sstevel 
728*29949e86Sstevel 
729*29949e86Sstevel 	/* kick off the OS led blinker */
730*29949e86Sstevel 	softsp->sys_led = FALSE;
731*29949e86Sstevel 	ddi_trigger_softintr(softsp->blink_led_id);
732*29949e86Sstevel 
733*29949e86Sstevel 	/* Now enable selected interrupt sources */
734*29949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
735*29949e86Sstevel 	*(softsp->csr) |= enable_sys_interrupt &
736*29949e86Sstevel 		(SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
737*29949e86Sstevel 		SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
738*29949e86Sstevel 	tmp_reg = *(softsp->csr);
739*29949e86Sstevel #ifdef lint
740*29949e86Sstevel 	tmp_reg = tmp_reg;
741*29949e86Sstevel #endif
742*29949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
743*29949e86Sstevel 
744*29949e86Sstevel 	/* Initialize the temperature */
745*29949e86Sstevel 	init_temp_arrays(&softsp->tempstat);
746*29949e86Sstevel 
747*29949e86Sstevel 	/*
748*29949e86Sstevel 	 * initialize key switch shadow state
749*29949e86Sstevel 	 */
750*29949e86Sstevel 	softsp->key_shadow = KEY_BOOT;
751*29949e86Sstevel 
752*29949e86Sstevel 	/*
753*29949e86Sstevel 	 * Now add this soft state structure to the front of the linked list
754*29949e86Sstevel 	 * of soft state structures.
755*29949e86Sstevel 	 */
756*29949e86Sstevel 	if (sys_list == (struct sysctrl_soft_state *)NULL) {
757*29949e86Sstevel 		mutex_init(&sslist_mutex, NULL, MUTEX_DEFAULT, NULL);
758*29949e86Sstevel 	}
759*29949e86Sstevel 	mutex_enter(&sslist_mutex);
760*29949e86Sstevel 	softsp->next = sys_list;
761*29949e86Sstevel 	sys_list = softsp;
762*29949e86Sstevel 	mutex_exit(&sslist_mutex);
763*29949e86Sstevel 
764*29949e86Sstevel 	/* Setup the kstats for this device */
765*29949e86Sstevel 	sysctrl_add_kstats(softsp);
766*29949e86Sstevel 
767*29949e86Sstevel 	/* kick off the PPS fan poll routine */
768*29949e86Sstevel 	pps_fan_poll(softsp);
769*29949e86Sstevel 
770*29949e86Sstevel 	if (sysctrl_overtemp_thread_started == 0) {
771*29949e86Sstevel 		/*
772*29949e86Sstevel 		 * set up the overtemp condition variable before
773*29949e86Sstevel 		 * starting the thread.
774*29949e86Sstevel 		 */
775*29949e86Sstevel 		cv_init(&overtemp_cv, NULL, CV_DRIVER, NULL);
776*29949e86Sstevel 
777*29949e86Sstevel 		/*
778*29949e86Sstevel 		 * start up the overtemp polling thread
779*29949e86Sstevel 		 */
780*29949e86Sstevel 		(void) thread_create(NULL, 0, (void (*)())sysctrl_overtemp_poll,
781*29949e86Sstevel 		    NULL, 0, &p0, TS_RUN, minclsyspri);
782*29949e86Sstevel 		sysctrl_overtemp_thread_started++;
783*29949e86Sstevel 	}
784*29949e86Sstevel 
785*29949e86Sstevel 	if (sysctrl_keyswitch_thread_started == 0) {
786*29949e86Sstevel 		extern void (*abort_seq_handler)();
787*29949e86Sstevel 
788*29949e86Sstevel 		/*
789*29949e86Sstevel 		 * interpose sysctrl's abort sequence handler
790*29949e86Sstevel 		 */
791*29949e86Sstevel 		abort_seq_handler = sysctrl_abort_seq_handler;
792*29949e86Sstevel 
793*29949e86Sstevel 		/*
794*29949e86Sstevel 		 * set up the key switch condition variable before
795*29949e86Sstevel 		 * starting the thread
796*29949e86Sstevel 		 */
797*29949e86Sstevel 		cv_init(&keyswitch_cv, NULL, CV_DRIVER, NULL);
798*29949e86Sstevel 
799*29949e86Sstevel 		/*
800*29949e86Sstevel 		 * start up the key switch polling thread
801*29949e86Sstevel 		 */
802*29949e86Sstevel 		(void) thread_create(NULL, 0,
803*29949e86Sstevel 		    (void (*)())sysctrl_keyswitch_poll, NULL, 0, &p0,
804*29949e86Sstevel 		    TS_RUN, minclsyspri);
805*29949e86Sstevel 		sysctrl_keyswitch_thread_started++;
806*29949e86Sstevel 	}
807*29949e86Sstevel 
808*29949e86Sstevel 	/*
809*29949e86Sstevel 	 * perform initialization to allow setting of powerfail-time
810*29949e86Sstevel 	 */
811*29949e86Sstevel 	if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL)
812*29949e86Sstevel 		softsp->options_nodeid = (pnode_t)NULL;
813*29949e86Sstevel 	else
814*29949e86Sstevel 		softsp->options_nodeid = (pnode_t)ddi_get_nodeid(dip);
815*29949e86Sstevel 
816*29949e86Sstevel 	DPRINTF(SYSCTRL_ATTACH_DEBUG,
817*29949e86Sstevel 		("sysctrl: Creating devices start:%d, limit:%d, incr:%d\n",
818*29949e86Sstevel 		start, limit, incr));
819*29949e86Sstevel 
820*29949e86Sstevel 	/*
821*29949e86Sstevel 	 * Create minor node for each system attachment points
822*29949e86Sstevel 	 */
823*29949e86Sstevel 	for (slot_num = start; slot_num < limit; slot_num = slot_num + incr) {
824*29949e86Sstevel 		char name[30];
825*29949e86Sstevel 		(void) sprintf(name, "slot%d", slot_num);
826*29949e86Sstevel 		if (ddi_create_minor_node(devi, name, S_IFCHR,
827*29949e86Sstevel 		    (PUTINSTANCE(instance) | slot_num),
828*29949e86Sstevel 		    DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
829*29949e86Sstevel 			cmn_err(CE_WARN, "sysctrl%d: \"%s\" "
830*29949e86Sstevel 				"ddi_create_minor_node failed",
831*29949e86Sstevel 				instance, name);
832*29949e86Sstevel 			goto bad16;
833*29949e86Sstevel 		}
834*29949e86Sstevel 	}
835*29949e86Sstevel 
836*29949e86Sstevel 	ddi_report_dev(devi);
837*29949e86Sstevel 
838*29949e86Sstevel 	/*
839*29949e86Sstevel 	 * Remote console is inherited from POST
840*29949e86Sstevel 	 */
841*29949e86Sstevel 	if ((*(softsp->clk_freq2) & RCONS_UART_EN) == 0) {
842*29949e86Sstevel 		softsp->enable_rcons_atboot = FALSE;
843*29949e86Sstevel 		cmn_err(CE_WARN, "Remote console not active");
844*29949e86Sstevel 	} else
845*29949e86Sstevel 		softsp->enable_rcons_atboot = TRUE;
846*29949e86Sstevel 
847*29949e86Sstevel 	return (DDI_SUCCESS);
848*29949e86Sstevel 
849*29949e86Sstevel bad16:
850*29949e86Sstevel 	cv_destroy(&keyswitch_cv);
851*29949e86Sstevel 	cv_destroy(&overtemp_cv);
852*29949e86Sstevel 	mutex_destroy(&sslist_mutex);
853*29949e86Sstevel 	mutex_destroy(&softsp->sys_led_lock);
854*29949e86Sstevel 	ddi_remove_softintr(softsp->blink_led_id);
855*29949e86Sstevel bad15:
856*29949e86Sstevel 	ddi_remove_softintr(softsp->sbrd_gone_id);
857*29949e86Sstevel bad14:
858*29949e86Sstevel 	ddi_remove_softintr(softsp->sbrd_pres_id);
859*29949e86Sstevel bad13:
860*29949e86Sstevel 	ddi_remove_softintr(softsp->pps_fan_high_id);
861*29949e86Sstevel bad12:
862*29949e86Sstevel 	ddi_remove_softintr(softsp->pps_fan_id);
863*29949e86Sstevel bad11:
864*29949e86Sstevel 	ddi_remove_softintr(softsp->ps_fail_poll_id);
865*29949e86Sstevel bad10:
866*29949e86Sstevel 	mutex_destroy(&softsp->ps_fail_lock);
867*29949e86Sstevel 	ddi_remove_softintr(softsp->ps_fail_int_id);
868*29949e86Sstevel bad9:
869*29949e86Sstevel 	ddi_remove_softintr(softsp->ac_fail_high_id);
870*29949e86Sstevel bad8:
871*29949e86Sstevel 	ddi_remove_softintr(softsp->ac_fail_id);
872*29949e86Sstevel bad7:
873*29949e86Sstevel 	ddi_remove_softintr(softsp->spur_long_to_id);
874*29949e86Sstevel bad6:
875*29949e86Sstevel 	ddi_remove_softintr(softsp->spur_high_id);
876*29949e86Sstevel bad5:
877*29949e86Sstevel 	mutex_destroy(&softsp->spur_int_lock);
878*29949e86Sstevel 	ddi_remove_softintr(softsp->spur_id);
879*29949e86Sstevel bad4:
880*29949e86Sstevel 	ddi_remove_intr(devi, 0, softsp->iblock);
881*29949e86Sstevel bad3:
882*29949e86Sstevel 	mutex_destroy(&softsp->csr_mutex);
883*29949e86Sstevel bad2:
884*29949e86Sstevel 	ddi_unmap_regs(softsp->dip, 1, (caddr_t *)&softsp->csr, 0, 0);
885*29949e86Sstevel 	if (softsp->clk_ver != NULL)
886*29949e86Sstevel 		ddi_unmap_regs(softsp->dip, 2, (caddr_t *)&softsp->clk_ver,
887*29949e86Sstevel 		    0, 0);
888*29949e86Sstevel bad1:
889*29949e86Sstevel 	ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->clk_freq1, 0, 0);
890*29949e86Sstevel 
891*29949e86Sstevel bad0:
892*29949e86Sstevel 	ddi_soft_state_free(sysctrlp, instance);
893*29949e86Sstevel 	ddi_remove_minor_node(dip, NULL);
894*29949e86Sstevel 	cmn_err(CE_WARN,
895*29949e86Sstevel 	    "sysctrl%d: Initialization failure. Some system level events,"
896*29949e86Sstevel 	    " {AC Fail, Fan Failure, PS Failure} not detected", instance);
897*29949e86Sstevel 	return (DDI_FAILURE);
898*29949e86Sstevel }
899*29949e86Sstevel 
900*29949e86Sstevel struct sysc_hold {
901*29949e86Sstevel 	int start;
902*29949e86Sstevel 	int limit;
903*29949e86Sstevel 	int incr;
904*29949e86Sstevel 	int hold;
905*29949e86Sstevel };
906*29949e86Sstevel 
907*29949e86Sstevel static int
908*29949e86Sstevel sysctrl_hold_rele_branches(dev_info_t *dip, void *arg)
909*29949e86Sstevel {
910*29949e86Sstevel 	int *rp, len, slot, i;
911*29949e86Sstevel 	struct sysc_hold *ap = (struct sysc_hold *)arg;
912*29949e86Sstevel 
913*29949e86Sstevel 	/*
914*29949e86Sstevel 	 * For Sunfire, top nodes on board are always children of root dip
915*29949e86Sstevel 	 */
916*29949e86Sstevel 	ASSERT(ddi_get_parent(dip) == ddi_root_node());
917*29949e86Sstevel 
918*29949e86Sstevel 	/*
919*29949e86Sstevel 	 * Skip non-PROM and "central" nodes
920*29949e86Sstevel 	 */
921*29949e86Sstevel 	if (!ndi_dev_is_prom_node(dip) ||
922*29949e86Sstevel 	    strcmp(ddi_node_name(dip), "central") == 0)
923*29949e86Sstevel 		return (DDI_WALK_PRUNECHILD);
924*29949e86Sstevel 
925*29949e86Sstevel 	/*
926*29949e86Sstevel 	 * Extract board # from reg property.
927*29949e86Sstevel 	 */
928*29949e86Sstevel 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
929*29949e86Sstevel 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", (caddr_t)&rp, &len)
930*29949e86Sstevel 	    != DDI_SUCCESS) {
931*29949e86Sstevel 		DPRINTF(SYSC_DEBUG, ("devinfo node %s(%p) has no reg"
932*29949e86Sstevel 		    " property\n", ddi_node_name(dip), (void *)dip));
933*29949e86Sstevel 		return (DDI_WALK_PRUNECHILD);
934*29949e86Sstevel 	}
935*29949e86Sstevel 
936*29949e86Sstevel 	slot = (*rp - 0x1c0) >> 2;
937*29949e86Sstevel 	kmem_free(rp, len);
938*29949e86Sstevel 
939*29949e86Sstevel 	ASSERT(ap->start >= 0 && ap->start < ap->limit);
940*29949e86Sstevel 
941*29949e86Sstevel 	for (i = ap->start; i < ap->limit; i = i + ap->incr) {
942*29949e86Sstevel 		if (i == slot)
943*29949e86Sstevel 			break;
944*29949e86Sstevel 	}
945*29949e86Sstevel 
946*29949e86Sstevel 	if (i >= ap->limit) {
947*29949e86Sstevel 		DPRINTF(SYSC_DEBUG, ("sysctrl_hold_rele: Invalid board # (%d)"
948*29949e86Sstevel 		    " for node %s(%p)\n", slot, ddi_node_name(dip),
949*29949e86Sstevel 		    (void *)dip));
950*29949e86Sstevel 		return (DDI_WALK_PRUNECHILD);
951*29949e86Sstevel 	}
952*29949e86Sstevel 
953*29949e86Sstevel 	if (ap->hold) {
954*29949e86Sstevel 		ASSERT(!e_ddi_branch_held(dip));
955*29949e86Sstevel 		e_ddi_branch_hold(dip);
956*29949e86Sstevel 	} else {
957*29949e86Sstevel 		ASSERT(e_ddi_branch_held(dip));
958*29949e86Sstevel 		e_ddi_branch_rele(dip);
959*29949e86Sstevel 	}
960*29949e86Sstevel 
961*29949e86Sstevel 	return (DDI_WALK_PRUNECHILD);
962*29949e86Sstevel }
963*29949e86Sstevel 
964*29949e86Sstevel /* ARGSUSED */
965*29949e86Sstevel static int
966*29949e86Sstevel sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
967*29949e86Sstevel {
968*29949e86Sstevel #ifdef	SYSCTRL_SUPPORTS_DETACH
969*29949e86Sstevel 	dev_info_t			*rdip;
970*29949e86Sstevel 	struct sysc_hold		arg = {0};
971*29949e86Sstevel 	struct sysctrl_soft_state	*softsp;
972*29949e86Sstevel #endif	/* SYSCTRL_SUPPORTS_DETACH */
973*29949e86Sstevel 
974*29949e86Sstevel 	if (sysctrl_enable_detach_suspend == FALSE)
975*29949e86Sstevel 		return (DDI_FAILURE);
976*29949e86Sstevel 
977*29949e86Sstevel 	switch (cmd) {
978*29949e86Sstevel 	case DDI_SUSPEND:
979*29949e86Sstevel 		/*
980*29949e86Sstevel 		 * XXX we don't presently save the state of the remote
981*29949e86Sstevel 		 * console because it is a constant function of POST.
982*29949e86Sstevel 		 * XXX we don't deal with the hardware watchdog here
983*29949e86Sstevel 		 * either.  It should be handled in hardclk.
984*29949e86Sstevel 		 */
985*29949e86Sstevel 		return (DDI_SUCCESS);
986*29949e86Sstevel 
987*29949e86Sstevel 	case DDI_DETACH:
988*29949e86Sstevel 		break;
989*29949e86Sstevel 	default:
990*29949e86Sstevel 		return (DDI_FAILURE);
991*29949e86Sstevel 	}
992*29949e86Sstevel 
993*29949e86Sstevel #ifdef	SYSCTRL_SUPPORTS_DETACH
994*29949e86Sstevel 
995*29949e86Sstevel 	/*
996*29949e86Sstevel 	 * XXX If sysctrl ever supports detach, this code should be enabled
997*29949e86Sstevel 	 * This is only the portion of the detach code dealing with
998*29949e86Sstevel 	 * the DDI branch routines. Other parts of detach will need
999*29949e86Sstevel 	 * to be added.
1000*29949e86Sstevel 	 */
1001*29949e86Sstevel 
1002*29949e86Sstevel 	/*
1003*29949e86Sstevel 	 * Walk immediate children of root devinfo node, releasing holds
1004*29949e86Sstevel 	 * on branches acquired in first sysctrl_open().
1005*29949e86Sstevel 	 */
1006*29949e86Sstevel 
1007*29949e86Sstevel 	instance = ddi_get_instance(dip);
1008*29949e86Sstevel 	softsp = GETSOFTC(instance);
1009*29949e86Sstevel 
1010*29949e86Sstevel 	if (softsp == NULL) {
1011*29949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d device not attached", instance);
1012*29949e86Sstevel 		return (DDI_FAILURE);
1013*29949e86Sstevel 	}
1014*29949e86Sstevel 
1015*29949e86Sstevel 	sysc_slot_info(softsp->nslots, &arg.start, &arg.limit, &arg.incr);
1016*29949e86Sstevel 
1017*29949e86Sstevel 	arg.hold = 0;
1018*29949e86Sstevel 
1019*29949e86Sstevel 	rdip = ddi_root_node();
1020*29949e86Sstevel 
1021*29949e86Sstevel 	ndi_devi_enter(rdip, &circ);
1022*29949e86Sstevel 	ddi_walk_devs(ddi_get_child(rdip), sysctrl_hold_rele_branches, &arg);
1023*29949e86Sstevel 	ndi_devi_exit(rdip, circ);
1024*29949e86Sstevel 
1025*29949e86Sstevel 	sysctrl_ddi_branch_init = 0;
1026*29949e86Sstevel 
1027*29949e86Sstevel 	return (DDI_SUCCESS);
1028*29949e86Sstevel #endif	/* SYSCTRL_SUPPORTS_DETACH */
1029*29949e86Sstevel 
1030*29949e86Sstevel 	return (DDI_FAILURE);
1031*29949e86Sstevel }
1032*29949e86Sstevel 
1033*29949e86Sstevel /* ARGSUSED */
1034*29949e86Sstevel static int
1035*29949e86Sstevel sysctrl_open(dev_t *devp, int flag, int otyp, cred_t *credp)
1036*29949e86Sstevel {
1037*29949e86Sstevel 	int		instance;
1038*29949e86Sstevel 	int		slot;
1039*29949e86Sstevel 	dev_t		dev;
1040*29949e86Sstevel 	int		circ;
1041*29949e86Sstevel 	dev_info_t	*rdip;
1042*29949e86Sstevel 	struct sysc_hold arg = {0};
1043*29949e86Sstevel 	struct sysctrl_soft_state *softsp;
1044*29949e86Sstevel 
1045*29949e86Sstevel 	dev = *devp;
1046*29949e86Sstevel 
1047*29949e86Sstevel 	/*
1048*29949e86Sstevel 	 * We checked against the instance softstate structure since there
1049*29949e86Sstevel 	 * will only be one instance of sysctrl (clock board) in UEXX00
1050*29949e86Sstevel 	 *
1051*29949e86Sstevel 	 * Since we only create minor devices for existing slots on a
1052*29949e86Sstevel 	 * particular system, we don't need to worry about non-exist slot.
1053*29949e86Sstevel 	 */
1054*29949e86Sstevel 
1055*29949e86Sstevel 	instance = GETINSTANCE(dev);
1056*29949e86Sstevel 	slot = GETSLOT(dev);
1057*29949e86Sstevel 
1058*29949e86Sstevel 	/* Is the instance attached? */
1059*29949e86Sstevel 	if ((softsp = GETSOFTC(instance)) == NULL) {
1060*29949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d device not attached", instance);
1061*29949e86Sstevel 		return (ENXIO);
1062*29949e86Sstevel 	}
1063*29949e86Sstevel 
1064*29949e86Sstevel 	/* verify that otyp is appropriate */
1065*29949e86Sstevel 	if (otyp != OTYP_CHR) {
1066*29949e86Sstevel 		return (EINVAL);
1067*29949e86Sstevel 	}
1068*29949e86Sstevel 
1069*29949e86Sstevel 	if (!fhc_bd_valid(slot))
1070*29949e86Sstevel 		return (ENXIO);
1071*29949e86Sstevel 
1072*29949e86Sstevel 	/*
1073*29949e86Sstevel 	 * On first open of a sysctrl minor walk immediate children of the
1074*29949e86Sstevel 	 * devinfo root node and hold all branches of interest.
1075*29949e86Sstevel 	 */
1076*29949e86Sstevel 	mutex_enter(&sysctrl_branch_mutex);
1077*29949e86Sstevel 	if (!sysctrl_ddi_branch_init) {
1078*29949e86Sstevel 
1079*29949e86Sstevel 		sysctrl_ddi_branch_init = 1;
1080*29949e86Sstevel 
1081*29949e86Sstevel 		sysc_slot_info(softsp->nslots, &arg.start, &arg.limit,
1082*29949e86Sstevel 		    &arg.incr);
1083*29949e86Sstevel 		arg.hold = 1;
1084*29949e86Sstevel 
1085*29949e86Sstevel 		rdip = ddi_root_node();
1086*29949e86Sstevel 
1087*29949e86Sstevel 		ndi_devi_enter(rdip, &circ);
1088*29949e86Sstevel 		ddi_walk_devs(ddi_get_child(rdip), sysctrl_hold_rele_branches,
1089*29949e86Sstevel 		    &arg);
1090*29949e86Sstevel 		ndi_devi_exit(rdip, circ);
1091*29949e86Sstevel 	}
1092*29949e86Sstevel 	mutex_exit(&sysctrl_branch_mutex);
1093*29949e86Sstevel 
1094*29949e86Sstevel 	return (DDI_SUCCESS);
1095*29949e86Sstevel }
1096*29949e86Sstevel 
1097*29949e86Sstevel /* ARGSUSED */
1098*29949e86Sstevel static int
1099*29949e86Sstevel sysctrl_close(dev_t devp, int flag, int otyp, cred_t *credp)
1100*29949e86Sstevel {
1101*29949e86Sstevel 	return (DDI_SUCCESS);
1102*29949e86Sstevel }
1103*29949e86Sstevel 
1104*29949e86Sstevel /*
1105*29949e86Sstevel  * This function will acquire the lock and set the in_transition
1106*29949e86Sstevel  * bit for the specified slot.  If the slot is being used,
1107*29949e86Sstevel  * we return FALSE; else set in_transition and return TRUE.
1108*29949e86Sstevel  */
1109*29949e86Sstevel static int
1110*29949e86Sstevel sysc_enter_transition(int slot)
1111*29949e86Sstevel {
1112*29949e86Sstevel 	fhc_bd_t	*list;
1113*29949e86Sstevel 	sysc_cfga_stat_t *sysc_stat_lk;
1114*29949e86Sstevel 	fhc_bd_t	*glist;
1115*29949e86Sstevel 	sysc_cfga_stat_t *sysc_stat_gk;
1116*29949e86Sstevel 
1117*29949e86Sstevel 	/* mutex lock the structure */
1118*29949e86Sstevel 	list = fhc_bdlist_lock(slot);
1119*29949e86Sstevel 	if ((slot != -1) && (list == NULL)) {
1120*29949e86Sstevel 		fhc_bdlist_unlock();
1121*29949e86Sstevel 		return (FALSE);
1122*29949e86Sstevel 	}
1123*29949e86Sstevel 
1124*29949e86Sstevel 	glist = fhc_bd_clock();
1125*29949e86Sstevel 	if (slot == -1)
1126*29949e86Sstevel 		list = glist;
1127*29949e86Sstevel 
1128*29949e86Sstevel 	/* change the in_transition bit */
1129*29949e86Sstevel 	sysc_stat_lk = &list->sc;
1130*29949e86Sstevel 	sysc_stat_gk = &glist->sc;
1131*29949e86Sstevel 	if ((sysc_stat_lk->in_transition == TRUE) ||
1132*29949e86Sstevel 	    (sysc_stat_gk->in_transition == TRUE)) {
1133*29949e86Sstevel 		fhc_bdlist_unlock();
1134*29949e86Sstevel 		return (FALSE);
1135*29949e86Sstevel 	} else {
1136*29949e86Sstevel 		sysc_stat_lk->in_transition = TRUE;
1137*29949e86Sstevel 		return (TRUE);
1138*29949e86Sstevel 	}
1139*29949e86Sstevel }
1140*29949e86Sstevel 
1141*29949e86Sstevel /*
1142*29949e86Sstevel  * This function will release the lock and clear the in_transition
1143*29949e86Sstevel  * bit for the specified slot.
1144*29949e86Sstevel  */
1145*29949e86Sstevel static void
1146*29949e86Sstevel sysc_exit_transition(int slot)
1147*29949e86Sstevel {
1148*29949e86Sstevel 	fhc_bd_t	*list;
1149*29949e86Sstevel 	sysc_cfga_stat_t *sysc_stat_lk;
1150*29949e86Sstevel 
1151*29949e86Sstevel 	ASSERT(fhc_bdlist_locked());
1152*29949e86Sstevel 
1153*29949e86Sstevel 	if (slot == -1)
1154*29949e86Sstevel 		list = fhc_bd_clock();
1155*29949e86Sstevel 	else
1156*29949e86Sstevel 		list = fhc_bd(slot);
1157*29949e86Sstevel 	sysc_stat_lk = &list->sc;
1158*29949e86Sstevel 	ASSERT(sysc_stat_lk->in_transition == TRUE);
1159*29949e86Sstevel 	sysc_stat_lk->in_transition = FALSE;
1160*29949e86Sstevel 	fhc_bdlist_unlock();
1161*29949e86Sstevel }
1162*29949e86Sstevel 
1163*29949e86Sstevel static int
1164*29949e86Sstevel sysc_pkt_init(sysc_cfga_pkt_t *pkt, intptr_t arg, int flag)
1165*29949e86Sstevel {
1166*29949e86Sstevel #ifdef _MULTI_DATAMODEL
1167*29949e86Sstevel 	if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
1168*29949e86Sstevel 		sysc_cfga_cmd32_t sysc_cmd32;
1169*29949e86Sstevel 
1170*29949e86Sstevel 		if (ddi_copyin((void *)arg, &sysc_cmd32,
1171*29949e86Sstevel 			sizeof (sysc_cfga_cmd32_t), flag) != 0) {
1172*29949e86Sstevel 			return (EFAULT);
1173*29949e86Sstevel 		}
1174*29949e86Sstevel 		pkt->cmd_cfga.force = sysc_cmd32.force;
1175*29949e86Sstevel 		pkt->cmd_cfga.test = sysc_cmd32.test;
1176*29949e86Sstevel 		pkt->cmd_cfga.arg = sysc_cmd32.arg;
1177*29949e86Sstevel 		pkt->cmd_cfga.errtype = sysc_cmd32.errtype;
1178*29949e86Sstevel 		pkt->cmd_cfga.outputstr =
1179*29949e86Sstevel 			(char *)(uintptr_t)sysc_cmd32.outputstr;
1180*29949e86Sstevel 	} else
1181*29949e86Sstevel #endif /* _MULTI_DATAMODEL */
1182*29949e86Sstevel 	if (ddi_copyin((void *)arg, &(pkt->cmd_cfga),
1183*29949e86Sstevel 		sizeof (sysc_cfga_cmd_t), flag) != 0) {
1184*29949e86Sstevel 		return (EFAULT);
1185*29949e86Sstevel 	}
1186*29949e86Sstevel 	pkt->errbuf = kmem_zalloc(SYSC_OUTPUT_LEN, KM_SLEEP);
1187*29949e86Sstevel 	return (0);
1188*29949e86Sstevel }
1189*29949e86Sstevel 
1190*29949e86Sstevel static int
1191*29949e86Sstevel sysc_pkt_fini(sysc_cfga_pkt_t *pkt, intptr_t arg, int flag)
1192*29949e86Sstevel {
1193*29949e86Sstevel 	int ret = TRUE;
1194*29949e86Sstevel 
1195*29949e86Sstevel #ifdef _MULTI_DATAMODEL
1196*29949e86Sstevel 	if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
1197*29949e86Sstevel 
1198*29949e86Sstevel 		if (ddi_copyout(&(pkt->cmd_cfga.errtype),
1199*29949e86Sstevel 			(void *)&(((sysc_cfga_cmd32_t *)arg)->errtype),
1200*29949e86Sstevel 			sizeof (sysc_err_t), flag) != 0) {
1201*29949e86Sstevel 			ret = FALSE;
1202*29949e86Sstevel 		}
1203*29949e86Sstevel 	} else
1204*29949e86Sstevel #endif
1205*29949e86Sstevel 	if (ddi_copyout(&(pkt->cmd_cfga.errtype),
1206*29949e86Sstevel 		(void *)&(((sysc_cfga_cmd_t *)arg)->errtype),
1207*29949e86Sstevel 		sizeof (sysc_err_t), flag) != 0) {
1208*29949e86Sstevel 		ret = FALSE;
1209*29949e86Sstevel 	}
1210*29949e86Sstevel 
1211*29949e86Sstevel 	if ((ret != FALSE) && ((pkt->cmd_cfga.outputstr != NULL) &&
1212*29949e86Sstevel 		(ddi_copyout(pkt->errbuf, pkt->cmd_cfga.outputstr,
1213*29949e86Sstevel 			SYSC_OUTPUT_LEN, flag) != 0))) {
1214*29949e86Sstevel 			ret = FALSE;
1215*29949e86Sstevel 	}
1216*29949e86Sstevel 
1217*29949e86Sstevel 	kmem_free(pkt->errbuf, SYSC_OUTPUT_LEN);
1218*29949e86Sstevel 	return (ret);
1219*29949e86Sstevel }
1220*29949e86Sstevel 
1221*29949e86Sstevel /* ARGSUSED */
1222*29949e86Sstevel static int
1223*29949e86Sstevel sysctrl_ioctl(dev_t devt, int cmd, intptr_t arg, int flag, cred_t *cred_p,
1224*29949e86Sstevel 		int *rval_p)
1225*29949e86Sstevel {
1226*29949e86Sstevel 	struct sysctrl_soft_state *softsp;
1227*29949e86Sstevel 	sysc_cfga_pkt_t sysc_pkt;
1228*29949e86Sstevel 	fhc_bd_t *fhc_list = NULL;
1229*29949e86Sstevel 	sysc_cfga_stat_t *sc_list = NULL;
1230*29949e86Sstevel 	fhc_bd_t *bdp;
1231*29949e86Sstevel 	sysc_cfga_stat_t *sc = NULL;
1232*29949e86Sstevel 	int instance;
1233*29949e86Sstevel 	int slot;
1234*29949e86Sstevel 	int retval = 0;
1235*29949e86Sstevel 	int i;
1236*29949e86Sstevel 
1237*29949e86Sstevel 	instance = GETINSTANCE(devt);
1238*29949e86Sstevel 	softsp = GETSOFTC(instance);
1239*29949e86Sstevel 	if (softsp == NULL) {
1240*29949e86Sstevel 		cmn_err(CE_CONT,
1241*29949e86Sstevel 			"sysctrl_ioctl(%d): NULL softstate ptr!\n",
1242*29949e86Sstevel 			(int)GETSLOT(devt));
1243*29949e86Sstevel 		return (ENXIO);
1244*29949e86Sstevel 	}
1245*29949e86Sstevel 
1246*29949e86Sstevel 	slot = GETSLOT(devt);
1247*29949e86Sstevel 
1248*29949e86Sstevel 	/*
1249*29949e86Sstevel 	 * First switch is to do correct locking and do ddi_copyin()
1250*29949e86Sstevel 	 */
1251*29949e86Sstevel 	switch (cmd) {
1252*29949e86Sstevel 	case SYSC_CFGA_CMD_GETSTATUS:
1253*29949e86Sstevel 		/* mutex lock the whole list */
1254*29949e86Sstevel 		if (sysc_enter_transition(-1) != TRUE) {
1255*29949e86Sstevel 			retval = EBUSY;
1256*29949e86Sstevel 			goto cleanup_exit;
1257*29949e86Sstevel 		}
1258*29949e86Sstevel 
1259*29949e86Sstevel 		/* allocate the memory before acquiring mutex */
1260*29949e86Sstevel 		fhc_list = kmem_zalloc(sizeof (fhc_bd_t) * fhc_max_boards(),
1261*29949e86Sstevel 		    KM_SLEEP);
1262*29949e86Sstevel 
1263*29949e86Sstevel 		sc_list = kmem_zalloc(sizeof (sysc_cfga_stat_t) *
1264*29949e86Sstevel 		    fhc_max_boards(), KM_SLEEP);
1265*29949e86Sstevel 
1266*29949e86Sstevel 		break;
1267*29949e86Sstevel 
1268*29949e86Sstevel 	case SYSC_CFGA_CMD_EJECT:
1269*29949e86Sstevel 	case SYSC_CFGA_CMD_INSERT:
1270*29949e86Sstevel 		retval = ENOTSUP;
1271*29949e86Sstevel 		goto cleanup_exit;
1272*29949e86Sstevel 
1273*29949e86Sstevel 	case SYSC_CFGA_CMD_CONNECT:
1274*29949e86Sstevel 	case SYSC_CFGA_CMD_DISCONNECT:
1275*29949e86Sstevel 	case SYSC_CFGA_CMD_UNCONFIGURE:
1276*29949e86Sstevel 	case SYSC_CFGA_CMD_CONFIGURE:
1277*29949e86Sstevel 	case SYSC_CFGA_CMD_TEST:
1278*29949e86Sstevel 	case SYSC_CFGA_CMD_TEST_SET_COND:
1279*29949e86Sstevel 	case SYSC_CFGA_CMD_QUIESCE_TEST:
1280*29949e86Sstevel 
1281*29949e86Sstevel 		/* ioctls allowed if caller has write permission */
1282*29949e86Sstevel 		if (!(flag & FWRITE)) {
1283*29949e86Sstevel 			retval = EPERM;
1284*29949e86Sstevel 			goto cleanup_exit;
1285*29949e86Sstevel 		}
1286*29949e86Sstevel 
1287*29949e86Sstevel 		retval = sysc_pkt_init(&sysc_pkt, arg, flag);
1288*29949e86Sstevel 		if (retval != 0)
1289*29949e86Sstevel 			goto cleanup_exit;
1290*29949e86Sstevel 
1291*29949e86Sstevel 		/* grasp lock and set in_transition bit */
1292*29949e86Sstevel 		if (sysc_enter_transition(cmd == SYSC_CFGA_CMD_QUIESCE_TEST
1293*29949e86Sstevel 				? -1 : slot) != TRUE) {
1294*29949e86Sstevel 			retval = EBUSY;
1295*29949e86Sstevel 			SYSC_ERR_SET(&sysc_pkt, SYSC_ERR_INTRANS);
1296*29949e86Sstevel 			goto cleanup_copyout;
1297*29949e86Sstevel 		}
1298*29949e86Sstevel 
1299*29949e86Sstevel 		/* get the status structure for the slot */
1300*29949e86Sstevel 		bdp = fhc_bd(slot);
1301*29949e86Sstevel 		sc = &bdp->sc;
1302*29949e86Sstevel 		break;
1303*29949e86Sstevel 
1304*29949e86Sstevel 	/* POSIX definition: return ENOTTY if unsupported command */
1305*29949e86Sstevel 	default:
1306*29949e86Sstevel 		retval = ENOTTY;
1307*29949e86Sstevel 		goto cleanup_exit;
1308*29949e86Sstevel 	}
1309*29949e86Sstevel 
1310*29949e86Sstevel 	/*
1311*29949e86Sstevel 	 * Second switch is to call the underlayer workhorse.
1312*29949e86Sstevel 	 */
1313*29949e86Sstevel 	switch (cmd) {
1314*29949e86Sstevel 	case SYSC_CFGA_CMD_GETSTATUS:
1315*29949e86Sstevel 		for (i = 0; i < fhc_max_boards(); i++) {
1316*29949e86Sstevel 			if (fhc_bd_valid(i)) {
1317*29949e86Sstevel 				bdp = fhc_bd(i);
1318*29949e86Sstevel 				if (fhc_bd_is_jtag_master(i))
1319*29949e86Sstevel 					bdp->sc.no_detach = 1;
1320*29949e86Sstevel 				else
1321*29949e86Sstevel 					bdp->sc.no_detach = 0;
1322*29949e86Sstevel 				bcopy((caddr_t)&bdp->sc,
1323*29949e86Sstevel 					&sc_list[i], sizeof (sysc_cfga_stat_t));
1324*29949e86Sstevel 			} else {
1325*29949e86Sstevel 				sc_list[i].board = -1;
1326*29949e86Sstevel 				sc_list[i].rstate = SYSC_CFGA_RSTATE_EMPTY;
1327*29949e86Sstevel 			}
1328*29949e86Sstevel 		}
1329*29949e86Sstevel 
1330*29949e86Sstevel 		sysc_exit_transition(-1);
1331*29949e86Sstevel 
1332*29949e86Sstevel 		break;
1333*29949e86Sstevel 
1334*29949e86Sstevel 	case SYSC_CFGA_CMD_EJECT:
1335*29949e86Sstevel 	case SYSC_CFGA_CMD_INSERT:
1336*29949e86Sstevel 		retval = ENOTSUP;
1337*29949e86Sstevel 		goto cleanup_exit;
1338*29949e86Sstevel 
1339*29949e86Sstevel 	case SYSC_CFGA_CMD_CONNECT:
1340*29949e86Sstevel 		retval = sysc_policy_connect(softsp, &sysc_pkt, sc);
1341*29949e86Sstevel 		sysc_exit_transition(slot);
1342*29949e86Sstevel 		break;
1343*29949e86Sstevel 
1344*29949e86Sstevel 	case SYSC_CFGA_CMD_DISCONNECT:
1345*29949e86Sstevel 		retval = sysc_policy_disconnect(softsp, &sysc_pkt, sc);
1346*29949e86Sstevel 		sysc_exit_transition(slot);
1347*29949e86Sstevel 		break;
1348*29949e86Sstevel 
1349*29949e86Sstevel 	case SYSC_CFGA_CMD_UNCONFIGURE:
1350*29949e86Sstevel 		retval = sysc_policy_unconfigure(softsp, &sysc_pkt, sc);
1351*29949e86Sstevel 		sysc_exit_transition(slot);
1352*29949e86Sstevel 		break;
1353*29949e86Sstevel 
1354*29949e86Sstevel 	case SYSC_CFGA_CMD_CONFIGURE:
1355*29949e86Sstevel 		retval = sysc_policy_configure(softsp, &sysc_pkt, sc);
1356*29949e86Sstevel 		sysc_exit_transition(slot);
1357*29949e86Sstevel 		break;
1358*29949e86Sstevel 
1359*29949e86Sstevel 	case SYSC_CFGA_CMD_TEST:
1360*29949e86Sstevel 		retval = fhc_bd_test(slot, &sysc_pkt);
1361*29949e86Sstevel 		sysc_exit_transition(slot);
1362*29949e86Sstevel 		break;
1363*29949e86Sstevel 
1364*29949e86Sstevel 	case SYSC_CFGA_CMD_TEST_SET_COND:
1365*29949e86Sstevel 		retval = fhc_bd_test_set_cond(slot, &sysc_pkt);
1366*29949e86Sstevel 		sysc_exit_transition(slot);
1367*29949e86Sstevel 		break;
1368*29949e86Sstevel 
1369*29949e86Sstevel 	case SYSC_CFGA_CMD_QUIESCE_TEST:
1370*29949e86Sstevel 		sysctrl_suspend_prepare();
1371*29949e86Sstevel 		fhc_bdlist_unlock();
1372*29949e86Sstevel 
1373*29949e86Sstevel 		if (sysctrl_suspend(&sysc_pkt) == DDI_SUCCESS) {
1374*29949e86Sstevel 			sysctrl_resume(&sysc_pkt);
1375*29949e86Sstevel 		} else {
1376*29949e86Sstevel 			retval = EBUSY;
1377*29949e86Sstevel 		}
1378*29949e86Sstevel 
1379*29949e86Sstevel 		(void) fhc_bdlist_lock(-1);
1380*29949e86Sstevel 		sysc_exit_transition(-1);
1381*29949e86Sstevel 		break;
1382*29949e86Sstevel 
1383*29949e86Sstevel 	default:
1384*29949e86Sstevel 		retval = ENOTTY;
1385*29949e86Sstevel 		goto cleanup_exit;
1386*29949e86Sstevel 	}
1387*29949e86Sstevel 
1388*29949e86Sstevel cleanup_copyout:
1389*29949e86Sstevel 	/*
1390*29949e86Sstevel 	 * 3rd switch is to do appropriate copyout and reset locks
1391*29949e86Sstevel 	 */
1392*29949e86Sstevel 	switch (cmd) {
1393*29949e86Sstevel 	case SYSC_CFGA_CMD_GETSTATUS:
1394*29949e86Sstevel 		if (ddi_copyout(sc_list, (void *)arg,
1395*29949e86Sstevel 			sizeof (sysc_cfga_stat_t) * fhc_max_boards(),
1396*29949e86Sstevel 			    flag) != 0) {
1397*29949e86Sstevel 			retval = EFAULT;
1398*29949e86Sstevel 		}
1399*29949e86Sstevel 
1400*29949e86Sstevel 		/* cleanup memory */
1401*29949e86Sstevel 		kmem_free(fhc_list, sizeof (fhc_bd_t) * fhc_max_boards());
1402*29949e86Sstevel 		kmem_free(sc_list, sizeof (sysc_cfga_stat_t) *
1403*29949e86Sstevel 		    fhc_max_boards());
1404*29949e86Sstevel 		break;
1405*29949e86Sstevel 
1406*29949e86Sstevel 	case SYSC_CFGA_CMD_EJECT:
1407*29949e86Sstevel 	case SYSC_CFGA_CMD_INSERT:
1408*29949e86Sstevel 		retval = ENOTSUP;
1409*29949e86Sstevel 		break;
1410*29949e86Sstevel 
1411*29949e86Sstevel 	case SYSC_CFGA_CMD_CONNECT:
1412*29949e86Sstevel 	case SYSC_CFGA_CMD_DISCONNECT:
1413*29949e86Sstevel 	case SYSC_CFGA_CMD_UNCONFIGURE:
1414*29949e86Sstevel 	case SYSC_CFGA_CMD_CONFIGURE:
1415*29949e86Sstevel 	case SYSC_CFGA_CMD_TEST:
1416*29949e86Sstevel 	case SYSC_CFGA_CMD_TEST_SET_COND:
1417*29949e86Sstevel 	case SYSC_CFGA_CMD_QUIESCE_TEST:
1418*29949e86Sstevel 		if (sysc_pkt_fini(&sysc_pkt, arg, flag) != TRUE)
1419*29949e86Sstevel 			return (EFAULT);
1420*29949e86Sstevel 		break;
1421*29949e86Sstevel 
1422*29949e86Sstevel 	default:
1423*29949e86Sstevel 		retval = ENOTTY;
1424*29949e86Sstevel 		break;
1425*29949e86Sstevel 	}
1426*29949e86Sstevel 
1427*29949e86Sstevel cleanup_exit:
1428*29949e86Sstevel 	return (retval);
1429*29949e86Sstevel }
1430*29949e86Sstevel 
1431*29949e86Sstevel /*
1432*29949e86Sstevel  * system_high_handler()
1433*29949e86Sstevel  * This routine handles system interrupts.
1434*29949e86Sstevel  *
1435*29949e86Sstevel  * This routine goes through all the interrupt sources and masks
1436*29949e86Sstevel  * off the enable bit if interrupting.  Because of the special
1437*29949e86Sstevel  * nature of the pps fan source bits, we also cache the state
1438*29949e86Sstevel  * of the fan bits for that special case.
1439*29949e86Sstevel  *
1440*29949e86Sstevel  * The rest of the work is done in the low level handlers
1441*29949e86Sstevel  */
1442*29949e86Sstevel static uint_t
1443*29949e86Sstevel system_high_handler(caddr_t arg)
1444*29949e86Sstevel {
1445*29949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1446*29949e86Sstevel 	uchar_t csr;
1447*29949e86Sstevel 	uchar_t status2;
1448*29949e86Sstevel 	uchar_t tmp_reg;
1449*29949e86Sstevel 	int serviced = 0;
1450*29949e86Sstevel 
1451*29949e86Sstevel 	ASSERT(softsp);
1452*29949e86Sstevel 
1453*29949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
1454*29949e86Sstevel 
1455*29949e86Sstevel 	/* read in the hardware registers */
1456*29949e86Sstevel 	csr = *(softsp->csr);
1457*29949e86Sstevel 	status2 = *(softsp->status2);
1458*29949e86Sstevel 
1459*29949e86Sstevel 	if (csr & SYS_AC_PWR_FAIL_EN) {
1460*29949e86Sstevel 		if (status2 & SYS_AC_FAIL) {
1461*29949e86Sstevel 
1462*29949e86Sstevel 			/* save the powerfail state in nvram */
1463*29949e86Sstevel 			nvram_update_powerfail(softsp);
1464*29949e86Sstevel 
1465*29949e86Sstevel 			/* disable this interrupt source */
1466*29949e86Sstevel 			csr &= ~SYS_AC_PWR_FAIL_EN;
1467*29949e86Sstevel 
1468*29949e86Sstevel 			ddi_trigger_softintr(softsp->ac_fail_id);
1469*29949e86Sstevel 			serviced++;
1470*29949e86Sstevel 		}
1471*29949e86Sstevel 	}
1472*29949e86Sstevel 
1473*29949e86Sstevel 	if (csr & SYS_PS_FAIL_EN) {
1474*29949e86Sstevel 		if ((*(softsp->ps_stat) != 0xff) ||
1475*29949e86Sstevel 		    ((~status2) & (SYS_PPS0_OK | SYS_CLK_33_OK |
1476*29949e86Sstevel 			SYS_CLK_50_OK)) ||
1477*29949e86Sstevel 		    (~(*(softsp->pppsr)) & SYS_PPPSR_BITS)) {
1478*29949e86Sstevel 
1479*29949e86Sstevel 			/* disable this interrupt source */
1480*29949e86Sstevel 			csr &= ~SYS_PS_FAIL_EN;
1481*29949e86Sstevel 
1482*29949e86Sstevel 			ddi_trigger_softintr(softsp->ps_fail_int_id);
1483*29949e86Sstevel 			serviced++;
1484*29949e86Sstevel 		}
1485*29949e86Sstevel 	}
1486*29949e86Sstevel 
1487*29949e86Sstevel 	if (csr & SYS_PPS_FAN_FAIL_EN) {
1488*29949e86Sstevel 		if (status2 & SYS_RACK_FANFAIL ||
1489*29949e86Sstevel 		    !(status2 & SYS_AC_FAN_OK) ||
1490*29949e86Sstevel 		    !(status2 & SYS_KEYSW_FAN_OK)) {
1491*29949e86Sstevel 
1492*29949e86Sstevel 			/*
1493*29949e86Sstevel 			 * we must cache the fan status because it goes
1494*29949e86Sstevel 			 * away when we disable interrupts !?!?!
1495*29949e86Sstevel 			 */
1496*29949e86Sstevel 			softsp->pps_fan_saved = status2;
1497*29949e86Sstevel 
1498*29949e86Sstevel 			/* disable this interrupt source */
1499*29949e86Sstevel 			csr &= ~SYS_PPS_FAN_FAIL_EN;
1500*29949e86Sstevel 
1501*29949e86Sstevel 			ddi_trigger_softintr(softsp->pps_fan_id);
1502*29949e86Sstevel 			serviced++;
1503*29949e86Sstevel 		}
1504*29949e86Sstevel 	}
1505*29949e86Sstevel 
1506*29949e86Sstevel 	if (csr & SYS_SBRD_PRES_EN) {
1507*29949e86Sstevel 		if (!(*(softsp->status1) & SYS_NOT_BRD_PRES)) {
1508*29949e86Sstevel 
1509*29949e86Sstevel 			/* disable this interrupt source */
1510*29949e86Sstevel 			csr &= ~SYS_SBRD_PRES_EN;
1511*29949e86Sstevel 
1512*29949e86Sstevel 			ddi_trigger_softintr(softsp->sbrd_pres_id);
1513*29949e86Sstevel 			serviced++;
1514*29949e86Sstevel 		}
1515*29949e86Sstevel 	}
1516*29949e86Sstevel 
1517*29949e86Sstevel 	if (!serviced) {
1518*29949e86Sstevel 
1519*29949e86Sstevel 		/*
1520*29949e86Sstevel 		 * if we get here than it is likely that contact bounce
1521*29949e86Sstevel 		 * is messing with us.  so, we need to shut this interrupt
1522*29949e86Sstevel 		 * up for a while to let the contacts settle down.
1523*29949e86Sstevel 		 * Then we will re-enable the interrupts that are enabled
1524*29949e86Sstevel 		 * right now.  The trick is to disable the appropriate
1525*29949e86Sstevel 		 * interrupts and then to re-enable them correctly, even
1526*29949e86Sstevel 		 * though intervening handlers might have been working.
1527*29949e86Sstevel 		 */
1528*29949e86Sstevel 
1529*29949e86Sstevel 		/* remember all interrupts that could have caused it */
1530*29949e86Sstevel 		softsp->saved_en_state |= csr &
1531*29949e86Sstevel 		    (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
1532*29949e86Sstevel 		    SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
1533*29949e86Sstevel 
1534*29949e86Sstevel 		/* and then turn them off */
1535*29949e86Sstevel 		csr &= ~(SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
1536*29949e86Sstevel 			SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
1537*29949e86Sstevel 
1538*29949e86Sstevel 		/* and then bump the counter */
1539*29949e86Sstevel 		softsp->spur_count++;
1540*29949e86Sstevel 
1541*29949e86Sstevel 		/* and kick off the timeout */
1542*29949e86Sstevel 		ddi_trigger_softintr(softsp->spur_id);
1543*29949e86Sstevel 	}
1544*29949e86Sstevel 
1545*29949e86Sstevel 	/* update the real csr */
1546*29949e86Sstevel 	*(softsp->csr) = csr;
1547*29949e86Sstevel 	tmp_reg = *(softsp->csr);
1548*29949e86Sstevel #ifdef lint
1549*29949e86Sstevel 	tmp_reg = tmp_reg;
1550*29949e86Sstevel #endif
1551*29949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
1552*29949e86Sstevel 
1553*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
1554*29949e86Sstevel }
1555*29949e86Sstevel 
1556*29949e86Sstevel /*
1557*29949e86Sstevel  * we've detected a spurious interrupt.
1558*29949e86Sstevel  * determine if we should log a message and if we need another timeout
1559*29949e86Sstevel  */
1560*29949e86Sstevel static uint_t
1561*29949e86Sstevel spur_delay(caddr_t arg)
1562*29949e86Sstevel {
1563*29949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1564*29949e86Sstevel 
1565*29949e86Sstevel 	ASSERT(softsp);
1566*29949e86Sstevel 
1567*29949e86Sstevel 	/* do we need to complain? */
1568*29949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
1569*29949e86Sstevel 
1570*29949e86Sstevel 	/* NOTE: this is == because we want one message per long timeout */
1571*29949e86Sstevel 	if (softsp->spur_count == MAX_SPUR_COUNT) {
1572*29949e86Sstevel 		char buf[128];
1573*29949e86Sstevel 
1574*29949e86Sstevel 		/* print out the candidates known at this time */
1575*29949e86Sstevel 		/* XXX not perfect because of re-entrant nature but close */
1576*29949e86Sstevel 		buf[0] = '\0';
1577*29949e86Sstevel 		if (softsp->saved_en_state & SYS_AC_PWR_FAIL_EN)
1578*29949e86Sstevel 			(void) strcat(buf, "AC FAIL");
1579*29949e86Sstevel 		if (softsp->saved_en_state & SYS_PPS_FAN_FAIL_EN)
1580*29949e86Sstevel 			(void) strcat(buf, buf[0] ? "|PPS FANS" : "PPS FANS");
1581*29949e86Sstevel 		if (softsp->saved_en_state & SYS_PS_FAIL_EN)
1582*29949e86Sstevel 			(void) strcat(buf, buf[0] ? "|PS FAIL" : "PS FAIL");
1583*29949e86Sstevel 		if (softsp->saved_en_state & SYS_SBRD_PRES_EN)
1584*29949e86Sstevel 			(void) strcat(buf,
1585*29949e86Sstevel 				buf[0] ? "|BOARD INSERT" : "BOARD INSERT");
1586*29949e86Sstevel 
1587*29949e86Sstevel 		/*
1588*29949e86Sstevel 		 * This is a high level mutex, therefore it needs to be
1589*29949e86Sstevel 		 * dropped before calling cmn_err.
1590*29949e86Sstevel 		 */
1591*29949e86Sstevel 		mutex_exit(&softsp->csr_mutex);
1592*29949e86Sstevel 
1593*29949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: unserviced interrupt."
1594*29949e86Sstevel 				" possible sources [%s].",
1595*29949e86Sstevel 				ddi_get_instance(softsp->dip), buf);
1596*29949e86Sstevel 	} else
1597*29949e86Sstevel 		mutex_exit(&softsp->csr_mutex);
1598*29949e86Sstevel 
1599*29949e86Sstevel 	mutex_enter(&softsp->spur_int_lock);
1600*29949e86Sstevel 
1601*29949e86Sstevel 	/* do we need to start the short timeout? */
1602*29949e86Sstevel 	if (softsp->spur_timeout_id == 0) {
1603*29949e86Sstevel 		softsp->spur_timeout_id = timeout(spur_retry, softsp,
1604*29949e86Sstevel 		    spur_timeout_hz);
1605*29949e86Sstevel 	}
1606*29949e86Sstevel 
1607*29949e86Sstevel 	/* do we need to start the long timeout? */
1608*29949e86Sstevel 	if (softsp->spur_long_timeout_id == 0) {
1609*29949e86Sstevel 		softsp->spur_long_timeout_id = timeout(spur_long_timeout,
1610*29949e86Sstevel 		    softsp, spur_long_timeout_hz);
1611*29949e86Sstevel 	}
1612*29949e86Sstevel 
1613*29949e86Sstevel 	mutex_exit(&softsp->spur_int_lock);
1614*29949e86Sstevel 
1615*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
1616*29949e86Sstevel }
1617*29949e86Sstevel 
1618*29949e86Sstevel /*
1619*29949e86Sstevel  * spur_retry
1620*29949e86Sstevel  *
1621*29949e86Sstevel  * this routine simply triggers the interrupt which will re-enable
1622*29949e86Sstevel  * the interrupts disabled by the spurious int detection.
1623*29949e86Sstevel  */
1624*29949e86Sstevel static void
1625*29949e86Sstevel spur_retry(void *arg)
1626*29949e86Sstevel {
1627*29949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
1628*29949e86Sstevel 
1629*29949e86Sstevel 	ASSERT(softsp);
1630*29949e86Sstevel 
1631*29949e86Sstevel 	ddi_trigger_softintr(softsp->spur_high_id);
1632*29949e86Sstevel 
1633*29949e86Sstevel 	mutex_enter(&softsp->spur_int_lock);
1634*29949e86Sstevel 	softsp->spur_timeout_id = 0;
1635*29949e86Sstevel 	mutex_exit(&softsp->spur_int_lock);
1636*29949e86Sstevel }
1637*29949e86Sstevel 
1638*29949e86Sstevel /*
1639*29949e86Sstevel  * spur_reenable
1640*29949e86Sstevel  *
1641*29949e86Sstevel  * OK, we've been slient for a while.   Go ahead and re-enable the
1642*29949e86Sstevel  * interrupts that were enabled at the time of the spurious detection.
1643*29949e86Sstevel  */
1644*29949e86Sstevel static uint_t
1645*29949e86Sstevel spur_reenable(caddr_t arg)
1646*29949e86Sstevel {
1647*29949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1648*29949e86Sstevel 	uchar_t tmp_reg;
1649*29949e86Sstevel 
1650*29949e86Sstevel 	ASSERT(softsp);
1651*29949e86Sstevel 
1652*29949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
1653*29949e86Sstevel 
1654*29949e86Sstevel 	/* reenable those who were spurious candidates */
1655*29949e86Sstevel 	*(softsp->csr) |= softsp->saved_en_state &
1656*29949e86Sstevel 		(SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
1657*29949e86Sstevel 		SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
1658*29949e86Sstevel 	tmp_reg = *(softsp->csr);
1659*29949e86Sstevel #ifdef lint
1660*29949e86Sstevel 	tmp_reg = tmp_reg;
1661*29949e86Sstevel #endif
1662*29949e86Sstevel 
1663*29949e86Sstevel 	/* clear out the saved state */
1664*29949e86Sstevel 	softsp->saved_en_state = 0;
1665*29949e86Sstevel 
1666*29949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
1667*29949e86Sstevel 
1668*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
1669*29949e86Sstevel }
1670*29949e86Sstevel 
1671*29949e86Sstevel /*
1672*29949e86Sstevel  * spur_long_timeout
1673*29949e86Sstevel  *
1674*29949e86Sstevel  * this routine merely resets the spurious interrupt counter thus ending
1675*29949e86Sstevel  * the interval of interest.  of course this is done by triggering a
1676*29949e86Sstevel  * softint because the counter is protected by an interrupt mutex.
1677*29949e86Sstevel  */
1678*29949e86Sstevel static void
1679*29949e86Sstevel spur_long_timeout(void *arg)
1680*29949e86Sstevel {
1681*29949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
1682*29949e86Sstevel 
1683*29949e86Sstevel 	ASSERT(softsp);
1684*29949e86Sstevel 
1685*29949e86Sstevel 	ddi_trigger_softintr(softsp->spur_long_to_id);
1686*29949e86Sstevel 
1687*29949e86Sstevel 	mutex_enter(&softsp->spur_int_lock);
1688*29949e86Sstevel 	softsp->spur_long_timeout_id = 0;
1689*29949e86Sstevel 	mutex_exit(&softsp->spur_int_lock);
1690*29949e86Sstevel }
1691*29949e86Sstevel 
1692*29949e86Sstevel /*
1693*29949e86Sstevel  * spur_clear_count
1694*29949e86Sstevel  *
1695*29949e86Sstevel  * simply clear out the spurious interrupt counter.
1696*29949e86Sstevel  *
1697*29949e86Sstevel  * softint level only
1698*29949e86Sstevel  */
1699*29949e86Sstevel static uint_t
1700*29949e86Sstevel spur_clear_count(caddr_t arg)
1701*29949e86Sstevel {
1702*29949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1703*29949e86Sstevel 
1704*29949e86Sstevel 	ASSERT(softsp);
1705*29949e86Sstevel 
1706*29949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
1707*29949e86Sstevel 	softsp->spur_count = 0;
1708*29949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
1709*29949e86Sstevel 
1710*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
1711*29949e86Sstevel }
1712*29949e86Sstevel 
1713*29949e86Sstevel /*
1714*29949e86Sstevel  * ac_fail_handler
1715*29949e86Sstevel  *
1716*29949e86Sstevel  * This routine polls the AC power failure bit in the system status2
1717*29949e86Sstevel  * register.  If we get to this routine, then we sensed an ac fail
1718*29949e86Sstevel  * condition.  Note the fact and check again in a few.
1719*29949e86Sstevel  *
1720*29949e86Sstevel  * Called as softint from high interrupt.
1721*29949e86Sstevel  */
1722*29949e86Sstevel static uint_t
1723*29949e86Sstevel ac_fail_handler(caddr_t arg)
1724*29949e86Sstevel {
1725*29949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1726*29949e86Sstevel 
1727*29949e86Sstevel 	ASSERT(softsp);
1728*29949e86Sstevel 
1729*29949e86Sstevel 	cmn_err(CE_WARN, "%s failure detected", ft_str_table[FT_AC_PWR]);
1730*29949e86Sstevel 	reg_fault(0, FT_AC_PWR, FT_SYSTEM);
1731*29949e86Sstevel 	(void) timeout(ac_fail_retry, softsp, ac_timeout_hz);
1732*29949e86Sstevel 
1733*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
1734*29949e86Sstevel }
1735*29949e86Sstevel 
1736*29949e86Sstevel /*
1737*29949e86Sstevel  * The timeout from ac_fail_handler() that checks to see if the
1738*29949e86Sstevel  * condition persists.
1739*29949e86Sstevel  */
1740*29949e86Sstevel static void
1741*29949e86Sstevel ac_fail_retry(void *arg)
1742*29949e86Sstevel {
1743*29949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
1744*29949e86Sstevel 
1745*29949e86Sstevel 	ASSERT(softsp);
1746*29949e86Sstevel 
1747*29949e86Sstevel 	if (*softsp->status2 & SYS_AC_FAIL) {	/* still bad? */
1748*29949e86Sstevel 		(void) timeout(ac_fail_retry, softsp, ac_timeout_hz);
1749*29949e86Sstevel 	} else {
1750*29949e86Sstevel 		cmn_err(CE_NOTE, "%s failure no longer detected",
1751*29949e86Sstevel 			ft_str_table[FT_AC_PWR]);
1752*29949e86Sstevel 		clear_fault(0, FT_AC_PWR, FT_SYSTEM);
1753*29949e86Sstevel 		ddi_trigger_softintr(softsp->ac_fail_high_id);
1754*29949e86Sstevel 	}
1755*29949e86Sstevel }
1756*29949e86Sstevel 
1757*29949e86Sstevel /*
1758*29949e86Sstevel  * The interrupt routine that we use to re-enable the interrupt.
1759*29949e86Sstevel  * Called from ddi_trigger_softint() in the ac_fail_retry() when
1760*29949e86Sstevel  * the AC is better.
1761*29949e86Sstevel  */
1762*29949e86Sstevel static uint_t
1763*29949e86Sstevel ac_fail_reenable(caddr_t arg)
1764*29949e86Sstevel {
1765*29949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1766*29949e86Sstevel 	uchar_t tmp_reg;
1767*29949e86Sstevel 
1768*29949e86Sstevel 	ASSERT(softsp);
1769*29949e86Sstevel 
1770*29949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
1771*29949e86Sstevel 	*(softsp->csr) |= SYS_AC_PWR_FAIL_EN;
1772*29949e86Sstevel 	tmp_reg = *(softsp->csr);
1773*29949e86Sstevel #ifdef lint
1774*29949e86Sstevel 	tmp_reg = tmp_reg;
1775*29949e86Sstevel #endif
1776*29949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
1777*29949e86Sstevel 
1778*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
1779*29949e86Sstevel }
1780*29949e86Sstevel 
1781*29949e86Sstevel /*
1782*29949e86Sstevel  * ps_fail_int_handler
1783*29949e86Sstevel  *
1784*29949e86Sstevel  * Handle power supply failure interrupt.
1785*29949e86Sstevel  *
1786*29949e86Sstevel  * This wrapper is called as softint from hardware interrupt routine.
1787*29949e86Sstevel  */
1788*29949e86Sstevel static uint_t
1789*29949e86Sstevel ps_fail_int_handler(caddr_t arg)
1790*29949e86Sstevel {
1791*29949e86Sstevel 	return (ps_fail_handler((struct sysctrl_soft_state *)arg, 1));
1792*29949e86Sstevel }
1793*29949e86Sstevel 
1794*29949e86Sstevel /*
1795*29949e86Sstevel  * ps_fail_poll_handler
1796*29949e86Sstevel  *
1797*29949e86Sstevel  * Handle power supply failure interrupt.
1798*29949e86Sstevel  *
1799*29949e86Sstevel  * This wrapper is called as softint from power supply poll routine.
1800*29949e86Sstevel  */
1801*29949e86Sstevel static uint_t
1802*29949e86Sstevel ps_fail_poll_handler(caddr_t arg)
1803*29949e86Sstevel {
1804*29949e86Sstevel 	return (ps_fail_handler((struct sysctrl_soft_state *)arg, 0));
1805*29949e86Sstevel }
1806*29949e86Sstevel 
1807*29949e86Sstevel /*
1808*29949e86Sstevel  * ps_fail_handler
1809*29949e86Sstevel  *
1810*29949e86Sstevel  * This routine checks all eight of the board power supplies that are
1811*29949e86Sstevel  * installed plus the Peripheral power supply and the two DC OK. Since the
1812*29949e86Sstevel  * hardware bits are not enough to indicate Power Supply failure
1813*29949e86Sstevel  * vs. being turned off via software, the driver must maintain a
1814*29949e86Sstevel  * shadow state for the Power Supply status and monitor all changes.
1815*29949e86Sstevel  *
1816*29949e86Sstevel  * Called as a softint only.
1817*29949e86Sstevel  */
1818*29949e86Sstevel static uint_t
1819*29949e86Sstevel ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint)
1820*29949e86Sstevel {
1821*29949e86Sstevel 	int i;
1822*29949e86Sstevel 	struct ps_state *pstatp;
1823*29949e86Sstevel 	int poll_needed = 0;
1824*29949e86Sstevel 	uchar_t ps_stat, ps_pres, status1, status2, pppsr;
1825*29949e86Sstevel 	uchar_t tmp_reg;
1826*29949e86Sstevel 	enum power_state current_power_state;
1827*29949e86Sstevel 
1828*29949e86Sstevel 	ASSERT(softsp);
1829*29949e86Sstevel 
1830*29949e86Sstevel 	/* pre-read the hardware state */
1831*29949e86Sstevel 	ps_stat = *softsp->ps_stat;
1832*29949e86Sstevel 	ps_pres = *softsp->ps_pres;
1833*29949e86Sstevel 	status1 = *softsp->status1;
1834*29949e86Sstevel 	status2 = *softsp->status2;
1835*29949e86Sstevel 	pppsr	= *softsp->pppsr;
1836*29949e86Sstevel 
1837*29949e86Sstevel 	(void) fhc_bdlist_lock(-1);
1838*29949e86Sstevel 
1839*29949e86Sstevel 	mutex_enter(&softsp->ps_fail_lock);
1840*29949e86Sstevel 
1841*29949e86Sstevel 	for (i = 0, pstatp = &softsp->ps_stats[0]; i < SYS_PS_COUNT;
1842*29949e86Sstevel 	    i++, pstatp++) {
1843*29949e86Sstevel 		int	temp_psok;
1844*29949e86Sstevel 		int	temp_pres;
1845*29949e86Sstevel 		int	is_precharge = FALSE;
1846*29949e86Sstevel 		int	is_fan_assy = FALSE;
1847*29949e86Sstevel 
1848*29949e86Sstevel 		/*
1849*29949e86Sstevel 		 * pre-compute the presence and ok bits for this
1850*29949e86Sstevel 		 * power supply from the hardware registers.
1851*29949e86Sstevel 		 * NOTE: 4-slot pps1 is the same as core ps 7...
1852*29949e86Sstevel 		 */
1853*29949e86Sstevel 		switch (i) {
1854*29949e86Sstevel 		/* the core power supplies */
1855*29949e86Sstevel 		case 0: case 1: case 2: case 3:
1856*29949e86Sstevel 		case 4: case 5: case 6: case 7:
1857*29949e86Sstevel 			temp_pres = !((ps_pres >> i) & 0x1);
1858*29949e86Sstevel 			temp_psok = (ps_stat >> i) & 0x1;
1859*29949e86Sstevel 			break;
1860*29949e86Sstevel 
1861*29949e86Sstevel 		/* the first peripheral power supply */
1862*29949e86Sstevel 		case SYS_PPS0_INDEX:
1863*29949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1864*29949e86Sstevel 			temp_psok = status2 & SYS_PPS0_OK;
1865*29949e86Sstevel 			break;
1866*29949e86Sstevel 
1867*29949e86Sstevel 		/* shared 3.3v clock power */
1868*29949e86Sstevel 		case SYS_CLK_33_INDEX:
1869*29949e86Sstevel 			temp_pres = TRUE;
1870*29949e86Sstevel 			temp_psok = status2 & SYS_CLK_33_OK;
1871*29949e86Sstevel 			break;
1872*29949e86Sstevel 
1873*29949e86Sstevel 		/* shared 5.0v clock power */
1874*29949e86Sstevel 		case SYS_CLK_50_INDEX:
1875*29949e86Sstevel 			temp_pres = TRUE;
1876*29949e86Sstevel 			temp_psok = status2 & SYS_CLK_50_OK;
1877*29949e86Sstevel 			break;
1878*29949e86Sstevel 
1879*29949e86Sstevel 		/* peripheral 5v */
1880*29949e86Sstevel 		case SYS_V5_P_INDEX:
1881*29949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES) ||
1882*29949e86Sstevel 				((IS4SLOT(softsp->nslots) ||
1883*29949e86Sstevel 				IS5SLOT(softsp->nslots)) &&
1884*29949e86Sstevel 				!(ps_pres & SYS_NOT_PPS1_PRES));
1885*29949e86Sstevel 			temp_psok = pppsr & SYS_V5_P_OK;
1886*29949e86Sstevel 			break;
1887*29949e86Sstevel 
1888*29949e86Sstevel 		/* peripheral 12v */
1889*29949e86Sstevel 		case SYS_V12_P_INDEX:
1890*29949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES) ||
1891*29949e86Sstevel 				((IS4SLOT(softsp->nslots) ||
1892*29949e86Sstevel 				IS5SLOT(softsp->nslots)) &&
1893*29949e86Sstevel 				!(ps_pres & SYS_NOT_PPS1_PRES));
1894*29949e86Sstevel 			temp_psok = pppsr & SYS_V12_P_OK;
1895*29949e86Sstevel 			break;
1896*29949e86Sstevel 
1897*29949e86Sstevel 		/* aux 5v */
1898*29949e86Sstevel 		case SYS_V5_AUX_INDEX:
1899*29949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1900*29949e86Sstevel 			temp_psok = pppsr & SYS_V5_AUX_OK;
1901*29949e86Sstevel 			break;
1902*29949e86Sstevel 
1903*29949e86Sstevel 		/* peripheral 5v precharge */
1904*29949e86Sstevel 		case SYS_V5_P_PCH_INDEX:
1905*29949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1906*29949e86Sstevel 			temp_psok = pppsr & SYS_V5_P_PCH_OK;
1907*29949e86Sstevel 			is_precharge = TRUE;
1908*29949e86Sstevel 			break;
1909*29949e86Sstevel 
1910*29949e86Sstevel 		/* peripheral 12v precharge */
1911*29949e86Sstevel 		case SYS_V12_P_PCH_INDEX:
1912*29949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1913*29949e86Sstevel 			temp_psok = pppsr & SYS_V12_P_PCH_OK;
1914*29949e86Sstevel 			is_precharge = TRUE;
1915*29949e86Sstevel 			break;
1916*29949e86Sstevel 
1917*29949e86Sstevel 		/* 3.3v precharge */
1918*29949e86Sstevel 		case SYS_V3_PCH_INDEX:
1919*29949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1920*29949e86Sstevel 			temp_psok = pppsr & SYS_V3_PCH_OK;
1921*29949e86Sstevel 			is_precharge = TRUE;
1922*29949e86Sstevel 			break;
1923*29949e86Sstevel 
1924*29949e86Sstevel 		/* 5v precharge */
1925*29949e86Sstevel 		case SYS_V5_PCH_INDEX:
1926*29949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1927*29949e86Sstevel 			temp_psok = pppsr & SYS_V5_PCH_OK;
1928*29949e86Sstevel 			is_precharge = TRUE;
1929*29949e86Sstevel 			break;
1930*29949e86Sstevel 
1931*29949e86Sstevel 		/* peripheral fan assy */
1932*29949e86Sstevel 		case SYS_P_FAN_INDEX:
1933*29949e86Sstevel 			temp_pres = (IS4SLOT(softsp->nslots) ||
1934*29949e86Sstevel 				IS5SLOT(softsp->nslots)) &&
1935*29949e86Sstevel 				!(status1 & SYS_NOT_P_FAN_PRES);
1936*29949e86Sstevel 			temp_psok = softsp->pps_fan_saved &
1937*29949e86Sstevel 				SYS_AC_FAN_OK;
1938*29949e86Sstevel 			is_fan_assy = TRUE;
1939*29949e86Sstevel 			break;
1940*29949e86Sstevel 		}
1941*29949e86Sstevel 
1942*29949e86Sstevel 		/* *** Phase 1 -- power supply presence tests *** */
1943*29949e86Sstevel 
1944*29949e86Sstevel 		/* do we know the presence status for this power supply? */
1945*29949e86Sstevel 		if (pstatp->pshadow == PRES_UNKNOWN) {
1946*29949e86Sstevel 			pstatp->pshadow = temp_pres ? PRES_IN : PRES_OUT;
1947*29949e86Sstevel 			pstatp->dcshadow = temp_pres ? PS_BOOT : PS_OUT;
1948*29949e86Sstevel 		} else {
1949*29949e86Sstevel 			/* has the ps presence state changed? */
1950*29949e86Sstevel 			if (!temp_pres ^ (pstatp->pshadow == PRES_IN)) {
1951*29949e86Sstevel 				pstatp->pctr = 0;
1952*29949e86Sstevel 			} else {
1953*29949e86Sstevel 				/* a change! are we counting? */
1954*29949e86Sstevel 				if (pstatp->pctr == 0) {
1955*29949e86Sstevel 					pstatp->pctr = PS_PRES_CHANGE_TICKS;
1956*29949e86Sstevel 				} else if (--pstatp->pctr == 0) {
1957*29949e86Sstevel 					pstatp->pshadow = temp_pres ?
1958*29949e86Sstevel 						PRES_IN : PRES_OUT;
1959*29949e86Sstevel 					pstatp->dcshadow = temp_pres ?
1960*29949e86Sstevel 						PS_UNKNOWN : PS_OUT;
1961*29949e86Sstevel 
1962*29949e86Sstevel 					/*
1963*29949e86Sstevel 					 * Now we know the state has
1964*29949e86Sstevel 					 * changed, so we should log it.
1965*29949e86Sstevel 					 */
1966*29949e86Sstevel 					ps_log_pres_change(softsp,
1967*29949e86Sstevel 						i, temp_pres);
1968*29949e86Sstevel 				}
1969*29949e86Sstevel 			}
1970*29949e86Sstevel 		}
1971*29949e86Sstevel 
1972*29949e86Sstevel 		/* *** Phase 2 -- power supply status tests *** */
1973*29949e86Sstevel 
1974*29949e86Sstevel 		/* check if the Power Supply is removed or same as before */
1975*29949e86Sstevel 		if ((pstatp->dcshadow == PS_OUT) ||
1976*29949e86Sstevel 		    ((pstatp->dcshadow == PS_OK) && temp_psok) ||
1977*29949e86Sstevel 		    ((pstatp->dcshadow == PS_FAIL) && !temp_psok)) {
1978*29949e86Sstevel 			pstatp->dcctr = 0;
1979*29949e86Sstevel 		} else {
1980*29949e86Sstevel 
1981*29949e86Sstevel 			/* OK, a change, do we start the timer? */
1982*29949e86Sstevel 			if (pstatp->dcctr == 0) {
1983*29949e86Sstevel 				switch (pstatp->dcshadow) {
1984*29949e86Sstevel 				case PS_BOOT:
1985*29949e86Sstevel 					pstatp->dcctr = PS_FROM_BOOT_TICKS;
1986*29949e86Sstevel 					break;
1987*29949e86Sstevel 
1988*29949e86Sstevel 				case PS_UNKNOWN:
1989*29949e86Sstevel 					pstatp->dcctr = is_fan_assy ?
1990*29949e86Sstevel 						PS_P_FAN_FROM_UNKNOWN_TICKS :
1991*29949e86Sstevel 						PS_FROM_UNKNOWN_TICKS;
1992*29949e86Sstevel 					break;
1993*29949e86Sstevel 
1994*29949e86Sstevel 				case PS_OK:
1995*29949e86Sstevel 					pstatp->dcctr = is_precharge ?
1996*29949e86Sstevel 						PS_PCH_FROM_OK_TICKS :
1997*29949e86Sstevel 						PS_FROM_OK_TICKS;
1998*29949e86Sstevel 					break;
1999*29949e86Sstevel 
2000*29949e86Sstevel 				case PS_FAIL:
2001*29949e86Sstevel 					pstatp->dcctr = PS_FROM_FAIL_TICKS;
2002*29949e86Sstevel 					break;
2003*29949e86Sstevel 
2004*29949e86Sstevel 				default:
2005*29949e86Sstevel 					panic("sysctrl%d: Unknown Power "
2006*29949e86Sstevel 					    "Supply State %d", pstatp->dcshadow,
2007*29949e86Sstevel 					    ddi_get_instance(softsp->dip));
2008*29949e86Sstevel 				}
2009*29949e86Sstevel 			}
2010*29949e86Sstevel 
2011*29949e86Sstevel 			/* has the ticker expired? */
2012*29949e86Sstevel 			if (--pstatp->dcctr == 0) {
2013*29949e86Sstevel 
2014*29949e86Sstevel 				/* we'll skip OK messages during boot */
2015*29949e86Sstevel 				if (!((pstatp->dcshadow == PS_BOOT) &&
2016*29949e86Sstevel 				    temp_psok)) {
2017*29949e86Sstevel 					ps_log_state_change(softsp,
2018*29949e86Sstevel 						i, temp_psok);
2019*29949e86Sstevel 				}
2020*29949e86Sstevel 
2021*29949e86Sstevel 				/*
2022*29949e86Sstevel 				 * remote console interface has to be
2023*29949e86Sstevel 				 * reinitialized on the rising edge V5_AUX
2024*29949e86Sstevel 				 * when it is NOT boot. At the boot time an
2025*29949e86Sstevel 				 * an error condition exists if it was not
2026*29949e86Sstevel 				 * enabled before.
2027*29949e86Sstevel 				 */
2028*29949e86Sstevel 				if ((i == SYS_V5_AUX_INDEX) &&
2029*29949e86Sstevel 				    (pstatp->dcshadow != PS_BOOT) &&
2030*29949e86Sstevel 				    (softsp->enable_rcons_atboot)) {
2031*29949e86Sstevel 					if (temp_psok)
2032*29949e86Sstevel 						rcons_reinit(softsp);
2033*29949e86Sstevel 					else
2034*29949e86Sstevel 						/* disable rconsole */
2035*29949e86Sstevel 						*(softsp->clk_freq2) &=
2036*29949e86Sstevel 						    ~RCONS_UART_EN;
2037*29949e86Sstevel 					tmp_reg = *(softsp->csr);
2038*29949e86Sstevel #ifdef lint
2039*29949e86Sstevel 					tmp_reg = tmp_reg;
2040*29949e86Sstevel #endif
2041*29949e86Sstevel 
2042*29949e86Sstevel 				}
2043*29949e86Sstevel 
2044*29949e86Sstevel 				/* regardless, update the shadow state */
2045*29949e86Sstevel 				pstatp->dcshadow = temp_psok ? PS_OK : PS_FAIL;
2046*29949e86Sstevel 
2047*29949e86Sstevel 				/* always update board condition */
2048*29949e86Sstevel 				sysc_policy_update(softsp, NULL,
2049*29949e86Sstevel 					SYSC_EVT_BD_PS_CHANGE);
2050*29949e86Sstevel 
2051*29949e86Sstevel 			}
2052*29949e86Sstevel 		}
2053*29949e86Sstevel 
2054*29949e86Sstevel 		/*
2055*29949e86Sstevel 		 * We will need to continue polling for three reasons:
2056*29949e86Sstevel 		 * - a failing power supply is detected and we haven't yet
2057*29949e86Sstevel 		 *   determined the power supplies existence.
2058*29949e86Sstevel 		 * - the power supply is just installed and we're waiting
2059*29949e86Sstevel 		 *   to give it a change to power up,
2060*29949e86Sstevel 		 * - a failed power supply state is recognized
2061*29949e86Sstevel 		 *
2062*29949e86Sstevel 		 * NOTE: PS_FAIL shadow state is not the same as !temp_psok
2063*29949e86Sstevel 		 * because of the persistence of PS_FAIL->PS_OK.
2064*29949e86Sstevel 		 */
2065*29949e86Sstevel 		if (!temp_psok ||
2066*29949e86Sstevel 		    (pstatp->dcshadow == PS_UNKNOWN) ||
2067*29949e86Sstevel 		    (pstatp->dcshadow == PS_FAIL)) {
2068*29949e86Sstevel 			poll_needed++;
2069*29949e86Sstevel 		}
2070*29949e86Sstevel 	}
2071*29949e86Sstevel 
2072*29949e86Sstevel 	/*
2073*29949e86Sstevel 	 * Now, get the current power state for this instance.
2074*29949e86Sstevel 	 * If the current state is different than what was known, complain.
2075*29949e86Sstevel 	 */
2076*29949e86Sstevel 	current_power_state = compute_power_state(softsp, 0);
2077*29949e86Sstevel 
2078*29949e86Sstevel 	if (softsp->power_state != current_power_state) {
2079*29949e86Sstevel 		switch (current_power_state) {
2080*29949e86Sstevel 		case BELOW_MINIMUM:
2081*29949e86Sstevel 			cmn_err(CE_WARN,
2082*29949e86Sstevel 				"Insufficient power available to system");
2083*29949e86Sstevel 			if (!disable_insufficient_power_reboot) {
2084*29949e86Sstevel 				cmn_err(CE_WARN, "System reboot in %d seconds",
2085*29949e86Sstevel 					PS_INSUFFICIENT_COUNTDOWN_SEC);
2086*29949e86Sstevel 			}
2087*29949e86Sstevel 			reg_fault(1, FT_INSUFFICIENT_POWER, FT_SYSTEM);
2088*29949e86Sstevel 			softsp->power_countdown = PS_POWER_COUNTDOWN_TICKS;
2089*29949e86Sstevel 			break;
2090*29949e86Sstevel 
2091*29949e86Sstevel 		case MINIMUM:
2092*29949e86Sstevel 			/* If we came from REDUNDANT, complain */
2093*29949e86Sstevel 			if (softsp->power_state == REDUNDANT) {
2094*29949e86Sstevel 				cmn_err(CE_WARN, "Redundant power lost");
2095*29949e86Sstevel 			/* If we came from BELOW_MINIMUM, hurrah! */
2096*29949e86Sstevel 			} else if (softsp->power_state == BELOW_MINIMUM) {
2097*29949e86Sstevel 				cmn_err(CE_NOTE, "Minimum power available");
2098*29949e86Sstevel 				clear_fault(1, FT_INSUFFICIENT_POWER,
2099*29949e86Sstevel 					FT_SYSTEM);
2100*29949e86Sstevel 			}
2101*29949e86Sstevel 			break;
2102*29949e86Sstevel 
2103*29949e86Sstevel 		case REDUNDANT:
2104*29949e86Sstevel 			/* If we aren't from boot, spread the good news */
2105*29949e86Sstevel 			if (softsp->power_state != BOOT) {
2106*29949e86Sstevel 				cmn_err(CE_NOTE, "Redundant power available");
2107*29949e86Sstevel 				clear_fault(1, FT_INSUFFICIENT_POWER,
2108*29949e86Sstevel 					FT_SYSTEM);
2109*29949e86Sstevel 			}
2110*29949e86Sstevel 			break;
2111*29949e86Sstevel 
2112*29949e86Sstevel 		default:
2113*29949e86Sstevel 			break;
2114*29949e86Sstevel 		}
2115*29949e86Sstevel 		softsp->power_state = current_power_state;
2116*29949e86Sstevel 		sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
2117*29949e86Sstevel 	}
2118*29949e86Sstevel 
2119*29949e86Sstevel 	mutex_exit(&softsp->ps_fail_lock);
2120*29949e86Sstevel 
2121*29949e86Sstevel 	fhc_bdlist_unlock();
2122*29949e86Sstevel 
2123*29949e86Sstevel 	/*
2124*29949e86Sstevel 	 * Are we in insufficient powerstate?
2125*29949e86Sstevel 	 * If so, is it time to take action?
2126*29949e86Sstevel 	 */
2127*29949e86Sstevel 	if (softsp->power_state == BELOW_MINIMUM &&
2128*29949e86Sstevel 	    softsp->power_countdown > 0 && --(softsp->power_countdown) == 0 &&
2129*29949e86Sstevel 	    !disable_insufficient_power_reboot) {
2130*29949e86Sstevel 		cmn_err(CE_WARN,
2131*29949e86Sstevel 		    "Insufficient power. System Reboot Started...");
2132*29949e86Sstevel 
2133*29949e86Sstevel 		fhc_reboot();
2134*29949e86Sstevel 	}
2135*29949e86Sstevel 
2136*29949e86Sstevel 	/*
2137*29949e86Sstevel 	 * If we don't have ps problems that need to be polled for, then
2138*29949e86Sstevel 	 * enable interrupts.
2139*29949e86Sstevel 	 */
2140*29949e86Sstevel 	if (!poll_needed) {
2141*29949e86Sstevel 		mutex_enter(&softsp->csr_mutex);
2142*29949e86Sstevel 		*(softsp->csr) |= SYS_PS_FAIL_EN;
2143*29949e86Sstevel 		tmp_reg = *(softsp->csr);
2144*29949e86Sstevel #ifdef lint
2145*29949e86Sstevel 		tmp_reg = tmp_reg;
2146*29949e86Sstevel #endif
2147*29949e86Sstevel 		mutex_exit(&softsp->csr_mutex);
2148*29949e86Sstevel 	}
2149*29949e86Sstevel 
2150*29949e86Sstevel 	/*
2151*29949e86Sstevel 	 * Only the polling loop re-triggers the polling loop timeout
2152*29949e86Sstevel 	 */
2153*29949e86Sstevel 	if (!fromint) {
2154*29949e86Sstevel 		(void) timeout(ps_fail_retry, softsp, ps_fail_timeout_hz);
2155*29949e86Sstevel 	}
2156*29949e86Sstevel 
2157*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
2158*29949e86Sstevel }
2159*29949e86Sstevel 
2160*29949e86Sstevel /*
2161*29949e86Sstevel  * Compute the current power configuration for this system.
2162*29949e86Sstevel  * Disk boards and Clock boards are not counted.
2163*29949e86Sstevel  *
2164*29949e86Sstevel  * This function must be called with the ps_fail_lock held.
2165*29949e86Sstevel  */
2166*29949e86Sstevel enum power_state
2167*29949e86Sstevel compute_power_state(struct sysctrl_soft_state *softsp, int plus_load)
2168*29949e86Sstevel {
2169*29949e86Sstevel 	int i;
2170*29949e86Sstevel 	int ok_supply_count = 0;
2171*29949e86Sstevel 	int load_count = 0;
2172*29949e86Sstevel 	int minimum_power_count;
2173*29949e86Sstevel 	int pps_ok;
2174*29949e86Sstevel 	fhc_bd_t *list;
2175*29949e86Sstevel 
2176*29949e86Sstevel 	ASSERT(mutex_owned(&softsp->ps_fail_lock));
2177*29949e86Sstevel 
2178*29949e86Sstevel 	/*
2179*29949e86Sstevel 	 * Walk down the interesting power supplies and
2180*29949e86Sstevel 	 * count the operational power units
2181*29949e86Sstevel 	 */
2182*29949e86Sstevel 	for (i = 0; i < 8; i++) {
2183*29949e86Sstevel 		/*
2184*29949e86Sstevel 		 * power supply id 7 on a 4 or 5 slot system is PPS1.
2185*29949e86Sstevel 		 * don't include it in the redundant core power calculation.
2186*29949e86Sstevel 		 */
2187*29949e86Sstevel 		if (i == 7 &&
2188*29949e86Sstevel 		    (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)))
2189*29949e86Sstevel 			continue;
2190*29949e86Sstevel 
2191*29949e86Sstevel 		if (softsp->ps_stats[i].dcshadow == PS_OK)
2192*29949e86Sstevel 			ok_supply_count++;
2193*29949e86Sstevel 	}
2194*29949e86Sstevel 
2195*29949e86Sstevel 	/* Note the state of the PPS... */
2196*29949e86Sstevel 	pps_ok = (softsp->ps_stats[SYS_PPS0_INDEX].dcshadow == PS_OK);
2197*29949e86Sstevel 
2198*29949e86Sstevel 	/*
2199*29949e86Sstevel 	 * Dynamically compute the load count in the system.
2200*29949e86Sstevel 	 * Don't count disk boards or boards in low power state.
2201*29949e86Sstevel 	 */
2202*29949e86Sstevel 	for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) {
2203*29949e86Sstevel 		ASSERT(list->sc.type != CLOCK_BOARD);
2204*29949e86Sstevel 		if (list->sc.rstate == SYSC_CFGA_RSTATE_CONNECTED) {
2205*29949e86Sstevel 			load_count++;
2206*29949e86Sstevel 		}
2207*29949e86Sstevel 	}
2208*29949e86Sstevel 
2209*29949e86Sstevel 	load_count += plus_load;
2210*29949e86Sstevel 	/*
2211*29949e86Sstevel 	 * If we are 8 slot and we have 7 or 8 boards, then the PPS
2212*29949e86Sstevel 	 * can count as a power supply...
2213*29949e86Sstevel 	 */
2214*29949e86Sstevel 	if (IS8SLOT(softsp->nslots) && load_count >= 7 && pps_ok)
2215*29949e86Sstevel 		ok_supply_count++;
2216*29949e86Sstevel 
2217*29949e86Sstevel 	/*
2218*29949e86Sstevel 	 * This is to cover the corner case of a UE3500 having 5
2219*29949e86Sstevel 	 * boards installed and still giving it N+1 power status.
2220*29949e86Sstevel 	 */
2221*29949e86Sstevel 	if (IS5SLOT(softsp->nslots) && (load_count >= 5))
2222*29949e86Sstevel 		ok_supply_count++;
2223*29949e86Sstevel 
2224*29949e86Sstevel 	/*
2225*29949e86Sstevel 	 * Determine our power situation.  This is a simple step
2226*29949e86Sstevel 	 * function right now:
2227*29949e86Sstevel 	 *
2228*29949e86Sstevel 	 * minimum power count = min(7, floor((board count + 1) / 2))
2229*29949e86Sstevel 	 */
2230*29949e86Sstevel 	minimum_power_count = (load_count + 1) / 2;
2231*29949e86Sstevel 	if (minimum_power_count > 7)
2232*29949e86Sstevel 		minimum_power_count = 7;
2233*29949e86Sstevel 
2234*29949e86Sstevel 	if (ok_supply_count > minimum_power_count)
2235*29949e86Sstevel 		return (REDUNDANT);
2236*29949e86Sstevel 	else if (ok_supply_count == minimum_power_count)
2237*29949e86Sstevel 		return (MINIMUM);
2238*29949e86Sstevel 	else
2239*29949e86Sstevel 		return (BELOW_MINIMUM);
2240*29949e86Sstevel }
2241*29949e86Sstevel 
2242*29949e86Sstevel /*
2243*29949e86Sstevel  * log the change of power supply presence
2244*29949e86Sstevel  */
2245*29949e86Sstevel static void
2246*29949e86Sstevel ps_log_pres_change(struct sysctrl_soft_state *softsp, int index, int present)
2247*29949e86Sstevel {
2248*29949e86Sstevel 	char	*trans = present ? "Installed" : "Removed";
2249*29949e86Sstevel 
2250*29949e86Sstevel 	switch (index) {
2251*29949e86Sstevel 	/* the core power supplies (except for 7) */
2252*29949e86Sstevel 	case 0: case 1: case 2: case 3:
2253*29949e86Sstevel 	case 4: case 5: case 6:
2254*29949e86Sstevel 		cmn_err(CE_NOTE, "%s %d %s", ft_str_table[FT_CORE_PS], index,
2255*29949e86Sstevel 		    trans);
2256*29949e86Sstevel 		if (!present) {
2257*29949e86Sstevel 		    clear_fault(index, FT_CORE_PS, FT_SYSTEM);
2258*29949e86Sstevel 		    sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
2259*29949e86Sstevel 		}
2260*29949e86Sstevel 		break;
2261*29949e86Sstevel 
2262*29949e86Sstevel 	/* power supply 7 / pps 1 */
2263*29949e86Sstevel 	case 7:
2264*29949e86Sstevel 		if (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)) {
2265*29949e86Sstevel 		    cmn_err(CE_NOTE, "%s 1 %s", ft_str_table[FT_PPS], trans);
2266*29949e86Sstevel 		    if (!present) {
2267*29949e86Sstevel 			clear_fault(1, FT_PPS, FT_SYSTEM);
2268*29949e86Sstevel 		    }
2269*29949e86Sstevel 		} else {
2270*29949e86Sstevel 		    cmn_err(CE_NOTE, "%s %d %s", ft_str_table[FT_CORE_PS],
2271*29949e86Sstevel 			index, trans);
2272*29949e86Sstevel 		    if (!present) {
2273*29949e86Sstevel 			clear_fault(7, FT_CORE_PS, FT_SYSTEM);
2274*29949e86Sstevel 			sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
2275*29949e86Sstevel 		    }
2276*29949e86Sstevel 		}
2277*29949e86Sstevel 		break;
2278*29949e86Sstevel 
2279*29949e86Sstevel 	/* the peripheral power supply 0 */
2280*29949e86Sstevel 	case SYS_PPS0_INDEX:
2281*29949e86Sstevel 		cmn_err(CE_NOTE, "%s 0 %s", ft_str_table[FT_PPS], trans);
2282*29949e86Sstevel 		if (!present) {
2283*29949e86Sstevel 			clear_fault(0, FT_PPS, FT_SYSTEM);
2284*29949e86Sstevel 			sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
2285*29949e86Sstevel 		}
2286*29949e86Sstevel 		break;
2287*29949e86Sstevel 
2288*29949e86Sstevel 	/* the peripheral rack fan assy */
2289*29949e86Sstevel 	case SYS_P_FAN_INDEX:
2290*29949e86Sstevel 		cmn_err(CE_NOTE, "%s %s", ft_str_table[FT_PPS_FAN], trans);
2291*29949e86Sstevel 		if (!present) {
2292*29949e86Sstevel 			clear_fault(0, FT_PPS_FAN, FT_SYSTEM);
2293*29949e86Sstevel 		}
2294*29949e86Sstevel 		break;
2295*29949e86Sstevel 
2296*29949e86Sstevel 	/* we don't mention a change of presence state for any other power */
2297*29949e86Sstevel 	}
2298*29949e86Sstevel }
2299*29949e86Sstevel 
2300*29949e86Sstevel /*
2301*29949e86Sstevel  * log the change of power supply status
2302*29949e86Sstevel  */
2303*29949e86Sstevel static void
2304*29949e86Sstevel ps_log_state_change(struct sysctrl_soft_state *softsp, int index, int ps_ok)
2305*29949e86Sstevel {
2306*29949e86Sstevel 	int level = ps_ok ? CE_NOTE : CE_WARN;
2307*29949e86Sstevel 	char *s = ps_ok ? "OK" : "Failing";
2308*29949e86Sstevel 
2309*29949e86Sstevel 	switch (index) {
2310*29949e86Sstevel 	/* the core power supplies (except 7) */
2311*29949e86Sstevel 	case 0: case 1: case 2: case 3:
2312*29949e86Sstevel 	case 4: case 5: case 6:
2313*29949e86Sstevel 		cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS], index, s);
2314*29949e86Sstevel 		if (ps_ok) {
2315*29949e86Sstevel 			clear_fault(index, FT_CORE_PS, FT_SYSTEM);
2316*29949e86Sstevel 		} else {
2317*29949e86Sstevel 			reg_fault(index, FT_CORE_PS, FT_SYSTEM);
2318*29949e86Sstevel 		}
2319*29949e86Sstevel 		break;
2320*29949e86Sstevel 
2321*29949e86Sstevel 	/* power supply 7 / pps 1 */
2322*29949e86Sstevel 	case 7:
2323*29949e86Sstevel 		if (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)) {
2324*29949e86Sstevel 			cmn_err(level, "%s 1 %s", ft_str_table[FT_PPS], s);
2325*29949e86Sstevel 			if (ps_ok) {
2326*29949e86Sstevel 				clear_fault(1, FT_PPS, FT_SYSTEM);
2327*29949e86Sstevel 			} else {
2328*29949e86Sstevel 				reg_fault(1, FT_PPS, FT_SYSTEM);
2329*29949e86Sstevel 			}
2330*29949e86Sstevel 		} else {
2331*29949e86Sstevel 			cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS],
2332*29949e86Sstevel 				index, s);
2333*29949e86Sstevel 			if (ps_ok) {
2334*29949e86Sstevel 				clear_fault(index, FT_CORE_PS, FT_SYSTEM);
2335*29949e86Sstevel 			} else {
2336*29949e86Sstevel 				reg_fault(index, FT_CORE_PS, FT_SYSTEM);
2337*29949e86Sstevel 			}
2338*29949e86Sstevel 		}
2339*29949e86Sstevel 		break;
2340*29949e86Sstevel 
2341*29949e86Sstevel 	/* the peripheral power supply */
2342*29949e86Sstevel 	case SYS_PPS0_INDEX:
2343*29949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_PPS], s);
2344*29949e86Sstevel 		if (ps_ok) {
2345*29949e86Sstevel 			clear_fault(0, FT_PPS, FT_SYSTEM);
2346*29949e86Sstevel 		} else {
2347*29949e86Sstevel 			reg_fault(0, FT_PPS, FT_SYSTEM);
2348*29949e86Sstevel 		}
2349*29949e86Sstevel 		break;
2350*29949e86Sstevel 
2351*29949e86Sstevel 	/* shared 3.3v clock power */
2352*29949e86Sstevel 	case SYS_CLK_33_INDEX:
2353*29949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_CLK_33], s);
2354*29949e86Sstevel 		if (ps_ok) {
2355*29949e86Sstevel 			clear_fault(0, FT_CLK_33, FT_SYSTEM);
2356*29949e86Sstevel 		} else {
2357*29949e86Sstevel 			reg_fault(0, FT_CLK_33, FT_SYSTEM);
2358*29949e86Sstevel 		}
2359*29949e86Sstevel 		break;
2360*29949e86Sstevel 
2361*29949e86Sstevel 	/* shared 5.0v clock power */
2362*29949e86Sstevel 	case SYS_CLK_50_INDEX:
2363*29949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_CLK_50], s);
2364*29949e86Sstevel 		if (ps_ok) {
2365*29949e86Sstevel 			clear_fault(0, FT_CLK_50, FT_SYSTEM);
2366*29949e86Sstevel 		} else {
2367*29949e86Sstevel 			reg_fault(0, FT_CLK_50, FT_SYSTEM);
2368*29949e86Sstevel 		}
2369*29949e86Sstevel 		break;
2370*29949e86Sstevel 
2371*29949e86Sstevel 	/* peripheral 5v */
2372*29949e86Sstevel 	case SYS_V5_P_INDEX:
2373*29949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V5_P], s);
2374*29949e86Sstevel 		if (ps_ok) {
2375*29949e86Sstevel 			clear_fault(0, FT_V5_P, FT_SYSTEM);
2376*29949e86Sstevel 		} else {
2377*29949e86Sstevel 			reg_fault(0, FT_V5_P, FT_SYSTEM);
2378*29949e86Sstevel 		}
2379*29949e86Sstevel 		break;
2380*29949e86Sstevel 
2381*29949e86Sstevel 	/* peripheral 12v */
2382*29949e86Sstevel 	case SYS_V12_P_INDEX:
2383*29949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V12_P], s);
2384*29949e86Sstevel 		if (ps_ok) {
2385*29949e86Sstevel 			clear_fault(0, FT_V12_P, FT_SYSTEM);
2386*29949e86Sstevel 		} else {
2387*29949e86Sstevel 			reg_fault(0, FT_V12_P, FT_SYSTEM);
2388*29949e86Sstevel 		}
2389*29949e86Sstevel 		break;
2390*29949e86Sstevel 
2391*29949e86Sstevel 	/* aux 5v */
2392*29949e86Sstevel 	case SYS_V5_AUX_INDEX:
2393*29949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V5_AUX], s);
2394*29949e86Sstevel 		if (ps_ok) {
2395*29949e86Sstevel 			clear_fault(0, FT_V5_AUX, FT_SYSTEM);
2396*29949e86Sstevel 		} else {
2397*29949e86Sstevel 			reg_fault(0, FT_V5_AUX, FT_SYSTEM);
2398*29949e86Sstevel 		}
2399*29949e86Sstevel 		break;
2400*29949e86Sstevel 
2401*29949e86Sstevel 	/* peripheral 5v precharge */
2402*29949e86Sstevel 	case SYS_V5_P_PCH_INDEX:
2403*29949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V5_P_PCH], s);
2404*29949e86Sstevel 		if (ps_ok) {
2405*29949e86Sstevel 			clear_fault(0, FT_V5_P_PCH, FT_SYSTEM);
2406*29949e86Sstevel 		} else {
2407*29949e86Sstevel 			reg_fault(0, FT_V5_P_PCH, FT_SYSTEM);
2408*29949e86Sstevel 		}
2409*29949e86Sstevel 		break;
2410*29949e86Sstevel 
2411*29949e86Sstevel 	/* peripheral 12v precharge */
2412*29949e86Sstevel 	case SYS_V12_P_PCH_INDEX:
2413*29949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V12_P_PCH], s);
2414*29949e86Sstevel 		if (ps_ok) {
2415*29949e86Sstevel 			clear_fault(0, FT_V12_P_PCH, FT_SYSTEM);
2416*29949e86Sstevel 		} else {
2417*29949e86Sstevel 			reg_fault(0, FT_V12_P_PCH, FT_SYSTEM);
2418*29949e86Sstevel 		}
2419*29949e86Sstevel 		break;
2420*29949e86Sstevel 
2421*29949e86Sstevel 	/* 3.3v precharge */
2422*29949e86Sstevel 	case SYS_V3_PCH_INDEX:
2423*29949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V3_PCH], s);
2424*29949e86Sstevel 		if (ps_ok) {
2425*29949e86Sstevel 			clear_fault(0, FT_V3_PCH, FT_SYSTEM);
2426*29949e86Sstevel 		} else {
2427*29949e86Sstevel 			reg_fault(0, FT_V3_PCH, FT_SYSTEM);
2428*29949e86Sstevel 		}
2429*29949e86Sstevel 		break;
2430*29949e86Sstevel 
2431*29949e86Sstevel 	/* 5v precharge */
2432*29949e86Sstevel 	case SYS_V5_PCH_INDEX:
2433*29949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V5_PCH], s);
2434*29949e86Sstevel 		if (ps_ok) {
2435*29949e86Sstevel 			clear_fault(0, FT_V5_PCH, FT_SYSTEM);
2436*29949e86Sstevel 		} else {
2437*29949e86Sstevel 			reg_fault(0, FT_V5_PCH, FT_SYSTEM);
2438*29949e86Sstevel 		}
2439*29949e86Sstevel 		break;
2440*29949e86Sstevel 
2441*29949e86Sstevel 	/* peripheral power supply fans */
2442*29949e86Sstevel 	case SYS_P_FAN_INDEX:
2443*29949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_PPS_FAN], s);
2444*29949e86Sstevel 		if (ps_ok) {
2445*29949e86Sstevel 			clear_fault(0, FT_PPS_FAN, FT_SYSTEM);
2446*29949e86Sstevel 		} else {
2447*29949e86Sstevel 			reg_fault(0, FT_PPS_FAN, FT_SYSTEM);
2448*29949e86Sstevel 		}
2449*29949e86Sstevel 		break;
2450*29949e86Sstevel 	}
2451*29949e86Sstevel }
2452*29949e86Sstevel 
2453*29949e86Sstevel /*
2454*29949e86Sstevel  * The timeout from ps_fail_handler() that simply re-triggers a check
2455*29949e86Sstevel  * of the ps condition.
2456*29949e86Sstevel  */
2457*29949e86Sstevel static void
2458*29949e86Sstevel ps_fail_retry(void *arg)
2459*29949e86Sstevel {
2460*29949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
2461*29949e86Sstevel 
2462*29949e86Sstevel 	ASSERT(softsp);
2463*29949e86Sstevel 
2464*29949e86Sstevel 	ddi_trigger_softintr(softsp->ps_fail_poll_id);
2465*29949e86Sstevel }
2466*29949e86Sstevel 
2467*29949e86Sstevel /*
2468*29949e86Sstevel  * pps_fanfail_handler
2469*29949e86Sstevel  *
2470*29949e86Sstevel  * This routine is called from the high level handler.
2471*29949e86Sstevel  */
2472*29949e86Sstevel static uint_t
2473*29949e86Sstevel pps_fanfail_handler(caddr_t arg)
2474*29949e86Sstevel {
2475*29949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
2476*29949e86Sstevel 
2477*29949e86Sstevel 	ASSERT(softsp);
2478*29949e86Sstevel 
2479*29949e86Sstevel 	/* always check again in a bit by re-enabling the fan interrupt */
2480*29949e86Sstevel 	(void) timeout(pps_fanfail_retry, softsp, pps_fan_timeout_hz);
2481*29949e86Sstevel 
2482*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
2483*29949e86Sstevel }
2484*29949e86Sstevel 
2485*29949e86Sstevel /*
2486*29949e86Sstevel  * After a bit of waiting, we simply re-enable the interrupt to
2487*29949e86Sstevel  * see if we get another one.  The softintr triggered routine does
2488*29949e86Sstevel  * the dirty work for us since it runs in the interrupt context.
2489*29949e86Sstevel  */
2490*29949e86Sstevel static void
2491*29949e86Sstevel pps_fanfail_retry(void *arg)
2492*29949e86Sstevel {
2493*29949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
2494*29949e86Sstevel 
2495*29949e86Sstevel 	ASSERT(softsp);
2496*29949e86Sstevel 
2497*29949e86Sstevel 	ddi_trigger_softintr(softsp->pps_fan_high_id);
2498*29949e86Sstevel }
2499*29949e86Sstevel 
2500*29949e86Sstevel /*
2501*29949e86Sstevel  * The other half of the retry handler run from the interrupt context
2502*29949e86Sstevel  */
2503*29949e86Sstevel static uint_t
2504*29949e86Sstevel pps_fanfail_reenable(caddr_t arg)
2505*29949e86Sstevel {
2506*29949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
2507*29949e86Sstevel 	uchar_t tmp_reg;
2508*29949e86Sstevel 
2509*29949e86Sstevel 	ASSERT(softsp);
2510*29949e86Sstevel 
2511*29949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
2512*29949e86Sstevel 
2513*29949e86Sstevel 	/*
2514*29949e86Sstevel 	 * re-initialize the bit field for all pps fans to assumed good.
2515*29949e86Sstevel 	 * If the fans are still bad, we're going to get an immediate system
2516*29949e86Sstevel 	 * interrupt which will put the correct state back anyway.
2517*29949e86Sstevel 	 *
2518*29949e86Sstevel 	 * NOTE: the polling routines that use this state understand the
2519*29949e86Sstevel 	 * pulse resulting from above...
2520*29949e86Sstevel 	 */
2521*29949e86Sstevel 	softsp->pps_fan_saved = SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK;
2522*29949e86Sstevel 
2523*29949e86Sstevel 	*(softsp->csr) |= SYS_PPS_FAN_FAIL_EN;
2524*29949e86Sstevel 	tmp_reg = *(softsp->csr);
2525*29949e86Sstevel #ifdef lint
2526*29949e86Sstevel 	tmp_reg = tmp_reg;
2527*29949e86Sstevel #endif
2528*29949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
2529*29949e86Sstevel 
2530*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
2531*29949e86Sstevel }
2532*29949e86Sstevel 
2533*29949e86Sstevel /*
2534*29949e86Sstevel  *
2535*29949e86Sstevel  * Poll the hardware shadow state to determine the pps fan status.
2536*29949e86Sstevel  * The shadow state is maintained by the system_high handler and its
2537*29949e86Sstevel  * associated pps_* functions (above).
2538*29949e86Sstevel  *
2539*29949e86Sstevel  * There is a short time interval where the shadow state is pulsed to
2540*29949e86Sstevel  * the OK state even when the fans are bad.  However, this polling
2541*29949e86Sstevel  * routine has some built in hysteresis to filter out those _normal_
2542*29949e86Sstevel  * events.
2543*29949e86Sstevel  */
2544*29949e86Sstevel static void
2545*29949e86Sstevel pps_fan_poll(void *arg)
2546*29949e86Sstevel {
2547*29949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
2548*29949e86Sstevel 	int i;
2549*29949e86Sstevel 
2550*29949e86Sstevel 	ASSERT(softsp);
2551*29949e86Sstevel 
2552*29949e86Sstevel 	for (i = 0; i < SYS_PPS_FAN_COUNT; i++) {
2553*29949e86Sstevel 		int fanfail = FALSE;
2554*29949e86Sstevel 
2555*29949e86Sstevel 		/* determine fan status */
2556*29949e86Sstevel 		switch (i) {
2557*29949e86Sstevel 		case RACK:
2558*29949e86Sstevel 			fanfail = softsp->pps_fan_saved & SYS_RACK_FANFAIL;
2559*29949e86Sstevel 			break;
2560*29949e86Sstevel 
2561*29949e86Sstevel 		case AC:
2562*29949e86Sstevel 			/*
2563*29949e86Sstevel 			 * Don't bother polling the AC fan on 4 and 5 slot
2564*29949e86Sstevel 			 * systems.
2565*29949e86Sstevel 			 * Rather, it is handled by the power supply loop.
2566*29949e86Sstevel 			 */
2567*29949e86Sstevel 			fanfail = !(IS4SLOT(softsp->nslots) ||
2568*29949e86Sstevel 				IS5SLOT(softsp->nslots)) &&
2569*29949e86Sstevel 				!(softsp->pps_fan_saved & SYS_AC_FAN_OK);
2570*29949e86Sstevel 			break;
2571*29949e86Sstevel 
2572*29949e86Sstevel 		case KEYSW:
2573*29949e86Sstevel 			/*
2574*29949e86Sstevel 			 * This signal is not usable if aux5v is missing
2575*29949e86Sstevel 			 * so we will synthesize a failed fan when aux5v
2576*29949e86Sstevel 			 * fails or when pps0 is out.
2577*29949e86Sstevel 			 * The 4 and 5 slot systems behave the same.
2578*29949e86Sstevel 			 */
2579*29949e86Sstevel 			fanfail = (!(IS4SLOT(softsp->nslots) ||
2580*29949e86Sstevel 				IS5SLOT(softsp->nslots)) &&
2581*29949e86Sstevel 			    (softsp->ps_stats[SYS_V5_AUX_INDEX].dcshadow !=
2582*29949e86Sstevel 				PS_OK)) ||
2583*29949e86Sstevel 			    !(softsp->pps_fan_saved & SYS_KEYSW_FAN_OK);
2584*29949e86Sstevel 			break;
2585*29949e86Sstevel 
2586*29949e86Sstevel 		}
2587*29949e86Sstevel 
2588*29949e86Sstevel 		/* is the fan bad? */
2589*29949e86Sstevel 		if (fanfail) {
2590*29949e86Sstevel 
2591*29949e86Sstevel 			/* is this condition different than we know? */
2592*29949e86Sstevel 			if (softsp->pps_fan_state_count[i] == 0) {
2593*29949e86Sstevel 
2594*29949e86Sstevel 				/* log the change to failed */
2595*29949e86Sstevel 				pps_fan_state_change(softsp, i, FALSE);
2596*29949e86Sstevel 			}
2597*29949e86Sstevel 
2598*29949e86Sstevel 			/* always restart the fan OK counter */
2599*29949e86Sstevel 			softsp->pps_fan_state_count[i] = PPS_FROM_FAIL_TICKS;
2600*29949e86Sstevel 		} else {
2601*29949e86Sstevel 
2602*29949e86Sstevel 			/* do we currently know the fan is bad? */
2603*29949e86Sstevel 			if (softsp->pps_fan_state_count[i]) {
2604*29949e86Sstevel 
2605*29949e86Sstevel 				/* yes, but has it been stable? */
2606*29949e86Sstevel 				if (--softsp->pps_fan_state_count[i] == 0) {
2607*29949e86Sstevel 
2608*29949e86Sstevel 					/* log the change to OK */
2609*29949e86Sstevel 					pps_fan_state_change(softsp, i, TRUE);
2610*29949e86Sstevel 				}
2611*29949e86Sstevel 			}
2612*29949e86Sstevel 		}
2613*29949e86Sstevel 	}
2614*29949e86Sstevel 
2615*29949e86Sstevel 	/* always check again in a bit by re-enabling the fan interrupt */
2616*29949e86Sstevel 	(void) timeout(pps_fan_poll, softsp, pps_fan_timeout_hz);
2617*29949e86Sstevel }
2618*29949e86Sstevel 
2619*29949e86Sstevel /*
2620*29949e86Sstevel  * pps_fan_state_change()
2621*29949e86Sstevel  *
2622*29949e86Sstevel  * Log the changed fan condition and update the external status.
2623*29949e86Sstevel  */
2624*29949e86Sstevel static void
2625*29949e86Sstevel pps_fan_state_change(struct sysctrl_soft_state *softsp, int index, int fan_ok)
2626*29949e86Sstevel {
2627*29949e86Sstevel 	char *fan_type;
2628*29949e86Sstevel 	char *state = fan_ok ? "fans OK" : "fan failure detected";
2629*29949e86Sstevel 
2630*29949e86Sstevel 	switch (index) {
2631*29949e86Sstevel 	case RACK:
2632*29949e86Sstevel 		/* 4 and 5 slot systems behave the same */
2633*29949e86Sstevel 		fan_type = (IS4SLOT(softsp->nslots) ||
2634*29949e86Sstevel 				IS5SLOT(softsp->nslots)) ?
2635*29949e86Sstevel 				"Disk Drive" : "Rack Exhaust";
2636*29949e86Sstevel 		if (fan_ok) {
2637*29949e86Sstevel 			softsp->pps_fan_external_state &= ~SYS_RACK_FANFAIL;
2638*29949e86Sstevel 			clear_fault(0, (IS4SLOT(softsp->nslots) ||
2639*29949e86Sstevel 				IS5SLOT(softsp->nslots)) ? FT_DSK_FAN :
2640*29949e86Sstevel 				FT_RACK_EXH, FT_SYSTEM);
2641*29949e86Sstevel 		} else {
2642*29949e86Sstevel 			softsp->pps_fan_external_state |= SYS_RACK_FANFAIL;
2643*29949e86Sstevel 			reg_fault(0, (IS4SLOT(softsp->nslots) ||
2644*29949e86Sstevel 				IS5SLOT(softsp->nslots)) ? FT_DSK_FAN :
2645*29949e86Sstevel 				FT_RACK_EXH, FT_SYSTEM);
2646*29949e86Sstevel 		}
2647*29949e86Sstevel 		break;
2648*29949e86Sstevel 
2649*29949e86Sstevel 	case AC:
2650*29949e86Sstevel 		fan_type = "AC Box";
2651*29949e86Sstevel 		if (fan_ok) {
2652*29949e86Sstevel 			softsp->pps_fan_external_state |= SYS_AC_FAN_OK;
2653*29949e86Sstevel 			clear_fault(0, FT_AC_FAN, FT_SYSTEM);
2654*29949e86Sstevel 		} else {
2655*29949e86Sstevel 			softsp->pps_fan_external_state &= ~SYS_AC_FAN_OK;
2656*29949e86Sstevel 			reg_fault(0, FT_AC_FAN, FT_SYSTEM);
2657*29949e86Sstevel 		}
2658*29949e86Sstevel 		break;
2659*29949e86Sstevel 
2660*29949e86Sstevel 	case KEYSW:
2661*29949e86Sstevel 		fan_type = "Keyswitch";
2662*29949e86Sstevel 		if (fan_ok) {
2663*29949e86Sstevel 			softsp->pps_fan_external_state |= SYS_KEYSW_FAN_OK;
2664*29949e86Sstevel 			clear_fault(0, FT_KEYSW_FAN, FT_SYSTEM);
2665*29949e86Sstevel 		} else {
2666*29949e86Sstevel 			softsp->pps_fan_external_state &= ~SYS_KEYSW_FAN_OK;
2667*29949e86Sstevel 			reg_fault(0, FT_KEYSW_FAN, FT_SYSTEM);
2668*29949e86Sstevel 		}
2669*29949e86Sstevel 		break;
2670*29949e86Sstevel 	default:
2671*29949e86Sstevel 		fan_type = "[invalid fan id]";
2672*29949e86Sstevel 		break;
2673*29949e86Sstevel 	}
2674*29949e86Sstevel 
2675*29949e86Sstevel 	/* now log the state change */
2676*29949e86Sstevel 	cmn_err(fan_ok ? CE_NOTE : CE_WARN, "%s %s", fan_type, state);
2677*29949e86Sstevel }
2678*29949e86Sstevel 
2679*29949e86Sstevel static uint_t
2680*29949e86Sstevel bd_insert_handler(caddr_t arg)
2681*29949e86Sstevel {
2682*29949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
2683*29949e86Sstevel 
2684*29949e86Sstevel 	ASSERT(softsp);
2685*29949e86Sstevel 
2686*29949e86Sstevel 	DPRINTF(SYSCTRL_ATTACH_DEBUG, ("bd_insert_handler()"));
2687*29949e86Sstevel 
2688*29949e86Sstevel 	(void) timeout(bd_insert_timeout, softsp, bd_insert_delay_hz);
2689*29949e86Sstevel 
2690*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
2691*29949e86Sstevel }
2692*29949e86Sstevel 
2693*29949e86Sstevel void
2694*29949e86Sstevel bd_remove_poll(struct sysctrl_soft_state *softsp)
2695*29949e86Sstevel {
2696*29949e86Sstevel 	ASSERT(fhc_bdlist_locked());
2697*29949e86Sstevel 
2698*29949e86Sstevel 	if (!bd_remove_to_id) {
2699*29949e86Sstevel 		bd_remove_to_id = timeout(bd_remove_timeout, softsp,
2700*29949e86Sstevel 						bd_remove_timeout_hz);
2701*29949e86Sstevel 	} else {
2702*29949e86Sstevel 		DPRINTF(SYSCTRL_ATTACH_DEBUG,
2703*29949e86Sstevel 			("bd_remove_poll ignoring start request"));
2704*29949e86Sstevel 	}
2705*29949e86Sstevel }
2706*29949e86Sstevel 
2707*29949e86Sstevel /*
2708*29949e86Sstevel  * bd_insert_timeout()
2709*29949e86Sstevel  *
2710*29949e86Sstevel  * This routine handles the board insert interrupt. It is called from a
2711*29949e86Sstevel  * timeout so that it does not run at interrupt level. The main job
2712*29949e86Sstevel  * of this routine is to find hotplugged boards and de-assert the
2713*29949e86Sstevel  * board insert interrupt coming from the board. For hotplug phase I,
2714*29949e86Sstevel  * the routine also powers down the board.
2715*29949e86Sstevel  * JTAG scan is used to find boards which have been inserted.
2716*29949e86Sstevel  * All other control of the boards is also done by JTAG scan.
2717*29949e86Sstevel  */
2718*29949e86Sstevel static void
2719*29949e86Sstevel bd_insert_timeout(void *arg)
2720*29949e86Sstevel {
2721*29949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
2722*29949e86Sstevel 	int found;
2723*29949e86Sstevel 
2724*29949e86Sstevel 	ASSERT(softsp);
2725*29949e86Sstevel 
2726*29949e86Sstevel 	if (sysctrl_hotplug_disabled) {
2727*29949e86Sstevel 		sysc_policy_update(softsp, NULL, SYSC_EVT_BD_HP_DISABLED);
2728*29949e86Sstevel 	} else {
2729*29949e86Sstevel 		/*
2730*29949e86Sstevel 		 * Lock the board list mutex. Keep it locked until all work
2731*29949e86Sstevel 		 * is done.
2732*29949e86Sstevel 		 */
2733*29949e86Sstevel 		(void) fhc_bdlist_lock(-1);
2734*29949e86Sstevel 
2735*29949e86Sstevel 		found = fhc_bd_insert_scan();
2736*29949e86Sstevel 
2737*29949e86Sstevel 		if (found) {
2738*29949e86Sstevel 			DPRINTF(SYSCTRL_ATTACH_DEBUG,
2739*29949e86Sstevel 			    ("bd_insert_timeout starting bd_remove_poll()"));
2740*29949e86Sstevel 			bd_remove_poll(softsp);
2741*29949e86Sstevel 		}
2742*29949e86Sstevel 
2743*29949e86Sstevel 		fhc_bdlist_unlock();
2744*29949e86Sstevel 	}
2745*29949e86Sstevel 
2746*29949e86Sstevel 	/*
2747*29949e86Sstevel 	 * Enable interrupts.
2748*29949e86Sstevel 	 */
2749*29949e86Sstevel 	ddi_trigger_softintr(softsp->sbrd_gone_id);
2750*29949e86Sstevel }
2751*29949e86Sstevel 
2752*29949e86Sstevel static void
2753*29949e86Sstevel bd_remove_timeout(void *arg)
2754*29949e86Sstevel {
2755*29949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
2756*29949e86Sstevel 	int keep_polling;
2757*29949e86Sstevel 
2758*29949e86Sstevel 	ASSERT(softsp);
2759*29949e86Sstevel 
2760*29949e86Sstevel 	/*
2761*29949e86Sstevel 	 * Lock the board list mutex. Keep it locked until all work
2762*29949e86Sstevel 	 * is done.
2763*29949e86Sstevel 	 */
2764*29949e86Sstevel 	(void) fhc_bdlist_lock(-1);
2765*29949e86Sstevel 
2766*29949e86Sstevel 	bd_remove_to_id = 0;	/* delete our timeout ID */
2767*29949e86Sstevel 
2768*29949e86Sstevel 	keep_polling = fhc_bd_remove_scan();
2769*29949e86Sstevel 
2770*29949e86Sstevel 	if (keep_polling) {
2771*29949e86Sstevel 		bd_remove_poll(softsp);
2772*29949e86Sstevel 	} else {
2773*29949e86Sstevel 		DPRINTF(SYSCTRL_ATTACH_DEBUG, ("exiting bd_remove_poll."));
2774*29949e86Sstevel 	}
2775*29949e86Sstevel 
2776*29949e86Sstevel 	fhc_bdlist_unlock();
2777*29949e86Sstevel }
2778*29949e86Sstevel 
2779*29949e86Sstevel static uint_t
2780*29949e86Sstevel bd_insert_normal(caddr_t arg)
2781*29949e86Sstevel {
2782*29949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
2783*29949e86Sstevel 	uchar_t tmp_reg;
2784*29949e86Sstevel 
2785*29949e86Sstevel 	ASSERT(softsp);
2786*29949e86Sstevel 
2787*29949e86Sstevel 	/* has the condition been removed? */
2788*29949e86Sstevel 	/* XXX add deglitch state machine here */
2789*29949e86Sstevel 	if (!(*(softsp->status1) & SYS_NOT_BRD_PRES)) {
2790*29949e86Sstevel 		/* check again in a few */
2791*29949e86Sstevel 		(void) timeout(bd_insert_timeout, softsp, bd_insert_retry_hz);
2792*29949e86Sstevel 	} else {
2793*29949e86Sstevel 		/* Turn on the enable bit for this interrupt */
2794*29949e86Sstevel 		mutex_enter(&softsp->csr_mutex);
2795*29949e86Sstevel 		*(softsp->csr) |= SYS_SBRD_PRES_EN;
2796*29949e86Sstevel 		/* flush the hardware store buffer */
2797*29949e86Sstevel 		tmp_reg = *(softsp->csr);
2798*29949e86Sstevel #ifdef lint
2799*29949e86Sstevel 		tmp_reg = tmp_reg;
2800*29949e86Sstevel #endif
2801*29949e86Sstevel 		mutex_exit(&softsp->csr_mutex);
2802*29949e86Sstevel 	}
2803*29949e86Sstevel 
2804*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
2805*29949e86Sstevel }
2806*29949e86Sstevel 
2807*29949e86Sstevel /*
2808*29949e86Sstevel  * blink LED handler.
2809*29949e86Sstevel  *
2810*29949e86Sstevel  * The actual bit manipulation needs to occur at interrupt level
2811*29949e86Sstevel  * because we need access to the CSR with its CSR mutex
2812*29949e86Sstevel  */
2813*29949e86Sstevel static uint_t
2814*29949e86Sstevel blink_led_handler(caddr_t arg)
2815*29949e86Sstevel {
2816*29949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
2817*29949e86Sstevel 	uchar_t tmp_reg;
2818*29949e86Sstevel 
2819*29949e86Sstevel 	ASSERT(softsp);
2820*29949e86Sstevel 
2821*29949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
2822*29949e86Sstevel 
2823*29949e86Sstevel 	/*
2824*29949e86Sstevel 	 * XXX - The lock for the sys_led is not held here. If more
2825*29949e86Sstevel 	 * complicated tasks are done with the System LED, then
2826*29949e86Sstevel 	 * locking should be done here.
2827*29949e86Sstevel 	 */
2828*29949e86Sstevel 
2829*29949e86Sstevel 	/* read the hardware register. */
2830*29949e86Sstevel 	tmp_reg = *(softsp->csr);
2831*29949e86Sstevel 
2832*29949e86Sstevel 	/* Only turn on the OS System LED bit if the softsp state is on. */
2833*29949e86Sstevel 	if (softsp->sys_led) {
2834*29949e86Sstevel 		tmp_reg |= SYS_LED_RIGHT;
2835*29949e86Sstevel 	} else {
2836*29949e86Sstevel 		tmp_reg &= ~SYS_LED_RIGHT;
2837*29949e86Sstevel 	}
2838*29949e86Sstevel 
2839*29949e86Sstevel 	/* Turn on the yellow LED if system fault status is set. */
2840*29949e86Sstevel 	if (softsp->sys_fault) {
2841*29949e86Sstevel 		tmp_reg |= SYS_LED_MID;
2842*29949e86Sstevel 	} else {
2843*29949e86Sstevel 		tmp_reg &= ~SYS_LED_MID;
2844*29949e86Sstevel 	}
2845*29949e86Sstevel 
2846*29949e86Sstevel 	/* write to the hardware register */
2847*29949e86Sstevel 	*(softsp->csr) = tmp_reg;
2848*29949e86Sstevel 
2849*29949e86Sstevel 	/* flush the hardware store buffer */
2850*29949e86Sstevel 	tmp_reg = *(softsp->csr);
2851*29949e86Sstevel #ifdef lint
2852*29949e86Sstevel 	tmp_reg = tmp_reg;
2853*29949e86Sstevel #endif
2854*29949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
2855*29949e86Sstevel 
2856*29949e86Sstevel 	(void) timeout(blink_led_timeout, softsp, blink_led_timeout_hz);
2857*29949e86Sstevel 
2858*29949e86Sstevel 	return (DDI_INTR_CLAIMED);
2859*29949e86Sstevel }
2860*29949e86Sstevel 
2861*29949e86Sstevel /*
2862*29949e86Sstevel  * simply re-trigger the interrupt handler on led timeout
2863*29949e86Sstevel  */
2864*29949e86Sstevel static void
2865*29949e86Sstevel blink_led_timeout(void *arg)
2866*29949e86Sstevel {
2867*29949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
2868*29949e86Sstevel 	int led_state;
2869*29949e86Sstevel 
2870*29949e86Sstevel 	ASSERT(softsp);
2871*29949e86Sstevel 
2872*29949e86Sstevel 	/*
2873*29949e86Sstevel 	 * Process the system fault list here. This is where the driver
2874*29949e86Sstevel 	 * must decide what yellow LEDs to turn on if any. The fault
2875*29949e86Sstevel 	 * list is walked and each fhc_list entry is updated with it's
2876*29949e86Sstevel 	 * yellow LED status. This info is used later by the routine
2877*29949e86Sstevel 	 * toggle_board_green_leds().
2878*29949e86Sstevel 	 *
2879*29949e86Sstevel 	 * The variable system_fault is non-zero if any non-
2880*29949e86Sstevel 	 * suppressed faults are found in the system.
2881*29949e86Sstevel 	 */
2882*29949e86Sstevel 	softsp->sys_fault = process_fault_list();
2883*29949e86Sstevel 
2884*29949e86Sstevel 	/* blink the system board OS LED */
2885*29949e86Sstevel 	mutex_enter(&softsp->sys_led_lock);
2886*29949e86Sstevel 	softsp->sys_led = !softsp->sys_led;
2887*29949e86Sstevel 	led_state = softsp->sys_led;
2888*29949e86Sstevel 	mutex_exit(&softsp->sys_led_lock);
2889*29949e86Sstevel 
2890*29949e86Sstevel 	toggle_board_green_leds(led_state);
2891*29949e86Sstevel 
2892*29949e86Sstevel 	ddi_trigger_softintr(softsp->blink_led_id);
2893*29949e86Sstevel }
2894*29949e86Sstevel 
2895*29949e86Sstevel void
2896*29949e86Sstevel toggle_board_green_leds(int led_state)
2897*29949e86Sstevel {
2898*29949e86Sstevel 	fhc_bd_t *list;
2899*29949e86Sstevel 
2900*29949e86Sstevel 	(void) fhc_bdlist_lock(-1);
2901*29949e86Sstevel 	for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) {
2902*29949e86Sstevel 		uint_t value = 0;
2903*29949e86Sstevel 
2904*29949e86Sstevel 		if (list->sc.in_transition ||
2905*29949e86Sstevel 		    (list->sc.rstate != SYSC_CFGA_RSTATE_CONNECTED))
2906*29949e86Sstevel 			continue;
2907*29949e86Sstevel 
2908*29949e86Sstevel 		ASSERT(list->sc.type != CLOCK_BOARD);
2909*29949e86Sstevel 		ASSERT(list->sc.type != DISK_BOARD);
2910*29949e86Sstevel 		ASSERT(list->softsp);
2911*29949e86Sstevel 
2912*29949e86Sstevel 		if ((list->sc.ostate == SYSC_CFGA_OSTATE_CONFIGURED) &&
2913*29949e86Sstevel 		    led_state)
2914*29949e86Sstevel 			value |= FHC_LED_RIGHT;
2915*29949e86Sstevel 
2916*29949e86Sstevel 		if (list->fault)
2917*29949e86Sstevel 			value |= FHC_LED_MID;
2918*29949e86Sstevel 		else
2919*29949e86Sstevel 			value &= ~FHC_LED_MID;
2920*29949e86Sstevel 
2921*29949e86Sstevel 		update_board_leds(list, FHC_LED_RIGHT|FHC_LED_MID, value);
2922*29949e86Sstevel 	}
2923*29949e86Sstevel 	fhc_bdlist_unlock();
2924*29949e86Sstevel }
2925*29949e86Sstevel 
2926*29949e86Sstevel /*
2927*29949e86Sstevel  * timestamp an AC power failure in nvram
2928*29949e86Sstevel  */
2929*29949e86Sstevel static void
2930*29949e86Sstevel nvram_update_powerfail(struct sysctrl_soft_state *softsp)
2931*29949e86Sstevel {
2932*29949e86Sstevel 	char buf[80];
2933*29949e86Sstevel 	int len = 0;
2934*29949e86Sstevel 
2935*29949e86Sstevel 	numtos(gethrestime_sec(), buf);
2936*29949e86Sstevel 
2937*29949e86Sstevel 	if (softsp->options_nodeid) {
2938*29949e86Sstevel 		len = prom_setprop(softsp->options_nodeid, "powerfail-time",
2939*29949e86Sstevel 			buf, strlen(buf)+1);
2940*29949e86Sstevel 	}
2941*29949e86Sstevel 
2942*29949e86Sstevel 	if (len <= 0) {
2943*29949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: failed to set powerfail-time "
2944*29949e86Sstevel 			"to %s\n", ddi_get_instance(softsp->dip), buf);
2945*29949e86Sstevel 	}
2946*29949e86Sstevel }
2947*29949e86Sstevel 
2948*29949e86Sstevel void
2949*29949e86Sstevel sysctrl_add_kstats(struct sysctrl_soft_state *softsp)
2950*29949e86Sstevel {
2951*29949e86Sstevel 	struct kstat	*ksp;		/* Generic sysctrl kstats */
2952*29949e86Sstevel 	struct kstat	*pksp;		/* Power Supply kstat */
2953*29949e86Sstevel 	struct kstat	*tksp;		/* Sysctrl temperatrure kstat */
2954*29949e86Sstevel 	struct kstat	*ttsp;		/* Sysctrl temperature test kstat */
2955*29949e86Sstevel 
2956*29949e86Sstevel 	if ((ksp = kstat_create("unix", ddi_get_instance(softsp->dip),
2957*29949e86Sstevel 	    SYSCTRL_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED,
2958*29949e86Sstevel 	    sizeof (struct sysctrl_kstat) / sizeof (kstat_named_t),
2959*29949e86Sstevel 	    KSTAT_FLAG_PERSISTENT)) == NULL) {
2960*29949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
2961*29949e86Sstevel 			ddi_get_instance(softsp->dip));
2962*29949e86Sstevel 	} else {
2963*29949e86Sstevel 		struct sysctrl_kstat *sysksp;
2964*29949e86Sstevel 
2965*29949e86Sstevel 		sysksp = (struct sysctrl_kstat *)(ksp->ks_data);
2966*29949e86Sstevel 
2967*29949e86Sstevel 		/* now init the named kstats */
2968*29949e86Sstevel 		kstat_named_init(&sysksp->csr, CSR_KSTAT_NAMED,
2969*29949e86Sstevel 			KSTAT_DATA_CHAR);
2970*29949e86Sstevel 
2971*29949e86Sstevel 		kstat_named_init(&sysksp->status1, STAT1_KSTAT_NAMED,
2972*29949e86Sstevel 			KSTAT_DATA_CHAR);
2973*29949e86Sstevel 
2974*29949e86Sstevel 		kstat_named_init(&sysksp->status2, STAT2_KSTAT_NAMED,
2975*29949e86Sstevel 			KSTAT_DATA_CHAR);
2976*29949e86Sstevel 
2977*29949e86Sstevel 		kstat_named_init(&sysksp->clk_freq2, CLK_FREQ2_KSTAT_NAMED,
2978*29949e86Sstevel 			KSTAT_DATA_CHAR);
2979*29949e86Sstevel 
2980*29949e86Sstevel 		kstat_named_init(&sysksp->fan_status, FAN_KSTAT_NAMED,
2981*29949e86Sstevel 			KSTAT_DATA_CHAR);
2982*29949e86Sstevel 
2983*29949e86Sstevel 		kstat_named_init(&sysksp->key_status, KEY_KSTAT_NAMED,
2984*29949e86Sstevel 			KSTAT_DATA_CHAR);
2985*29949e86Sstevel 
2986*29949e86Sstevel 		kstat_named_init(&sysksp->power_state, POWER_KSTAT_NAMED,
2987*29949e86Sstevel 			KSTAT_DATA_INT32);
2988*29949e86Sstevel 
2989*29949e86Sstevel 		kstat_named_init(&sysksp->clk_ver, CLK_VER_KSTAT_NAME,
2990*29949e86Sstevel 			KSTAT_DATA_CHAR);
2991*29949e86Sstevel 
2992*29949e86Sstevel 		ksp->ks_update = sysctrl_kstat_update;
2993*29949e86Sstevel 		ksp->ks_private = (void *)softsp;
2994*29949e86Sstevel 		kstat_install(ksp);
2995*29949e86Sstevel 	}
2996*29949e86Sstevel 
2997*29949e86Sstevel 	if ((tksp = kstat_create("unix", CLOCK_BOARD_INDEX,
2998*29949e86Sstevel 	    OVERTEMP_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
2999*29949e86Sstevel 	    sizeof (struct temp_stats), KSTAT_FLAG_PERSISTENT)) == NULL) {
3000*29949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
3001*29949e86Sstevel 			ddi_get_instance(softsp->dip));
3002*29949e86Sstevel 	} else {
3003*29949e86Sstevel 		tksp->ks_update = overtemp_kstat_update;
3004*29949e86Sstevel 		tksp->ks_private = (void *)&softsp->tempstat;
3005*29949e86Sstevel 		kstat_install(tksp);
3006*29949e86Sstevel 	}
3007*29949e86Sstevel 
3008*29949e86Sstevel 	if ((ttsp = kstat_create("unix", CLOCK_BOARD_INDEX,
3009*29949e86Sstevel 	    TEMP_OVERRIDE_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, sizeof (short),
3010*29949e86Sstevel 		KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
3011*29949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
3012*29949e86Sstevel 			ddi_get_instance(softsp->dip));
3013*29949e86Sstevel 	} else {
3014*29949e86Sstevel 		ttsp->ks_update = temp_override_kstat_update;
3015*29949e86Sstevel 		ttsp->ks_private = (void *)&softsp->tempstat.override;
3016*29949e86Sstevel 		kstat_install(ttsp);
3017*29949e86Sstevel 	}
3018*29949e86Sstevel 
3019*29949e86Sstevel 	if ((pksp = kstat_create("unix", ddi_get_instance(softsp->dip),
3020*29949e86Sstevel 	    PSSHAD_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
3021*29949e86Sstevel 	    SYS_PS_COUNT, KSTAT_FLAG_PERSISTENT)) == NULL) {
3022*29949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
3023*29949e86Sstevel 			ddi_get_instance(softsp->dip));
3024*29949e86Sstevel 	} else {
3025*29949e86Sstevel 		pksp->ks_update = psstat_kstat_update;
3026*29949e86Sstevel 		pksp->ks_private = (void *)softsp;
3027*29949e86Sstevel 		kstat_install(pksp);
3028*29949e86Sstevel 	}
3029*29949e86Sstevel }
3030*29949e86Sstevel 
3031*29949e86Sstevel static int
3032*29949e86Sstevel sysctrl_kstat_update(kstat_t *ksp, int rw)
3033*29949e86Sstevel {
3034*29949e86Sstevel 	struct sysctrl_kstat *sysksp;
3035*29949e86Sstevel 	struct sysctrl_soft_state *softsp;
3036*29949e86Sstevel 
3037*29949e86Sstevel 	sysksp = (struct sysctrl_kstat *)(ksp->ks_data);
3038*29949e86Sstevel 	softsp = (struct sysctrl_soft_state *)(ksp->ks_private);
3039*29949e86Sstevel 
3040*29949e86Sstevel 	/* this is a read-only kstat. Exit on a write */
3041*29949e86Sstevel 
3042*29949e86Sstevel 	if (rw == KSTAT_WRITE) {
3043*29949e86Sstevel 		return (EACCES);
3044*29949e86Sstevel 	} else {
3045*29949e86Sstevel 		/*
3046*29949e86Sstevel 		 * copy the current state of the hardware into the
3047*29949e86Sstevel 		 * kstat structure.
3048*29949e86Sstevel 		 */
3049*29949e86Sstevel 		sysksp->csr.value.c[0] = *(softsp->csr);
3050*29949e86Sstevel 		sysksp->status1.value.c[0] = *(softsp->status1);
3051*29949e86Sstevel 		sysksp->status2.value.c[0] = *(softsp->status2);
3052*29949e86Sstevel 		sysksp->clk_freq2.value.c[0] = *(softsp->clk_freq2);
3053*29949e86Sstevel 
3054*29949e86Sstevel 		sysksp->fan_status.value.c[0] = softsp->pps_fan_external_state;
3055*29949e86Sstevel 		sysksp->key_status.value.c[0] = softsp->key_shadow;
3056*29949e86Sstevel 		sysksp->power_state.value.i32 = softsp->power_state;
3057*29949e86Sstevel 
3058*29949e86Sstevel 		/*
3059*29949e86Sstevel 		 * non-existence of the clock version register returns the
3060*29949e86Sstevel 		 * value 0xff when the hardware register location is read
3061*29949e86Sstevel 		 */
3062*29949e86Sstevel 		if (softsp->clk_ver != NULL)
3063*29949e86Sstevel 			sysksp->clk_ver.value.c[0] = *(softsp->clk_ver);
3064*29949e86Sstevel 		else
3065*29949e86Sstevel 			sysksp->clk_ver.value.c[0] = (char)0xff;
3066*29949e86Sstevel 	}
3067*29949e86Sstevel 	return (0);
3068*29949e86Sstevel }
3069*29949e86Sstevel 
3070*29949e86Sstevel static int
3071*29949e86Sstevel psstat_kstat_update(kstat_t *ksp, int rw)
3072*29949e86Sstevel {
3073*29949e86Sstevel 	struct sysctrl_soft_state *softsp;
3074*29949e86Sstevel 	uchar_t *ptr = (uchar_t *)(ksp->ks_data);
3075*29949e86Sstevel 	int ps;
3076*29949e86Sstevel 
3077*29949e86Sstevel 	softsp = (struct sysctrl_soft_state *)(ksp->ks_private);
3078*29949e86Sstevel 
3079*29949e86Sstevel 	if (rw == KSTAT_WRITE) {
3080*29949e86Sstevel 		return (EACCES);
3081*29949e86Sstevel 	} else {
3082*29949e86Sstevel 		for (ps = 0; ps < SYS_PS_COUNT; ps++) {
3083*29949e86Sstevel 			*ptr++ = softsp->ps_stats[ps].dcshadow;
3084*29949e86Sstevel 		}
3085*29949e86Sstevel 	}
3086*29949e86Sstevel 	return (0);
3087*29949e86Sstevel }
3088*29949e86Sstevel 
3089*29949e86Sstevel static void
3090*29949e86Sstevel sysctrl_thread_wakeup(void *arg)
3091*29949e86Sstevel {
3092*29949e86Sstevel 	int type = (int)(uintptr_t)arg;
3093*29949e86Sstevel 
3094*29949e86Sstevel 	/*
3095*29949e86Sstevel 	 * grab mutex to guarantee that our wakeup call
3096*29949e86Sstevel 	 * arrives after we go to sleep -- so we can't sleep forever.
3097*29949e86Sstevel 	 */
3098*29949e86Sstevel 	mutex_enter(&sslist_mutex);
3099*29949e86Sstevel 	switch (type) {
3100*29949e86Sstevel 	case OVERTEMP_POLL:
3101*29949e86Sstevel 		cv_signal(&overtemp_cv);
3102*29949e86Sstevel 		break;
3103*29949e86Sstevel 	case KEYSWITCH_POLL:
3104*29949e86Sstevel 		cv_signal(&keyswitch_cv);
3105*29949e86Sstevel 		break;
3106*29949e86Sstevel 	default:
3107*29949e86Sstevel 		cmn_err(CE_WARN, "sysctrl: invalid type %d to wakeup\n", type);
3108*29949e86Sstevel 		break;
3109*29949e86Sstevel 	}
3110*29949e86Sstevel 	mutex_exit(&sslist_mutex);
3111*29949e86Sstevel }
3112*29949e86Sstevel 
3113*29949e86Sstevel static void
3114*29949e86Sstevel sysctrl_overtemp_poll(void)
3115*29949e86Sstevel {
3116*29949e86Sstevel 	struct sysctrl_soft_state *list;
3117*29949e86Sstevel 	callb_cpr_t cprinfo;
3118*29949e86Sstevel 
3119*29949e86Sstevel 	CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "overtemp");
3120*29949e86Sstevel 
3121*29949e86Sstevel 	/* The overtemp data structures are protected by a mutex. */
3122*29949e86Sstevel 	mutex_enter(&sslist_mutex);
3123*29949e86Sstevel 
3124*29949e86Sstevel 	while (sysctrl_do_overtemp_thread) {
3125*29949e86Sstevel 
3126*29949e86Sstevel 		for (list = sys_list; list != NULL; list = list->next) {
3127*29949e86Sstevel 			if (list->temp_reg != NULL) {
3128*29949e86Sstevel 				update_temp(list->pdip, &list->tempstat,
3129*29949e86Sstevel 					*(list->temp_reg));
3130*29949e86Sstevel 			}
3131*29949e86Sstevel 		}
3132*29949e86Sstevel 
3133*29949e86Sstevel 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
3134*29949e86Sstevel 
3135*29949e86Sstevel 		/* now have this thread sleep for a while */
3136*29949e86Sstevel 		(void) timeout(sysctrl_thread_wakeup, (void *)OVERTEMP_POLL,
3137*29949e86Sstevel 			overtemp_timeout_hz);
3138*29949e86Sstevel 
3139*29949e86Sstevel 		cv_wait(&overtemp_cv, &sslist_mutex);
3140*29949e86Sstevel 
3141*29949e86Sstevel 		CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex);
3142*29949e86Sstevel 	}
3143*29949e86Sstevel 	CALLB_CPR_EXIT(&cprinfo);
3144*29949e86Sstevel 	thread_exit();
3145*29949e86Sstevel 	/* NOTREACHED */
3146*29949e86Sstevel }
3147*29949e86Sstevel 
3148*29949e86Sstevel static void
3149*29949e86Sstevel sysctrl_keyswitch_poll(void)
3150*29949e86Sstevel {
3151*29949e86Sstevel 	struct sysctrl_soft_state *list;
3152*29949e86Sstevel 	callb_cpr_t cprinfo;
3153*29949e86Sstevel 
3154*29949e86Sstevel 	CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "keyswitch");
3155*29949e86Sstevel 
3156*29949e86Sstevel 	/* The keyswitch data strcutures are protected by a mutex. */
3157*29949e86Sstevel 	mutex_enter(&sslist_mutex);
3158*29949e86Sstevel 
3159*29949e86Sstevel 	while (sysctrl_do_keyswitch_thread) {
3160*29949e86Sstevel 
3161*29949e86Sstevel 		for (list = sys_list; list != NULL; list = list->next) {
3162*29949e86Sstevel 			if (list->status1 != NULL)
3163*29949e86Sstevel 				update_key_state(list);
3164*29949e86Sstevel 		}
3165*29949e86Sstevel 
3166*29949e86Sstevel 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
3167*29949e86Sstevel 
3168*29949e86Sstevel 		/* now have this thread sleep for a while */
3169*29949e86Sstevel 		(void) timeout(sysctrl_thread_wakeup, (void *)KEYSWITCH_POLL,
3170*29949e86Sstevel 			keyswitch_timeout_hz);
3171*29949e86Sstevel 
3172*29949e86Sstevel 		cv_wait(&keyswitch_cv, &sslist_mutex);
3173*29949e86Sstevel 
3174*29949e86Sstevel 		CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex);
3175*29949e86Sstevel 	}
3176*29949e86Sstevel 	CALLB_CPR_EXIT(&cprinfo);
3177*29949e86Sstevel 	thread_exit();
3178*29949e86Sstevel 	/* NOTREACHED */
3179*29949e86Sstevel }
3180*29949e86Sstevel 
3181*29949e86Sstevel /*
3182*29949e86Sstevel  * check the key switch position for state changes
3183*29949e86Sstevel  */
3184*29949e86Sstevel static void
3185*29949e86Sstevel update_key_state(struct sysctrl_soft_state *list)
3186*29949e86Sstevel {
3187*29949e86Sstevel 	enum keyswitch_state key;
3188*29949e86Sstevel 
3189*29949e86Sstevel 	/*
3190*29949e86Sstevel 	 * snapshot current hardware key position
3191*29949e86Sstevel 	 */
3192*29949e86Sstevel 	if (*(list->status1) & SYS_NOT_SECURE)
3193*29949e86Sstevel 		key = KEY_NOT_SECURE;
3194*29949e86Sstevel 	else
3195*29949e86Sstevel 		key = KEY_SECURE;
3196*29949e86Sstevel 
3197*29949e86Sstevel 	/*
3198*29949e86Sstevel 	 * check for state transition
3199*29949e86Sstevel 	 */
3200*29949e86Sstevel 	if (key != list->key_shadow) {
3201*29949e86Sstevel 
3202*29949e86Sstevel 		/*
3203*29949e86Sstevel 		 * handle state transition
3204*29949e86Sstevel 		 */
3205*29949e86Sstevel 		switch (list->key_shadow) {
3206*29949e86Sstevel 		case KEY_BOOT:
3207*29949e86Sstevel 			cmn_err(CE_CONT, "?sysctrl%d: Key switch is%sin the "
3208*29949e86Sstevel 			    "secure position\n", ddi_get_instance(list->dip),
3209*29949e86Sstevel 			    (key == KEY_SECURE) ? " " : " not ");
3210*29949e86Sstevel 			list->key_shadow = key;
3211*29949e86Sstevel 			break;
3212*29949e86Sstevel 		case KEY_SECURE:
3213*29949e86Sstevel 		case KEY_NOT_SECURE:
3214*29949e86Sstevel 			cmn_err(CE_NOTE, "sysctrl%d: Key switch has changed"
3215*29949e86Sstevel 			    " to the %s position",
3216*29949e86Sstevel 			    ddi_get_instance(list->dip),
3217*29949e86Sstevel 			    (key == KEY_SECURE) ? "secure" : "not-secure");
3218*29949e86Sstevel 			list->key_shadow = key;
3219*29949e86Sstevel 			break;
3220*29949e86Sstevel 		default:
3221*29949e86Sstevel 			cmn_err(CE_CONT,
3222*29949e86Sstevel 			    "?sysctrl%d: Key switch is in an unknown position,"
3223*29949e86Sstevel 			    "treated as being in the %s position\n",
3224*29949e86Sstevel 			    ddi_get_instance(list->dip),
3225*29949e86Sstevel 			    (list->key_shadow == KEY_SECURE) ?
3226*29949e86Sstevel 			    "secure" : "not-secure");
3227*29949e86Sstevel 			break;
3228*29949e86Sstevel 		}
3229*29949e86Sstevel 	}
3230*29949e86Sstevel }
3231*29949e86Sstevel 
3232*29949e86Sstevel /*
3233*29949e86Sstevel  * consider key switch position when handling an abort sequence
3234*29949e86Sstevel  */
3235*29949e86Sstevel static void
3236*29949e86Sstevel sysctrl_abort_seq_handler(char *msg)
3237*29949e86Sstevel {
3238*29949e86Sstevel 	struct sysctrl_soft_state *list;
3239*29949e86Sstevel 	uint_t secure = 0;
3240*29949e86Sstevel 	char buf[64], inst[4];
3241*29949e86Sstevel 
3242*29949e86Sstevel 
3243*29949e86Sstevel 	/*
3244*29949e86Sstevel 	 * if any of the key switch positions are secure,
3245*29949e86Sstevel 	 * then disallow entry to the prom/debugger
3246*29949e86Sstevel 	 */
3247*29949e86Sstevel 	mutex_enter(&sslist_mutex);
3248*29949e86Sstevel 	buf[0] = (char)0;
3249*29949e86Sstevel 	for (list = sys_list; list != NULL; list = list->next) {
3250*29949e86Sstevel 		if (!(*(list->status1) & SYS_NOT_SECURE)) {
3251*29949e86Sstevel 			if (secure++)
3252*29949e86Sstevel 				(void) strcat(buf, ",");
3253*29949e86Sstevel 			/*
3254*29949e86Sstevel 			 * XXX: later, replace instance number with nodeid
3255*29949e86Sstevel 			 */
3256*29949e86Sstevel 			(void) sprintf(inst, "%d", ddi_get_instance(list->dip));
3257*29949e86Sstevel 			(void) strcat(buf, inst);
3258*29949e86Sstevel 		}
3259*29949e86Sstevel 	}
3260*29949e86Sstevel 	mutex_exit(&sslist_mutex);
3261*29949e86Sstevel 
3262*29949e86Sstevel 	if (secure) {
3263*29949e86Sstevel 		cmn_err(CE_CONT,
3264*29949e86Sstevel 			"!sysctrl(%s): ignoring debug enter sequence\n", buf);
3265*29949e86Sstevel 	} else {
3266*29949e86Sstevel 		cmn_err(CE_CONT, "!sysctrl: allowing debug enter\n");
3267*29949e86Sstevel 		debug_enter(msg);
3268*29949e86Sstevel 	}
3269*29949e86Sstevel }
3270*29949e86Sstevel 
3271*29949e86Sstevel #define	TABLE_END	0xFF
3272*29949e86Sstevel 
3273*29949e86Sstevel struct uart_cmd {
3274*29949e86Sstevel 	uchar_t reg;
3275*29949e86Sstevel 	uchar_t data;
3276*29949e86Sstevel };
3277*29949e86Sstevel 
3278*29949e86Sstevel /*
3279*29949e86Sstevel  * Time constant defined by this formula:
3280*29949e86Sstevel  *	((4915200/32)/(baud) -2)
3281*29949e86Sstevel  */
3282*29949e86Sstevel 
3283*29949e86Sstevel struct uart_cmd uart_table[] = {
3284*29949e86Sstevel 	{ 0x09, 0xc0 },	/* Force hardware reset */
3285*29949e86Sstevel 	{ 0x04, 0x46 },	/* X16 clock mode, 1 stop bit/char, no parity */
3286*29949e86Sstevel 	{ 0x03, 0xc0 },	/* Rx is 8 bits/char */
3287*29949e86Sstevel 	{ 0x05, 0xe2 },	/* DTR, Tx is 8 bits/char, RTS */
3288*29949e86Sstevel 	{ 0x09, 0x02 },	/* No vector returned on interrupt */
3289*29949e86Sstevel 	{ 0x0b, 0x55 },	/* Rx Clock = Tx Clock = BR generator = ~TRxC OUT */
3290*29949e86Sstevel 	{ 0x0c, 0x0e },	/* Time Constant = 0x000e for 9600 baud */
3291*29949e86Sstevel 	{ 0x0d, 0x00 },	/* High byte of time constant */
3292*29949e86Sstevel 	{ 0x0e, 0x02 },	/* BR generator comes from Z-SCC's PCLK input */
3293*29949e86Sstevel 	{ 0x03, 0xc1 },	/* Rx is 8 bits/char, Rx is enabled */
3294*29949e86Sstevel 	{ 0x05, 0xea },	/* DTR, Tx is 8 bits/char, Tx is enabled, RTS */
3295*29949e86Sstevel 	{ 0x0e, 0x03 },	/* BR comes from PCLK, BR generator is enabled */
3296*29949e86Sstevel 	{ 0x00, 0x30 },	/* Error reset */
3297*29949e86Sstevel 	{ 0x00, 0x30 },	/* Error reset */
3298*29949e86Sstevel 	{ 0x00, 0x10 },	/* external status reset */
3299*29949e86Sstevel 	{ 0x03, 0xc1 },	/* Rx is 8 bits/char, Rx is enabled */
3300*29949e86Sstevel 	{ TABLE_END, 0x0 }
3301*29949e86Sstevel };
3302*29949e86Sstevel 
3303*29949e86Sstevel static void
3304*29949e86Sstevel init_remote_console_uart(struct sysctrl_soft_state *softsp)
3305*29949e86Sstevel {
3306*29949e86Sstevel 	int i = 0;
3307*29949e86Sstevel 
3308*29949e86Sstevel 	/*
3309*29949e86Sstevel 	 * Serial chip expects software to write to the control
3310*29949e86Sstevel 	 * register first with the desired register number. Then
3311*29949e86Sstevel 	 * write to the control register with the desired data.
3312*29949e86Sstevel 	 * So walk thru table writing the register/data pairs to
3313*29949e86Sstevel 	 * the serial port chip.
3314*29949e86Sstevel 	 */
3315*29949e86Sstevel 	while (uart_table[i].reg != TABLE_END) {
3316*29949e86Sstevel 		*(softsp->rcons_ctl) = uart_table[i].reg;
3317*29949e86Sstevel 		*(softsp->rcons_ctl) = uart_table[i].data;
3318*29949e86Sstevel 		i++;
3319*29949e86Sstevel 	}
3320*29949e86Sstevel }
3321*29949e86Sstevel 
3322*29949e86Sstevel /*
3323*29949e86Sstevel  * return the slot information of the system
3324*29949e86Sstevel  *
3325*29949e86Sstevel  * function take a sysctrl_soft_state, so it's ready for sunfire+
3326*29949e86Sstevel  * change which requires 2 registers to decide the system type.
3327*29949e86Sstevel  */
3328*29949e86Sstevel static void
3329*29949e86Sstevel sysc_slot_info(int nslots, int *start, int *limit, int *incr)
3330*29949e86Sstevel {
3331*29949e86Sstevel 	switch (nslots) {
3332*29949e86Sstevel 	case 8:
3333*29949e86Sstevel 		*start = 0;
3334*29949e86Sstevel 		*limit = 8;
3335*29949e86Sstevel 		*incr = 1;
3336*29949e86Sstevel 		break;
3337*29949e86Sstevel 	case 5:
3338*29949e86Sstevel 		*start = 1;
3339*29949e86Sstevel 		*limit = 10;
3340*29949e86Sstevel 		*incr = 2;
3341*29949e86Sstevel 		break;
3342*29949e86Sstevel 	case 4:
3343*29949e86Sstevel 		*start = 1;
3344*29949e86Sstevel 		*limit = 8;
3345*29949e86Sstevel 		*incr = 2;
3346*29949e86Sstevel 		break;
3347*29949e86Sstevel 	case 0:
3348*29949e86Sstevel 	case 16:
3349*29949e86Sstevel 	default:
3350*29949e86Sstevel 		*start = 0;
3351*29949e86Sstevel 		*limit = 16;
3352*29949e86Sstevel 		*incr = 1;
3353*29949e86Sstevel 		break;
3354*29949e86Sstevel 	}
3355*29949e86Sstevel }
3356*29949e86Sstevel 
3357*29949e86Sstevel /*
3358*29949e86Sstevel  * reinitialize the Remote Console on the clock board
3359*29949e86Sstevel  *
3360*29949e86Sstevel  * with V5_AUX power outage the Remote Console ends up in
3361*29949e86Sstevel  * unknown state and has to be reinitilized if it was enabled
3362*29949e86Sstevel  * initially.
3363*29949e86Sstevel  */
3364*29949e86Sstevel static void
3365*29949e86Sstevel rcons_reinit(struct sysctrl_soft_state *softsp)
3366*29949e86Sstevel {
3367*29949e86Sstevel 	uchar_t tmp_reg;
3368*29949e86Sstevel 
3369*29949e86Sstevel 	if (!(softsp->rcons_ctl))
3370*29949e86Sstevel 		/*
3371*29949e86Sstevel 		 * There is no OBP register set for the remote console UART,
3372*29949e86Sstevel 		 * so offset from the last register set, the misc register
3373*29949e86Sstevel 		 * set, in order to map in the remote console UART.
3374*29949e86Sstevel 		 */
3375*29949e86Sstevel 		if (ddi_map_regs(softsp->dip, 1, (caddr_t *)&softsp->rcons_ctl,
3376*29949e86Sstevel 		    RMT_CONS_OFFSET, RMT_CONS_LEN)) {
3377*29949e86Sstevel 			cmn_err(CE_WARN, "Unable to reinitialize "
3378*29949e86Sstevel 				"remote console.");
3379*29949e86Sstevel 			return;
3380*29949e86Sstevel 		}
3381*29949e86Sstevel 
3382*29949e86Sstevel 
3383*29949e86Sstevel 	/* Disable the remote console reset control bits. */
3384*29949e86Sstevel 	*(softsp->clk_freq2) &= ~RCONS_UART_EN;
3385*29949e86Sstevel 
3386*29949e86Sstevel 	/* flush the hardware buffers */
3387*29949e86Sstevel 	tmp_reg = *(softsp->csr);
3388*29949e86Sstevel 
3389*29949e86Sstevel 	/*
3390*29949e86Sstevel 	 * Program the UART to watch ttya console.
3391*29949e86Sstevel 	 */
3392*29949e86Sstevel 	init_remote_console_uart(softsp);
3393*29949e86Sstevel 
3394*29949e86Sstevel 	/* Now enable the remote console reset control bits. */
3395*29949e86Sstevel 	*(softsp->clk_freq2) |= RCONS_UART_EN;
3396*29949e86Sstevel 
3397*29949e86Sstevel 	/* flush the hardware buffers */
3398*29949e86Sstevel 	tmp_reg = *(softsp->csr);
3399*29949e86Sstevel 
3400*29949e86Sstevel 	/* print some info for user to watch */
3401*29949e86Sstevel 	cmn_err(CE_NOTE, "Remote console reinitialized");
3402*29949e86Sstevel #ifdef lint
3403*29949e86Sstevel 	tmp_reg = tmp_reg;
3404*29949e86Sstevel #endif
3405*29949e86Sstevel }
3406