xref: /titanic_51/usr/src/uts/sun4u/sunfire/io/sysctrl.c (revision 89b43686db1fe9681d80a7cf5662730cb9378cae)
129949e86Sstevel /*
229949e86Sstevel  * CDDL HEADER START
329949e86Sstevel  *
429949e86Sstevel  * The contents of this file are subject to the terms of the
529949e86Sstevel  * Common Development and Distribution License (the "License").
629949e86Sstevel  * You may not use this file except in compliance with the License.
729949e86Sstevel  *
829949e86Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
929949e86Sstevel  * or http://www.opensolaris.org/os/licensing.
1029949e86Sstevel  * See the License for the specific language governing permissions
1129949e86Sstevel  * and limitations under the License.
1229949e86Sstevel  *
1329949e86Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1429949e86Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1529949e86Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1629949e86Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1729949e86Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1829949e86Sstevel  *
1929949e86Sstevel  * CDDL HEADER END
2029949e86Sstevel  */
2129949e86Sstevel 
2229949e86Sstevel /*
2307d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2429949e86Sstevel  * Use is subject to license terms.
25*89b43686SBayard Bell  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
2629949e86Sstevel  */
2729949e86Sstevel 
2829949e86Sstevel 
2929949e86Sstevel #include <sys/types.h>
3029949e86Sstevel #include <sys/conf.h>
3129949e86Sstevel #include <sys/ddi.h>
3229949e86Sstevel #include <sys/sunddi.h>
3329949e86Sstevel #include <sys/ddi_impldefs.h>
3429949e86Sstevel #include <sys/sunndi.h>
3529949e86Sstevel #include <sys/ndi_impldefs.h>
3629949e86Sstevel #include <sys/obpdefs.h>
3729949e86Sstevel #include <sys/cmn_err.h>
3829949e86Sstevel #include <sys/errno.h>
3929949e86Sstevel #include <sys/kmem.h>
4029949e86Sstevel #include <sys/debug.h>
4129949e86Sstevel #include <sys/sysmacros.h>
4229949e86Sstevel #include <sys/ivintr.h>
4329949e86Sstevel #include <sys/autoconf.h>
4429949e86Sstevel #include <sys/intreg.h>
4529949e86Sstevel #include <sys/proc.h>
4629949e86Sstevel #include <sys/modctl.h>
4729949e86Sstevel #include <sys/callb.h>
4829949e86Sstevel #include <sys/file.h>
4929949e86Sstevel #include <sys/open.h>
5029949e86Sstevel #include <sys/stat.h>
5129949e86Sstevel #include <sys/fhc.h>
5229949e86Sstevel #include <sys/sysctrl.h>
5329949e86Sstevel #include <sys/jtag.h>
5429949e86Sstevel #include <sys/ac.h>
5529949e86Sstevel #include <sys/simmstat.h>
5629949e86Sstevel #include <sys/clock.h>
5729949e86Sstevel #include <sys/promif.h>
5829949e86Sstevel #include <sys/promimpl.h>
5929949e86Sstevel #include <sys/sunndi.h>
6029949e86Sstevel #include <sys/machsystm.h>
6129949e86Sstevel 
6229949e86Sstevel /* Useful debugging Stuff */
6329949e86Sstevel #ifdef DEBUG
6429949e86Sstevel int sysc_debug_info = 1;
6529949e86Sstevel int sysc_debug_print_level = 0;
6629949e86Sstevel #endif
6729949e86Sstevel 
6829949e86Sstevel /*
6929949e86Sstevel  * Function prototypes
7029949e86Sstevel  */
7129949e86Sstevel static int sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
7229949e86Sstevel 		void **result);
7329949e86Sstevel 
7429949e86Sstevel static int sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
7529949e86Sstevel 
7629949e86Sstevel static int sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
7729949e86Sstevel 
7829949e86Sstevel static int sysctrl_open(dev_t *, int, int, cred_t *);
7929949e86Sstevel 
8029949e86Sstevel static int sysctrl_close(dev_t, int, int, cred_t *);
8129949e86Sstevel 
8229949e86Sstevel static int sysctrl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
8329949e86Sstevel 
8429949e86Sstevel static uint_t system_high_handler(caddr_t arg);
8529949e86Sstevel 
8629949e86Sstevel static uint_t spur_delay(caddr_t arg);
8729949e86Sstevel 
8829949e86Sstevel static void spur_retry(void *);
8929949e86Sstevel 
9029949e86Sstevel static uint_t spur_reenable(caddr_t arg);
9129949e86Sstevel 
9229949e86Sstevel static void spur_long_timeout(void *);
9329949e86Sstevel 
9429949e86Sstevel static uint_t spur_clear_count(caddr_t arg);
9529949e86Sstevel 
9629949e86Sstevel static uint_t ac_fail_handler(caddr_t arg);
9729949e86Sstevel 
9829949e86Sstevel static void ac_fail_retry(void *);
9929949e86Sstevel 
10029949e86Sstevel static uint_t ac_fail_reenable(caddr_t arg);
10129949e86Sstevel 
10229949e86Sstevel static uint_t ps_fail_int_handler(caddr_t arg);
10329949e86Sstevel 
10429949e86Sstevel static uint_t ps_fail_poll_handler(caddr_t arg);
10529949e86Sstevel 
10629949e86Sstevel static uint_t ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint);
10729949e86Sstevel 
10829949e86Sstevel enum power_state compute_power_state(struct sysctrl_soft_state *softsp,
10929949e86Sstevel 					int plus_load);
11029949e86Sstevel 
11129949e86Sstevel static void ps_log_state_change(struct sysctrl_soft_state *softsp,
11229949e86Sstevel 					int index, int present);
11329949e86Sstevel 
11429949e86Sstevel static void ps_log_pres_change(struct sysctrl_soft_state *softsp,
11529949e86Sstevel 					int index, int present);
11629949e86Sstevel 
11729949e86Sstevel static void ps_fail_retry(void *);
11829949e86Sstevel 
11929949e86Sstevel static uint_t pps_fanfail_handler(caddr_t arg);
12029949e86Sstevel 
12129949e86Sstevel static void pps_fanfail_retry(void *);
12229949e86Sstevel 
12329949e86Sstevel static uint_t pps_fanfail_reenable(caddr_t arg);
12429949e86Sstevel 
12529949e86Sstevel static void pps_fan_poll(void *);
12629949e86Sstevel 
12729949e86Sstevel static void pps_fan_state_change(struct sysctrl_soft_state *softsp,
12829949e86Sstevel 					int index, int fan_ok);
12929949e86Sstevel 
13029949e86Sstevel static uint_t bd_insert_handler(caddr_t arg);
13129949e86Sstevel 
13229949e86Sstevel static void bd_insert_timeout(void *);
13329949e86Sstevel 
13429949e86Sstevel static void bd_remove_timeout(void *);
13529949e86Sstevel 
13629949e86Sstevel static uint_t bd_insert_normal(caddr_t arg);
13729949e86Sstevel 
13829949e86Sstevel static void sysctrl_add_kstats(struct sysctrl_soft_state *softsp);
13929949e86Sstevel 
14029949e86Sstevel static int sysctrl_kstat_update(kstat_t *ksp, int rw);
14129949e86Sstevel 
14229949e86Sstevel static int psstat_kstat_update(kstat_t *, int);
14329949e86Sstevel 
14429949e86Sstevel static void init_remote_console_uart(struct sysctrl_soft_state *);
14529949e86Sstevel 
14629949e86Sstevel static void blink_led_timeout(void *);
14729949e86Sstevel 
14829949e86Sstevel static uint_t blink_led_handler(caddr_t arg);
14929949e86Sstevel 
15029949e86Sstevel static void sysctrl_thread_wakeup(void *type);
15129949e86Sstevel 
15229949e86Sstevel static void sysctrl_overtemp_poll(void);
15329949e86Sstevel 
15429949e86Sstevel static void sysctrl_keyswitch_poll(void);
15529949e86Sstevel 
15629949e86Sstevel static void update_key_state(struct sysctrl_soft_state *);
15729949e86Sstevel 
15829949e86Sstevel static void sysctrl_abort_seq_handler(char *msg);
15929949e86Sstevel 
16029949e86Sstevel static void nvram_update_powerfail(struct sysctrl_soft_state *softsp);
16129949e86Sstevel 
16229949e86Sstevel static void toggle_board_green_leds(int);
16329949e86Sstevel 
16429949e86Sstevel void bd_remove_poll(struct sysctrl_soft_state *);
16529949e86Sstevel 
16629949e86Sstevel static void sysc_slot_info(int nslots, int *start, int *limit, int *incr);
16729949e86Sstevel 
16829949e86Sstevel extern void sysc_board_connect_supported_init(void);
16929949e86Sstevel 
17029949e86Sstevel static void rcons_reinit(struct sysctrl_soft_state *softsp);
17129949e86Sstevel 
17229949e86Sstevel /*
17329949e86Sstevel  * Configuration data structures
17429949e86Sstevel  */
17529949e86Sstevel static struct cb_ops sysctrl_cb_ops = {
17629949e86Sstevel 	sysctrl_open,		/* open */
17729949e86Sstevel 	sysctrl_close,		/* close */
17829949e86Sstevel 	nulldev,		/* strategy */
17929949e86Sstevel 	nulldev,		/* print */
18029949e86Sstevel 	nulldev,		/* dump */
18129949e86Sstevel 	nulldev,		/* read */
18229949e86Sstevel 	nulldev,		/* write */
18329949e86Sstevel 	sysctrl_ioctl,		/* ioctl */
18429949e86Sstevel 	nodev,			/* devmap */
18529949e86Sstevel 	nodev,			/* mmap */
18629949e86Sstevel 	nodev,			/* segmap */
18729949e86Sstevel 	nochpoll,		/* poll */
18829949e86Sstevel 	ddi_prop_op,		/* cb_prop_op */
18929949e86Sstevel 	0,			/* streamtab */
19029949e86Sstevel 	D_MP|D_NEW,		/* Driver compatibility flag */
19129949e86Sstevel 	CB_REV,			/* rev */
19229949e86Sstevel 	nodev,			/* cb_aread */
19329949e86Sstevel 	nodev			/* cb_awrite */
19429949e86Sstevel };
19529949e86Sstevel 
19629949e86Sstevel static struct dev_ops sysctrl_ops = {
19729949e86Sstevel 	DEVO_REV,		/* devo_rev */
19829949e86Sstevel 	0,			/* refcnt */
19929949e86Sstevel 	sysctrl_info,		/* getinfo */
20029949e86Sstevel 	nulldev,		/* identify */
20129949e86Sstevel 	nulldev,		/* probe */
20229949e86Sstevel 	sysctrl_attach,		/* attach */
20329949e86Sstevel 	sysctrl_detach,		/* detach */
20429949e86Sstevel 	nulldev,		/* reset */
20529949e86Sstevel 	&sysctrl_cb_ops,	/* cb_ops */
20629949e86Sstevel 	(struct bus_ops *)0,	/* bus_ops */
20719397407SSherry Moore 	nulldev,		/* power */
20819397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
20929949e86Sstevel };
21029949e86Sstevel 
21129949e86Sstevel void *sysctrlp;				/* sysctrl soft state hook */
21229949e86Sstevel 
21329949e86Sstevel /* # of ticks to silence spurious interrupts */
21429949e86Sstevel static clock_t spur_timeout_hz;
21529949e86Sstevel 
21629949e86Sstevel /* # of ticks to count spurious interrupts to print message */
21729949e86Sstevel static clock_t spur_long_timeout_hz;
21829949e86Sstevel 
21929949e86Sstevel /* # of ticks between AC failure polling */
22029949e86Sstevel static clock_t ac_timeout_hz;
22129949e86Sstevel 
22229949e86Sstevel /* # of ticks between Power Supply Failure polling */
22329949e86Sstevel static clock_t ps_fail_timeout_hz;
22429949e86Sstevel 
22529949e86Sstevel /*
22629949e86Sstevel  * # of ticks between Peripheral Power Supply failure polling
22729949e86Sstevel  * (used both for interrupt retry timeout and polling function)
22829949e86Sstevel  */
22929949e86Sstevel static clock_t pps_fan_timeout_hz;
23029949e86Sstevel 
23129949e86Sstevel /* # of ticks delay after board insert interrupt */
23229949e86Sstevel static clock_t bd_insert_delay_hz;
23329949e86Sstevel 
23429949e86Sstevel /* # of secs to wait before restarting poll if we cannot clear interrupts */
23529949e86Sstevel static clock_t bd_insert_retry_hz;
23629949e86Sstevel 
23729949e86Sstevel /* # of secs between Board Removal polling */
23829949e86Sstevel static clock_t bd_remove_timeout_hz;
23929949e86Sstevel 
24029949e86Sstevel /* # of secs between toggle of OS LED */
24129949e86Sstevel static clock_t blink_led_timeout_hz;
24229949e86Sstevel 
24329949e86Sstevel /* overtemp polling routine timeout delay */
24429949e86Sstevel static clock_t overtemp_timeout_hz;
24529949e86Sstevel 
24629949e86Sstevel /* key switch polling routine timeout delay */
24729949e86Sstevel static clock_t keyswitch_timeout_hz;
24829949e86Sstevel 
24929949e86Sstevel /* Specify which system interrupt condition to monitor */
25029949e86Sstevel int enable_sys_interrupt = SYS_AC_PWR_FAIL_EN | SYS_PPS_FAN_FAIL_EN |
25129949e86Sstevel 			SYS_PS_FAIL_EN | SYS_SBRD_PRES_EN;
25229949e86Sstevel 
25329949e86Sstevel /* Should the overtemp_poll thread be running? */
25429949e86Sstevel static int sysctrl_do_overtemp_thread = 1;
25529949e86Sstevel 
25629949e86Sstevel /* Should the keyswitch_poll thread be running? */
25729949e86Sstevel static int sysctrl_do_keyswitch_thread = 1;
25829949e86Sstevel 
25929949e86Sstevel /*
26029949e86Sstevel  * This timeout ID is for board remove polling routine. It is
26129949e86Sstevel  * protected by the fhc_bdlist mutex.
26229949e86Sstevel  * XXX - This will not work for wildfire. A different scheme must be
26329949e86Sstevel  * used since there will be multiple sysctrl nodes, each with its
26429949e86Sstevel  * own list of hotplugged boards to scan.
26529949e86Sstevel  */
26629949e86Sstevel static timeout_id_t bd_remove_to_id = 0;
26729949e86Sstevel 
26829949e86Sstevel /*
26929949e86Sstevel  * If this is set, the system will not shutdown when insufficient power
27029949e86Sstevel  * condition persists.
27129949e86Sstevel  */
27229949e86Sstevel int disable_insufficient_power_reboot = 0;
27329949e86Sstevel 
27429949e86Sstevel /*
27529949e86Sstevel  * Set this to enable suspend/resume
27629949e86Sstevel  */
27729949e86Sstevel int sysctrl_enable_detach_suspend = 0;
27829949e86Sstevel 
27929949e86Sstevel /*
28029949e86Sstevel  * Set this to reflect the OBP initialized HOTPLUG_DISABLED_PROPERTY and
28129949e86Sstevel  * during dynamic detection
28229949e86Sstevel  */
28329949e86Sstevel int sysctrl_hotplug_disabled = FALSE;
28429949e86Sstevel 
28529949e86Sstevel /* Indicates whether or not the overtemp thread has been started */
28629949e86Sstevel static int sysctrl_overtemp_thread_started = 0;
28729949e86Sstevel 
28829949e86Sstevel /* Indicates whether or not the key switch thread has been started */
28929949e86Sstevel static int sysctrl_keyswitch_thread_started = 0;
29029949e86Sstevel 
29129949e86Sstevel /* *Mutex used to protect the soft state list */
29229949e86Sstevel static kmutex_t sslist_mutex;
29329949e86Sstevel 
29429949e86Sstevel /* The CV is used to wakeup the overtemp thread when needed. */
29529949e86Sstevel static kcondvar_t overtemp_cv;
29629949e86Sstevel 
29729949e86Sstevel /* The CV is used to wakeup the key switch thread when needed. */
29829949e86Sstevel static kcondvar_t keyswitch_cv;
29929949e86Sstevel 
30029949e86Sstevel /* This mutex is used to protect the sysctrl_ddi_branch_init variable */
30129949e86Sstevel static kmutex_t sysctrl_branch_mutex;
30229949e86Sstevel 
30329949e86Sstevel /*
30429949e86Sstevel  * This variable is set after all existing branches in the system have
30529949e86Sstevel  * been discovered and held via e_ddi_branch_hold(). This happens on
30629949e86Sstevel  * first open() of any sysctrl minor node.
30729949e86Sstevel  */
30829949e86Sstevel static int sysctrl_ddi_branch_init;
30929949e86Sstevel 
31029949e86Sstevel /*
31129949e86Sstevel  * Linked list of all syctrl soft state structures.
31229949e86Sstevel  * Used for polling sysctrl state changes, i.e. temperature.
31329949e86Sstevel  */
31429949e86Sstevel struct sysctrl_soft_state *sys_list = NULL;
31529949e86Sstevel 
31629949e86Sstevel extern struct mod_ops mod_driverops;
31729949e86Sstevel 
31829949e86Sstevel static struct modldrv modldrv = {
31929949e86Sstevel 	&mod_driverops,		/* Type of module.  This one is a driver */
32019397407SSherry Moore 	"Clock Board",		/* name of module */
32129949e86Sstevel 	&sysctrl_ops,		/* driver ops */
32229949e86Sstevel };
32329949e86Sstevel 
32429949e86Sstevel static struct modlinkage modlinkage = {
32529949e86Sstevel 	MODREV_1,		/* rev */
32629949e86Sstevel 	(void *)&modldrv,
32729949e86Sstevel 	NULL
32829949e86Sstevel };
32929949e86Sstevel 
33029949e86Sstevel /*
33129949e86Sstevel  * These are the module initialization routines.
33229949e86Sstevel  */
33329949e86Sstevel 
33429949e86Sstevel int
33529949e86Sstevel _init(void)
33629949e86Sstevel {
33729949e86Sstevel 	int error;
33829949e86Sstevel 
33929949e86Sstevel 	if ((error = ddi_soft_state_init(&sysctrlp,
34029949e86Sstevel 	    sizeof (struct sysctrl_soft_state), 1)) != 0)
34129949e86Sstevel 		return (error);
34229949e86Sstevel 
34329949e86Sstevel 	error = mod_install(&modlinkage);
34429949e86Sstevel 	if (error != 0) {
34529949e86Sstevel 		ddi_soft_state_fini(&sysctrlp);
34629949e86Sstevel 		return (error);
34729949e86Sstevel 	}
34829949e86Sstevel 
34929949e86Sstevel 	mutex_init(&sysctrl_branch_mutex, NULL, MUTEX_DRIVER, NULL);
35029949e86Sstevel 
35129949e86Sstevel 	return (0);
35229949e86Sstevel }
35329949e86Sstevel 
35429949e86Sstevel int
35529949e86Sstevel _fini(void)
35629949e86Sstevel {
35729949e86Sstevel 	int error;
35829949e86Sstevel 
35929949e86Sstevel 	if ((error = mod_remove(&modlinkage)) != 0)
36029949e86Sstevel 		return (error);
36129949e86Sstevel 
36229949e86Sstevel 	ddi_soft_state_fini(&sysctrlp);
36329949e86Sstevel 
36429949e86Sstevel 	mutex_destroy(&sysctrl_branch_mutex);
36529949e86Sstevel 
36629949e86Sstevel 	return (0);
36729949e86Sstevel }
36829949e86Sstevel 
36929949e86Sstevel int
37029949e86Sstevel _info(struct modinfo *modinfop)
37129949e86Sstevel {
37229949e86Sstevel 	return (mod_info(&modlinkage, modinfop));
37329949e86Sstevel }
37429949e86Sstevel 
37529949e86Sstevel /* ARGSUSED */
37629949e86Sstevel static int
37729949e86Sstevel sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
37829949e86Sstevel {
37929949e86Sstevel 	dev_t	dev;
38029949e86Sstevel 	int	instance;
38129949e86Sstevel 
38229949e86Sstevel 	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
38329949e86Sstevel 		dev = (dev_t)arg;
38429949e86Sstevel 		instance = GETINSTANCE(dev);
38529949e86Sstevel 		*result = (void *)(uintptr_t)instance;
38629949e86Sstevel 		return (DDI_SUCCESS);
38729949e86Sstevel 	}
38829949e86Sstevel 	return (DDI_FAILURE);
38929949e86Sstevel }
39029949e86Sstevel 
39129949e86Sstevel static int
39229949e86Sstevel sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
39329949e86Sstevel {
39429949e86Sstevel 	struct sysctrl_soft_state *softsp;
39529949e86Sstevel 	int instance;
39629949e86Sstevel 	uchar_t tmp_reg;
39729949e86Sstevel 	dev_info_t *dip;
39829949e86Sstevel 	char *propval;
39929949e86Sstevel 	int proplen;
40029949e86Sstevel 	int slot_num;
40129949e86Sstevel 	int start;		/* start index for scan loop */
40229949e86Sstevel 	int limit;		/* board number limit for scan loop */
40329949e86Sstevel 	int incr;		/* amount to incr each pass thru loop */
40429949e86Sstevel 	void set_clockbrd_info(void);
40529949e86Sstevel 
40629949e86Sstevel 
40729949e86Sstevel 	switch (cmd) {
40829949e86Sstevel 	case DDI_ATTACH:
40929949e86Sstevel 		break;
41029949e86Sstevel 
41129949e86Sstevel 	case DDI_RESUME:
41229949e86Sstevel 		/* XXX see sysctrl:DDI_SUSPEND for special h/w treatment */
41329949e86Sstevel 		return (DDI_SUCCESS);
41429949e86Sstevel 
41529949e86Sstevel 	default:
41629949e86Sstevel 		return (DDI_FAILURE);
41729949e86Sstevel 	}
41829949e86Sstevel 
41929949e86Sstevel 	instance = ddi_get_instance(devi);
42029949e86Sstevel 
42129949e86Sstevel 	if (ddi_soft_state_zalloc(sysctrlp, instance) != DDI_SUCCESS)
42229949e86Sstevel 		return (DDI_FAILURE);
42329949e86Sstevel 
42429949e86Sstevel 	softsp = GETSOFTC(instance);
42529949e86Sstevel 
42629949e86Sstevel 	/* Set the dip in the soft state */
42729949e86Sstevel 	softsp->dip = devi;
42829949e86Sstevel 
42929949e86Sstevel 	/* Set up the parent dip */
43029949e86Sstevel 	softsp->pdip = ddi_get_parent(softsp->dip);
43129949e86Sstevel 
43229949e86Sstevel 	DPRINTF(SYSCTRL_ATTACH_DEBUG, ("sysctrl: devi= 0x%p\n, softsp=0x%p\n",
43307d06da5SSurya Prakki 	    (void *)devi, (void *)softsp));
43429949e86Sstevel 
43529949e86Sstevel 	/* First set all of the timeout values */
43629949e86Sstevel 	spur_timeout_hz = drv_usectohz(SPUR_TIMEOUT_USEC);
43729949e86Sstevel 	spur_long_timeout_hz = drv_usectohz(SPUR_LONG_TIMEOUT_USEC);
43829949e86Sstevel 	ac_timeout_hz = drv_usectohz(AC_TIMEOUT_USEC);
43929949e86Sstevel 	ps_fail_timeout_hz = drv_usectohz(PS_FAIL_TIMEOUT_USEC);
44029949e86Sstevel 	pps_fan_timeout_hz = drv_usectohz(PPS_FAN_TIMEOUT_USEC);
44129949e86Sstevel 	bd_insert_delay_hz = drv_usectohz(BRD_INSERT_DELAY_USEC);
44229949e86Sstevel 	bd_insert_retry_hz = drv_usectohz(BRD_INSERT_RETRY_USEC);
44329949e86Sstevel 	bd_remove_timeout_hz = drv_usectohz(BRD_REMOVE_TIMEOUT_USEC);
44429949e86Sstevel 	blink_led_timeout_hz = drv_usectohz(BLINK_LED_TIMEOUT_USEC);
44529949e86Sstevel 	overtemp_timeout_hz = drv_usectohz(OVERTEMP_TIMEOUT_SEC * MICROSEC);
44629949e86Sstevel 	keyswitch_timeout_hz = drv_usectohz(KEYSWITCH_TIMEOUT_USEC);
44729949e86Sstevel 
44829949e86Sstevel 	/*
44929949e86Sstevel 	 * Map in the registers sets that OBP hands us. According
45029949e86Sstevel 	 * to the sun4u device tree spec., the register sets are as
45129949e86Sstevel 	 * follows:
45229949e86Sstevel 	 *
45329949e86Sstevel 	 *	0	Clock Frequency Registers (contains the bit
45429949e86Sstevel 	 *		for enabling the remote console reset)
45529949e86Sstevel 	 *	1	Misc (has all the registers that we need
45629949e86Sstevel 	 *	2	Clock Version Register
45729949e86Sstevel 	 */
45829949e86Sstevel 	if (ddi_map_regs(softsp->dip, 0,
45929949e86Sstevel 	    (caddr_t *)&softsp->clk_freq1, 0, 0)) {
46029949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: unable to map clock frequency "
46129949e86Sstevel 		    "registers", instance);
46229949e86Sstevel 		goto bad0;
46329949e86Sstevel 	}
46429949e86Sstevel 
46529949e86Sstevel 	if (ddi_map_regs(softsp->dip, 1,
46629949e86Sstevel 	    (caddr_t *)&softsp->csr, 0, 0)) {
46729949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: unable to map internal"
46829949e86Sstevel 		    "registers", instance);
46929949e86Sstevel 		goto bad1;
47029949e86Sstevel 	}
47129949e86Sstevel 
47229949e86Sstevel 	/*
47329949e86Sstevel 	 * There is a new register for newer vintage clock board nodes,
47429949e86Sstevel 	 * OBP register set 2 in the clock board node.
47529949e86Sstevel 	 *
47629949e86Sstevel 	 */
47729949e86Sstevel 	(void) ddi_map_regs(softsp->dip, 2, (caddr_t *)&softsp->clk_ver, 0, 0);
47829949e86Sstevel 
47929949e86Sstevel 	/*
48029949e86Sstevel 	 * Fill in the virtual addresses of the registers in the
48129949e86Sstevel 	 * sysctrl_soft_state structure. We do not want to calculate
48229949e86Sstevel 	 * them on the fly. This way we waste a little memory, but
48329949e86Sstevel 	 * avoid bugs down the road.
48429949e86Sstevel 	 */
48529949e86Sstevel 	softsp->clk_freq2 = (uchar_t *)((caddr_t)softsp->clk_freq1 +
48629949e86Sstevel 	    SYS_OFF_CLK_FREQ2);
48729949e86Sstevel 
48829949e86Sstevel 	softsp->status1 = (uchar_t *)((caddr_t)softsp->csr +
48929949e86Sstevel 	    SYS_OFF_STAT1);
49029949e86Sstevel 
49129949e86Sstevel 	softsp->status2 = (uchar_t *)((caddr_t)softsp->csr +
49229949e86Sstevel 	    SYS_OFF_STAT2);
49329949e86Sstevel 
49429949e86Sstevel 	softsp->ps_stat = (uchar_t *)((caddr_t)softsp->csr +
49529949e86Sstevel 	    SYS_OFF_PSSTAT);
49629949e86Sstevel 
49729949e86Sstevel 	softsp->ps_pres = (uchar_t *)((caddr_t)softsp->csr +
49829949e86Sstevel 	    SYS_OFF_PSPRES);
49929949e86Sstevel 
50029949e86Sstevel 	softsp->pppsr = (uchar_t *)((caddr_t)softsp->csr +
50129949e86Sstevel 	    SYS_OFF_PPPSR);
50229949e86Sstevel 
50329949e86Sstevel 	softsp->temp_reg = (uchar_t *)((caddr_t)softsp->csr +
50429949e86Sstevel 	    SYS_OFF_TEMP);
50529949e86Sstevel 
50629949e86Sstevel 	set_clockbrd_info();
50729949e86Sstevel 
50829949e86Sstevel 	/*
50929949e86Sstevel 	 * Enable the hardware watchdog gate on the clock board if
51029949e86Sstevel 	 * map_wellknown has detected that watchdog timer is available
51129949e86Sstevel 	 * and user wants it to be enabled.
51229949e86Sstevel 	 */
51329949e86Sstevel 	if (watchdog_available && watchdog_enable)
51429949e86Sstevel 		*(softsp->clk_freq2) |= TOD_RESET_EN;
51529949e86Sstevel 	else
51629949e86Sstevel 		*(softsp->clk_freq2) &= ~TOD_RESET_EN;
51729949e86Sstevel 
51829949e86Sstevel 	/* Check for inherited faults from the PROM. */
51929949e86Sstevel 	if (*softsp->csr & SYS_LED_MID) {
52029949e86Sstevel 		reg_fault(0, FT_PROM, FT_SYSTEM);
52129949e86Sstevel 	}
52229949e86Sstevel 
52329949e86Sstevel 	/*
52429949e86Sstevel 	 * calculate and cache the number of slots on this system
52529949e86Sstevel 	 */
52629949e86Sstevel 	switch (SYS_TYPE(*softsp->status1)) {
52729949e86Sstevel 	case SYS_16_SLOT:
52829949e86Sstevel 		softsp->nslots = 16;
52929949e86Sstevel 		break;
53029949e86Sstevel 
53129949e86Sstevel 	case SYS_8_SLOT:
53229949e86Sstevel 		softsp->nslots = 8;
53329949e86Sstevel 		break;
53429949e86Sstevel 
53529949e86Sstevel 	case SYS_4_SLOT:
53629949e86Sstevel 		/* check the clk_version register - if the ptr is valid */
53729949e86Sstevel 		if ((softsp->clk_ver != NULL) &&
53829949e86Sstevel 		    (SYS_TYPE2(*softsp->clk_ver) == SYS_PLUS_SYSTEM)) {
53929949e86Sstevel 			softsp->nslots = 5;
54029949e86Sstevel 		} else {
54129949e86Sstevel 			softsp->nslots = 4;
54229949e86Sstevel 		}
54329949e86Sstevel 		break;
54429949e86Sstevel 
54529949e86Sstevel 	case SYS_TESTBED:
54629949e86Sstevel 	default:
54729949e86Sstevel 		softsp->nslots = 0;
54829949e86Sstevel 		break;
54929949e86Sstevel 	}
55029949e86Sstevel 
55129949e86Sstevel 
55229949e86Sstevel 	/* create the fault list kstat */
55329949e86Sstevel 	create_ft_kstats(instance);
55429949e86Sstevel 
55529949e86Sstevel 	/*
55629949e86Sstevel 	 * Do a priming read on the ADC, and throw away the first value
55729949e86Sstevel 	 * read. This is a feature of the ADC hardware. After a power cycle
55829949e86Sstevel 	 * it does not contains valid data until a read occurs.
55929949e86Sstevel 	 */
56029949e86Sstevel 	tmp_reg = *(softsp->temp_reg);
56129949e86Sstevel 
56229949e86Sstevel 	/* Wait 30 usec for ADC hardware to stabilize. */
56329949e86Sstevel 	DELAY(30);
56429949e86Sstevel 
56529949e86Sstevel 	/* shut off all interrupt sources */
56629949e86Sstevel 	*(softsp->csr) &= ~(SYS_PPS_FAN_FAIL_EN | SYS_PS_FAIL_EN |
56729949e86Sstevel 	    SYS_AC_PWR_FAIL_EN | SYS_SBRD_PRES_EN);
56829949e86Sstevel 	tmp_reg = *(softsp->csr);
56929949e86Sstevel #ifdef lint
57029949e86Sstevel 	tmp_reg = tmp_reg;
57129949e86Sstevel #endif
57229949e86Sstevel 
57329949e86Sstevel 	/*
57429949e86Sstevel 	 * Now register our high interrupt with the system.
57529949e86Sstevel 	 */
57629949e86Sstevel 	if (ddi_add_intr(devi, 0, &softsp->iblock,
57729949e86Sstevel 	    &softsp->idevice, (uint_t (*)(caddr_t))nulldev, NULL) !=
57829949e86Sstevel 	    DDI_SUCCESS)
57929949e86Sstevel 		goto bad2;
58029949e86Sstevel 
58129949e86Sstevel 	mutex_init(&softsp->csr_mutex, NULL, MUTEX_DRIVER,
58229949e86Sstevel 	    (void *)softsp->iblock);
58329949e86Sstevel 
58429949e86Sstevel 	ddi_remove_intr(devi, 0, softsp->iblock);
58529949e86Sstevel 
58629949e86Sstevel 	if (ddi_add_intr(devi, 0, &softsp->iblock,
58729949e86Sstevel 	    &softsp->idevice, system_high_handler, (caddr_t)softsp) !=
58829949e86Sstevel 	    DDI_SUCCESS)
58929949e86Sstevel 		goto bad3;
59029949e86Sstevel 
59129949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_id,
59229949e86Sstevel 	    &softsp->spur_int_c, NULL, spur_delay, (caddr_t)softsp) !=
59329949e86Sstevel 	    DDI_SUCCESS)
59429949e86Sstevel 		goto bad4;
59529949e86Sstevel 
59629949e86Sstevel 	mutex_init(&softsp->spur_int_lock, NULL, MUTEX_DRIVER,
59729949e86Sstevel 	    (void *)softsp->spur_int_c);
59829949e86Sstevel 
59929949e86Sstevel 
60029949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_high_id,
60129949e86Sstevel 	    NULL, NULL, spur_reenable, (caddr_t)softsp) != DDI_SUCCESS)
60229949e86Sstevel 		goto bad5;
60329949e86Sstevel 
60429949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_long_to_id,
60529949e86Sstevel 	    NULL, NULL, spur_clear_count, (caddr_t)softsp) != DDI_SUCCESS)
60629949e86Sstevel 		goto bad6;
60729949e86Sstevel 
60829949e86Sstevel 	/*
60929949e86Sstevel 	 * Now register low-level ac fail handler
61029949e86Sstevel 	 */
61129949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ac_fail_id,
61229949e86Sstevel 	    NULL, NULL, ac_fail_handler, (caddr_t)softsp) != DDI_SUCCESS)
61329949e86Sstevel 		goto bad7;
61429949e86Sstevel 
61529949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ac_fail_high_id,
61629949e86Sstevel 	    NULL, NULL, ac_fail_reenable, (caddr_t)softsp) != DDI_SUCCESS)
61729949e86Sstevel 		goto bad8;
61829949e86Sstevel 
61929949e86Sstevel 	/*
62029949e86Sstevel 	 * Now register low-level ps fail handler
62129949e86Sstevel 	 */
62229949e86Sstevel 
62329949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ps_fail_int_id,
62429949e86Sstevel 	    &softsp->ps_fail_c, NULL, ps_fail_int_handler, (caddr_t)softsp) !=
62529949e86Sstevel 	    DDI_SUCCESS)
62629949e86Sstevel 		goto bad9;
62729949e86Sstevel 
62829949e86Sstevel 	mutex_init(&softsp->ps_fail_lock, NULL, MUTEX_DRIVER,
62929949e86Sstevel 	    (void *)softsp->ps_fail_c);
63029949e86Sstevel 
63129949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ps_fail_poll_id,
63229949e86Sstevel 	    NULL, NULL, ps_fail_poll_handler, (caddr_t)softsp) !=
63329949e86Sstevel 	    DDI_SUCCESS)
63429949e86Sstevel 		goto bad10;
63529949e86Sstevel 
63629949e86Sstevel 	/*
63729949e86Sstevel 	 * Now register low-level pps fan fail handler
63829949e86Sstevel 	 */
63929949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_id,
64029949e86Sstevel 	    NULL, NULL, pps_fanfail_handler, (caddr_t)softsp) !=
64129949e86Sstevel 	    DDI_SUCCESS)
64229949e86Sstevel 		goto bad11;
64329949e86Sstevel 
64429949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_high_id,
64529949e86Sstevel 	    NULL, NULL, pps_fanfail_reenable, (caddr_t)softsp) !=
64629949e86Sstevel 	    DDI_SUCCESS)
64729949e86Sstevel 		goto bad12;
64829949e86Sstevel 
64929949e86Sstevel 	/*
65029949e86Sstevel 	 * Based upon a check for a current share backplane, advise
65129949e86Sstevel 	 * that system does not support hot plug
65229949e86Sstevel 	 *
65329949e86Sstevel 	 */
65429949e86Sstevel 	if ((*(softsp->pppsr) & SYS_NOT_CURRENT_S) != 0) {
65529949e86Sstevel 		cmn_err(CE_NOTE, "Hot Plug not supported in this system");
65629949e86Sstevel 		sysctrl_hotplug_disabled = TRUE;
65729949e86Sstevel 	}
65829949e86Sstevel 
65929949e86Sstevel 	/*
66029949e86Sstevel 	 * If the trigger circuit is busted or the NOT_BRD_PRES line
66129949e86Sstevel 	 * is stuck then OBP will publish this property stating that
66229949e86Sstevel 	 * hot plug is not available.  If this happens we will complain
66329949e86Sstevel 	 * to the console and register a system fault.  We will also
66429949e86Sstevel 	 * not enable the board insert interrupt for this session.
66529949e86Sstevel 	 */
66629949e86Sstevel 	if (ddi_prop_op(DDI_DEV_T_ANY, softsp->dip, PROP_LEN_AND_VAL_ALLOC,
66729949e86Sstevel 	    DDI_PROP_DONTPASS, HOTPLUG_DISABLED_PROPERTY,
66829949e86Sstevel 	    (caddr_t)&propval, &proplen) == DDI_PROP_SUCCESS) {
66929949e86Sstevel 		cmn_err(CE_WARN, "Hot Plug Unavailable [%s]", propval);
67029949e86Sstevel 		reg_fault(0, FT_HOT_PLUG, FT_SYSTEM);
67129949e86Sstevel 		sysctrl_hotplug_disabled = TRUE;
67229949e86Sstevel 		enable_sys_interrupt &= ~SYS_SBRD_PRES_EN;
67329949e86Sstevel 		kmem_free(propval, proplen);
67429949e86Sstevel 	}
67529949e86Sstevel 
67629949e86Sstevel 	sysc_board_connect_supported_init();
67729949e86Sstevel 
67829949e86Sstevel 	fhc_bd_sc_register(sysc_policy_update, softsp);
67929949e86Sstevel 
68029949e86Sstevel 	sysc_slot_info(softsp->nslots, &start, &limit, &incr);
68129949e86Sstevel 
68229949e86Sstevel 	/* Prime the board list. */
68329949e86Sstevel 	fhc_bdlist_prime(start, limit, incr);
68429949e86Sstevel 
68529949e86Sstevel 	/*
68629949e86Sstevel 	 * Set up a board remove timeout call.
68729949e86Sstevel 	 */
68829949e86Sstevel 	(void) fhc_bdlist_lock(-1);
68929949e86Sstevel 
69029949e86Sstevel 	DPRINTF(SYSCTRL_ATTACH_DEBUG,
69129949e86Sstevel 	    ("attach: start bd_remove_poll()..."));
69229949e86Sstevel 
69329949e86Sstevel 	bd_remove_poll(softsp);
69429949e86Sstevel 	fhc_bdlist_unlock();
69529949e86Sstevel 
69629949e86Sstevel 	/*
69729949e86Sstevel 	 * Now register low-level board insert handler
69829949e86Sstevel 	 */
69929949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_pres_id,
70029949e86Sstevel 	    NULL, NULL, bd_insert_handler, (caddr_t)softsp) != DDI_SUCCESS)
70129949e86Sstevel 		goto bad13;
70229949e86Sstevel 
70329949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_gone_id,
70429949e86Sstevel 	    NULL, NULL, bd_insert_normal, (caddr_t)softsp) != DDI_SUCCESS)
70529949e86Sstevel 		goto bad14;
70629949e86Sstevel 
70729949e86Sstevel 	/*
70829949e86Sstevel 	 * Now register led blink handler (interrupt level)
70929949e86Sstevel 	 */
71029949e86Sstevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->blink_led_id,
71129949e86Sstevel 	    &softsp->sys_led_c, NULL, blink_led_handler, (caddr_t)softsp) !=
71229949e86Sstevel 	    DDI_SUCCESS)
71329949e86Sstevel 		goto bad15;
71429949e86Sstevel 	mutex_init(&softsp->sys_led_lock, NULL, MUTEX_DRIVER,
71529949e86Sstevel 	    (void *)softsp->sys_led_c);
71629949e86Sstevel 
71729949e86Sstevel 	/* initialize the bit field for all pps fans to assumed good */
71829949e86Sstevel 	softsp->pps_fan_saved = softsp->pps_fan_external_state =
71929949e86Sstevel 	    SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK;
72029949e86Sstevel 
72129949e86Sstevel 	/* prime the power supply state machines */
72229949e86Sstevel 	if (enable_sys_interrupt & SYS_PS_FAIL_EN)
72329949e86Sstevel 		ddi_trigger_softintr(softsp->ps_fail_poll_id);
72429949e86Sstevel 
72529949e86Sstevel 
72629949e86Sstevel 	/* kick off the OS led blinker */
72729949e86Sstevel 	softsp->sys_led = FALSE;
72829949e86Sstevel 	ddi_trigger_softintr(softsp->blink_led_id);
72929949e86Sstevel 
73029949e86Sstevel 	/* Now enable selected interrupt sources */
73129949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
73229949e86Sstevel 	*(softsp->csr) |= enable_sys_interrupt &
73329949e86Sstevel 	    (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
73429949e86Sstevel 	    SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
73529949e86Sstevel 	tmp_reg = *(softsp->csr);
73629949e86Sstevel #ifdef lint
73729949e86Sstevel 	tmp_reg = tmp_reg;
73829949e86Sstevel #endif
73929949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
74029949e86Sstevel 
74129949e86Sstevel 	/* Initialize the temperature */
74229949e86Sstevel 	init_temp_arrays(&softsp->tempstat);
74329949e86Sstevel 
74429949e86Sstevel 	/*
74529949e86Sstevel 	 * initialize key switch shadow state
74629949e86Sstevel 	 */
74729949e86Sstevel 	softsp->key_shadow = KEY_BOOT;
74829949e86Sstevel 
74929949e86Sstevel 	/*
75029949e86Sstevel 	 * Now add this soft state structure to the front of the linked list
75129949e86Sstevel 	 * of soft state structures.
75229949e86Sstevel 	 */
75329949e86Sstevel 	if (sys_list == (struct sysctrl_soft_state *)NULL) {
75429949e86Sstevel 		mutex_init(&sslist_mutex, NULL, MUTEX_DEFAULT, NULL);
75529949e86Sstevel 	}
75629949e86Sstevel 	mutex_enter(&sslist_mutex);
75729949e86Sstevel 	softsp->next = sys_list;
75829949e86Sstevel 	sys_list = softsp;
75929949e86Sstevel 	mutex_exit(&sslist_mutex);
76029949e86Sstevel 
76129949e86Sstevel 	/* Setup the kstats for this device */
76229949e86Sstevel 	sysctrl_add_kstats(softsp);
76329949e86Sstevel 
76429949e86Sstevel 	/* kick off the PPS fan poll routine */
76529949e86Sstevel 	pps_fan_poll(softsp);
76629949e86Sstevel 
76729949e86Sstevel 	if (sysctrl_overtemp_thread_started == 0) {
76829949e86Sstevel 		/*
76929949e86Sstevel 		 * set up the overtemp condition variable before
77029949e86Sstevel 		 * starting the thread.
77129949e86Sstevel 		 */
77229949e86Sstevel 		cv_init(&overtemp_cv, NULL, CV_DRIVER, NULL);
77329949e86Sstevel 
77429949e86Sstevel 		/*
77529949e86Sstevel 		 * start up the overtemp polling thread
77629949e86Sstevel 		 */
77729949e86Sstevel 		(void) thread_create(NULL, 0, (void (*)())sysctrl_overtemp_poll,
77829949e86Sstevel 		    NULL, 0, &p0, TS_RUN, minclsyspri);
77929949e86Sstevel 		sysctrl_overtemp_thread_started++;
78029949e86Sstevel 	}
78129949e86Sstevel 
78229949e86Sstevel 	if (sysctrl_keyswitch_thread_started == 0) {
78329949e86Sstevel 		extern void (*abort_seq_handler)();
78429949e86Sstevel 
78529949e86Sstevel 		/*
78629949e86Sstevel 		 * interpose sysctrl's abort sequence handler
78729949e86Sstevel 		 */
78829949e86Sstevel 		abort_seq_handler = sysctrl_abort_seq_handler;
78929949e86Sstevel 
79029949e86Sstevel 		/*
79129949e86Sstevel 		 * set up the key switch condition variable before
79229949e86Sstevel 		 * starting the thread
79329949e86Sstevel 		 */
79429949e86Sstevel 		cv_init(&keyswitch_cv, NULL, CV_DRIVER, NULL);
79529949e86Sstevel 
79629949e86Sstevel 		/*
79729949e86Sstevel 		 * start up the key switch polling thread
79829949e86Sstevel 		 */
79929949e86Sstevel 		(void) thread_create(NULL, 0,
80029949e86Sstevel 		    (void (*)())sysctrl_keyswitch_poll, NULL, 0, &p0,
80129949e86Sstevel 		    TS_RUN, minclsyspri);
80229949e86Sstevel 		sysctrl_keyswitch_thread_started++;
80329949e86Sstevel 	}
80429949e86Sstevel 
80529949e86Sstevel 	/*
80629949e86Sstevel 	 * perform initialization to allow setting of powerfail-time
80729949e86Sstevel 	 */
80829949e86Sstevel 	if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL)
80929949e86Sstevel 		softsp->options_nodeid = (pnode_t)NULL;
81029949e86Sstevel 	else
81129949e86Sstevel 		softsp->options_nodeid = (pnode_t)ddi_get_nodeid(dip);
81229949e86Sstevel 
81329949e86Sstevel 	DPRINTF(SYSCTRL_ATTACH_DEBUG,
81429949e86Sstevel 	    ("sysctrl: Creating devices start:%d, limit:%d, incr:%d\n",
81529949e86Sstevel 	    start, limit, incr));
81629949e86Sstevel 
81729949e86Sstevel 	/*
81829949e86Sstevel 	 * Create minor node for each system attachment points
81929949e86Sstevel 	 */
82029949e86Sstevel 	for (slot_num = start; slot_num < limit; slot_num = slot_num + incr) {
82129949e86Sstevel 		char name[30];
82229949e86Sstevel 		(void) sprintf(name, "slot%d", slot_num);
82329949e86Sstevel 		if (ddi_create_minor_node(devi, name, S_IFCHR,
82429949e86Sstevel 		    (PUTINSTANCE(instance) | slot_num),
82529949e86Sstevel 		    DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
82629949e86Sstevel 			cmn_err(CE_WARN, "sysctrl%d: \"%s\" "
82729949e86Sstevel 			    "ddi_create_minor_node failed",
82829949e86Sstevel 			    instance, name);
82929949e86Sstevel 			goto bad16;
83029949e86Sstevel 		}
83129949e86Sstevel 	}
83229949e86Sstevel 
83329949e86Sstevel 	ddi_report_dev(devi);
83429949e86Sstevel 
83529949e86Sstevel 	/*
83629949e86Sstevel 	 * Remote console is inherited from POST
83729949e86Sstevel 	 */
83829949e86Sstevel 	if ((*(softsp->clk_freq2) & RCONS_UART_EN) == 0) {
83929949e86Sstevel 		softsp->enable_rcons_atboot = FALSE;
84029949e86Sstevel 		cmn_err(CE_WARN, "Remote console not active");
84129949e86Sstevel 	} else
84229949e86Sstevel 		softsp->enable_rcons_atboot = TRUE;
84329949e86Sstevel 
84429949e86Sstevel 	return (DDI_SUCCESS);
84529949e86Sstevel 
84629949e86Sstevel bad16:
84729949e86Sstevel 	cv_destroy(&keyswitch_cv);
84829949e86Sstevel 	cv_destroy(&overtemp_cv);
84929949e86Sstevel 	mutex_destroy(&sslist_mutex);
85029949e86Sstevel 	mutex_destroy(&softsp->sys_led_lock);
85129949e86Sstevel 	ddi_remove_softintr(softsp->blink_led_id);
85229949e86Sstevel bad15:
85329949e86Sstevel 	ddi_remove_softintr(softsp->sbrd_gone_id);
85429949e86Sstevel bad14:
85529949e86Sstevel 	ddi_remove_softintr(softsp->sbrd_pres_id);
85629949e86Sstevel bad13:
85729949e86Sstevel 	ddi_remove_softintr(softsp->pps_fan_high_id);
85829949e86Sstevel bad12:
85929949e86Sstevel 	ddi_remove_softintr(softsp->pps_fan_id);
86029949e86Sstevel bad11:
86129949e86Sstevel 	ddi_remove_softintr(softsp->ps_fail_poll_id);
86229949e86Sstevel bad10:
86329949e86Sstevel 	mutex_destroy(&softsp->ps_fail_lock);
86429949e86Sstevel 	ddi_remove_softintr(softsp->ps_fail_int_id);
86529949e86Sstevel bad9:
86629949e86Sstevel 	ddi_remove_softintr(softsp->ac_fail_high_id);
86729949e86Sstevel bad8:
86829949e86Sstevel 	ddi_remove_softintr(softsp->ac_fail_id);
86929949e86Sstevel bad7:
87029949e86Sstevel 	ddi_remove_softintr(softsp->spur_long_to_id);
87129949e86Sstevel bad6:
87229949e86Sstevel 	ddi_remove_softintr(softsp->spur_high_id);
87329949e86Sstevel bad5:
87429949e86Sstevel 	mutex_destroy(&softsp->spur_int_lock);
87529949e86Sstevel 	ddi_remove_softintr(softsp->spur_id);
87629949e86Sstevel bad4:
87729949e86Sstevel 	ddi_remove_intr(devi, 0, softsp->iblock);
87829949e86Sstevel bad3:
87929949e86Sstevel 	mutex_destroy(&softsp->csr_mutex);
88029949e86Sstevel bad2:
88129949e86Sstevel 	ddi_unmap_regs(softsp->dip, 1, (caddr_t *)&softsp->csr, 0, 0);
88229949e86Sstevel 	if (softsp->clk_ver != NULL)
88329949e86Sstevel 		ddi_unmap_regs(softsp->dip, 2, (caddr_t *)&softsp->clk_ver,
88429949e86Sstevel 		    0, 0);
88529949e86Sstevel bad1:
88629949e86Sstevel 	ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->clk_freq1, 0, 0);
88729949e86Sstevel 
88829949e86Sstevel bad0:
88929949e86Sstevel 	ddi_soft_state_free(sysctrlp, instance);
89029949e86Sstevel 	ddi_remove_minor_node(dip, NULL);
89129949e86Sstevel 	cmn_err(CE_WARN,
89229949e86Sstevel 	    "sysctrl%d: Initialization failure. Some system level events,"
89329949e86Sstevel 	    " {AC Fail, Fan Failure, PS Failure} not detected", instance);
89429949e86Sstevel 	return (DDI_FAILURE);
89529949e86Sstevel }
89629949e86Sstevel 
89729949e86Sstevel struct sysc_hold {
89829949e86Sstevel 	int start;
89929949e86Sstevel 	int limit;
90029949e86Sstevel 	int incr;
90129949e86Sstevel 	int hold;
90229949e86Sstevel };
90329949e86Sstevel 
90429949e86Sstevel static int
90529949e86Sstevel sysctrl_hold_rele_branches(dev_info_t *dip, void *arg)
90629949e86Sstevel {
90729949e86Sstevel 	int *rp, len, slot, i;
90829949e86Sstevel 	struct sysc_hold *ap = (struct sysc_hold *)arg;
90929949e86Sstevel 
91029949e86Sstevel 	/*
91129949e86Sstevel 	 * For Sunfire, top nodes on board are always children of root dip
91229949e86Sstevel 	 */
91329949e86Sstevel 	ASSERT(ddi_get_parent(dip) == ddi_root_node());
91429949e86Sstevel 
91529949e86Sstevel 	/*
91629949e86Sstevel 	 * Skip non-PROM and "central" nodes
91729949e86Sstevel 	 */
91829949e86Sstevel 	if (!ndi_dev_is_prom_node(dip) ||
91929949e86Sstevel 	    strcmp(ddi_node_name(dip), "central") == 0)
92029949e86Sstevel 		return (DDI_WALK_PRUNECHILD);
92129949e86Sstevel 
92229949e86Sstevel 	/*
92329949e86Sstevel 	 * Extract board # from reg property.
92429949e86Sstevel 	 */
92529949e86Sstevel 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
92629949e86Sstevel 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", (caddr_t)&rp, &len)
92729949e86Sstevel 	    != DDI_SUCCESS) {
92829949e86Sstevel 		DPRINTF(SYSC_DEBUG, ("devinfo node %s(%p) has no reg"
92929949e86Sstevel 		    " property\n", ddi_node_name(dip), (void *)dip));
93029949e86Sstevel 		return (DDI_WALK_PRUNECHILD);
93129949e86Sstevel 	}
93229949e86Sstevel 
93329949e86Sstevel 	slot = (*rp - 0x1c0) >> 2;
93429949e86Sstevel 	kmem_free(rp, len);
93529949e86Sstevel 
93629949e86Sstevel 	ASSERT(ap->start >= 0 && ap->start < ap->limit);
93729949e86Sstevel 
93829949e86Sstevel 	for (i = ap->start; i < ap->limit; i = i + ap->incr) {
93929949e86Sstevel 		if (i == slot)
94029949e86Sstevel 			break;
94129949e86Sstevel 	}
94229949e86Sstevel 
94329949e86Sstevel 	if (i >= ap->limit) {
94429949e86Sstevel 		DPRINTF(SYSC_DEBUG, ("sysctrl_hold_rele: Invalid board # (%d)"
94529949e86Sstevel 		    " for node %s(%p)\n", slot, ddi_node_name(dip),
94629949e86Sstevel 		    (void *)dip));
94729949e86Sstevel 		return (DDI_WALK_PRUNECHILD);
94829949e86Sstevel 	}
94929949e86Sstevel 
95029949e86Sstevel 	if (ap->hold) {
95129949e86Sstevel 		ASSERT(!e_ddi_branch_held(dip));
95229949e86Sstevel 		e_ddi_branch_hold(dip);
95329949e86Sstevel 	} else {
95429949e86Sstevel 		ASSERT(e_ddi_branch_held(dip));
95529949e86Sstevel 		e_ddi_branch_rele(dip);
95629949e86Sstevel 	}
95729949e86Sstevel 
95829949e86Sstevel 	return (DDI_WALK_PRUNECHILD);
95929949e86Sstevel }
96029949e86Sstevel 
96129949e86Sstevel /* ARGSUSED */
96229949e86Sstevel static int
96329949e86Sstevel sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
96429949e86Sstevel {
96529949e86Sstevel #ifdef	SYSCTRL_SUPPORTS_DETACH
96629949e86Sstevel 	dev_info_t			*rdip;
96729949e86Sstevel 	struct sysc_hold		arg = {0};
96829949e86Sstevel 	struct sysctrl_soft_state	*softsp;
96929949e86Sstevel #endif	/* SYSCTRL_SUPPORTS_DETACH */
97029949e86Sstevel 
97129949e86Sstevel 	if (sysctrl_enable_detach_suspend == FALSE)
97229949e86Sstevel 		return (DDI_FAILURE);
97329949e86Sstevel 
97429949e86Sstevel 	switch (cmd) {
97529949e86Sstevel 	case DDI_SUSPEND:
97629949e86Sstevel 		/*
97729949e86Sstevel 		 * XXX we don't presently save the state of the remote
97829949e86Sstevel 		 * console because it is a constant function of POST.
97929949e86Sstevel 		 * XXX we don't deal with the hardware watchdog here
98029949e86Sstevel 		 * either.  It should be handled in hardclk.
98129949e86Sstevel 		 */
98229949e86Sstevel 		return (DDI_SUCCESS);
98329949e86Sstevel 
98429949e86Sstevel 	case DDI_DETACH:
98529949e86Sstevel 		break;
98629949e86Sstevel 	default:
98729949e86Sstevel 		return (DDI_FAILURE);
98829949e86Sstevel 	}
98929949e86Sstevel 
99029949e86Sstevel #ifdef	SYSCTRL_SUPPORTS_DETACH
99129949e86Sstevel 
99229949e86Sstevel 	/*
99329949e86Sstevel 	 * XXX If sysctrl ever supports detach, this code should be enabled
99429949e86Sstevel 	 * This is only the portion of the detach code dealing with
99529949e86Sstevel 	 * the DDI branch routines. Other parts of detach will need
99629949e86Sstevel 	 * to be added.
99729949e86Sstevel 	 */
99829949e86Sstevel 
99929949e86Sstevel 	/*
100029949e86Sstevel 	 * Walk immediate children of root devinfo node, releasing holds
100129949e86Sstevel 	 * on branches acquired in first sysctrl_open().
100229949e86Sstevel 	 */
100329949e86Sstevel 
100429949e86Sstevel 	instance = ddi_get_instance(dip);
100529949e86Sstevel 	softsp = GETSOFTC(instance);
100629949e86Sstevel 
100729949e86Sstevel 	if (softsp == NULL) {
100829949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d device not attached", instance);
100929949e86Sstevel 		return (DDI_FAILURE);
101029949e86Sstevel 	}
101129949e86Sstevel 
101229949e86Sstevel 	sysc_slot_info(softsp->nslots, &arg.start, &arg.limit, &arg.incr);
101329949e86Sstevel 
101429949e86Sstevel 	arg.hold = 0;
101529949e86Sstevel 
101629949e86Sstevel 	rdip = ddi_root_node();
101729949e86Sstevel 
101829949e86Sstevel 	ndi_devi_enter(rdip, &circ);
101929949e86Sstevel 	ddi_walk_devs(ddi_get_child(rdip), sysctrl_hold_rele_branches, &arg);
102029949e86Sstevel 	ndi_devi_exit(rdip, circ);
102129949e86Sstevel 
102229949e86Sstevel 	sysctrl_ddi_branch_init = 0;
102329949e86Sstevel 
102429949e86Sstevel 	return (DDI_SUCCESS);
102529949e86Sstevel #endif	/* SYSCTRL_SUPPORTS_DETACH */
102629949e86Sstevel 
102729949e86Sstevel 	return (DDI_FAILURE);
102829949e86Sstevel }
102929949e86Sstevel 
103029949e86Sstevel /* ARGSUSED */
103129949e86Sstevel static int
103229949e86Sstevel sysctrl_open(dev_t *devp, int flag, int otyp, cred_t *credp)
103329949e86Sstevel {
103429949e86Sstevel 	int		instance;
103529949e86Sstevel 	int		slot;
103629949e86Sstevel 	dev_t		dev;
103729949e86Sstevel 	int		circ;
103829949e86Sstevel 	dev_info_t	*rdip;
103929949e86Sstevel 	struct sysc_hold arg = {0};
104029949e86Sstevel 	struct sysctrl_soft_state *softsp;
104129949e86Sstevel 
104229949e86Sstevel 	dev = *devp;
104329949e86Sstevel 
104429949e86Sstevel 	/*
104529949e86Sstevel 	 * We checked against the instance softstate structure since there
104629949e86Sstevel 	 * will only be one instance of sysctrl (clock board) in UEXX00
104729949e86Sstevel 	 *
104829949e86Sstevel 	 * Since we only create minor devices for existing slots on a
104929949e86Sstevel 	 * particular system, we don't need to worry about non-exist slot.
105029949e86Sstevel 	 */
105129949e86Sstevel 
105229949e86Sstevel 	instance = GETINSTANCE(dev);
105329949e86Sstevel 	slot = GETSLOT(dev);
105429949e86Sstevel 
105529949e86Sstevel 	/* Is the instance attached? */
105629949e86Sstevel 	if ((softsp = GETSOFTC(instance)) == NULL) {
105729949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d device not attached", instance);
105829949e86Sstevel 		return (ENXIO);
105929949e86Sstevel 	}
106029949e86Sstevel 
106129949e86Sstevel 	/* verify that otyp is appropriate */
106229949e86Sstevel 	if (otyp != OTYP_CHR) {
106329949e86Sstevel 		return (EINVAL);
106429949e86Sstevel 	}
106529949e86Sstevel 
106629949e86Sstevel 	if (!fhc_bd_valid(slot))
106729949e86Sstevel 		return (ENXIO);
106829949e86Sstevel 
106929949e86Sstevel 	/*
107029949e86Sstevel 	 * On first open of a sysctrl minor walk immediate children of the
107129949e86Sstevel 	 * devinfo root node and hold all branches of interest.
107229949e86Sstevel 	 */
107329949e86Sstevel 	mutex_enter(&sysctrl_branch_mutex);
107429949e86Sstevel 	if (!sysctrl_ddi_branch_init) {
107529949e86Sstevel 
107629949e86Sstevel 		sysctrl_ddi_branch_init = 1;
107729949e86Sstevel 
107829949e86Sstevel 		sysc_slot_info(softsp->nslots, &arg.start, &arg.limit,
107929949e86Sstevel 		    &arg.incr);
108029949e86Sstevel 		arg.hold = 1;
108129949e86Sstevel 
108229949e86Sstevel 		rdip = ddi_root_node();
108329949e86Sstevel 
108429949e86Sstevel 		ndi_devi_enter(rdip, &circ);
108529949e86Sstevel 		ddi_walk_devs(ddi_get_child(rdip), sysctrl_hold_rele_branches,
108629949e86Sstevel 		    &arg);
108729949e86Sstevel 		ndi_devi_exit(rdip, circ);
108829949e86Sstevel 	}
108929949e86Sstevel 	mutex_exit(&sysctrl_branch_mutex);
109029949e86Sstevel 
109129949e86Sstevel 	return (DDI_SUCCESS);
109229949e86Sstevel }
109329949e86Sstevel 
109429949e86Sstevel /* ARGSUSED */
109529949e86Sstevel static int
109629949e86Sstevel sysctrl_close(dev_t devp, int flag, int otyp, cred_t *credp)
109729949e86Sstevel {
109829949e86Sstevel 	return (DDI_SUCCESS);
109929949e86Sstevel }
110029949e86Sstevel 
110129949e86Sstevel /*
110229949e86Sstevel  * This function will acquire the lock and set the in_transition
110329949e86Sstevel  * bit for the specified slot.  If the slot is being used,
110429949e86Sstevel  * we return FALSE; else set in_transition and return TRUE.
110529949e86Sstevel  */
110629949e86Sstevel static int
110729949e86Sstevel sysc_enter_transition(int slot)
110829949e86Sstevel {
110929949e86Sstevel 	fhc_bd_t	*list;
111029949e86Sstevel 	sysc_cfga_stat_t *sysc_stat_lk;
111129949e86Sstevel 	fhc_bd_t	*glist;
111229949e86Sstevel 	sysc_cfga_stat_t *sysc_stat_gk;
111329949e86Sstevel 
111429949e86Sstevel 	/* mutex lock the structure */
111529949e86Sstevel 	list = fhc_bdlist_lock(slot);
111629949e86Sstevel 	if ((slot != -1) && (list == NULL)) {
111729949e86Sstevel 		fhc_bdlist_unlock();
111829949e86Sstevel 		return (FALSE);
111929949e86Sstevel 	}
112029949e86Sstevel 
112129949e86Sstevel 	glist = fhc_bd_clock();
112229949e86Sstevel 	if (slot == -1)
112329949e86Sstevel 		list = glist;
112429949e86Sstevel 
112529949e86Sstevel 	/* change the in_transition bit */
112629949e86Sstevel 	sysc_stat_lk = &list->sc;
112729949e86Sstevel 	sysc_stat_gk = &glist->sc;
112829949e86Sstevel 	if ((sysc_stat_lk->in_transition == TRUE) ||
112929949e86Sstevel 	    (sysc_stat_gk->in_transition == TRUE)) {
113029949e86Sstevel 		fhc_bdlist_unlock();
113129949e86Sstevel 		return (FALSE);
113229949e86Sstevel 	} else {
113329949e86Sstevel 		sysc_stat_lk->in_transition = TRUE;
113429949e86Sstevel 		return (TRUE);
113529949e86Sstevel 	}
113629949e86Sstevel }
113729949e86Sstevel 
113829949e86Sstevel /*
113929949e86Sstevel  * This function will release the lock and clear the in_transition
114029949e86Sstevel  * bit for the specified slot.
114129949e86Sstevel  */
114229949e86Sstevel static void
114329949e86Sstevel sysc_exit_transition(int slot)
114429949e86Sstevel {
114529949e86Sstevel 	fhc_bd_t	*list;
114629949e86Sstevel 	sysc_cfga_stat_t *sysc_stat_lk;
114729949e86Sstevel 
114829949e86Sstevel 	ASSERT(fhc_bdlist_locked());
114929949e86Sstevel 
115029949e86Sstevel 	if (slot == -1)
115129949e86Sstevel 		list = fhc_bd_clock();
115229949e86Sstevel 	else
115329949e86Sstevel 		list = fhc_bd(slot);
115429949e86Sstevel 	sysc_stat_lk = &list->sc;
115529949e86Sstevel 	ASSERT(sysc_stat_lk->in_transition == TRUE);
115629949e86Sstevel 	sysc_stat_lk->in_transition = FALSE;
115729949e86Sstevel 	fhc_bdlist_unlock();
115829949e86Sstevel }
115929949e86Sstevel 
116029949e86Sstevel static int
116129949e86Sstevel sysc_pkt_init(sysc_cfga_pkt_t *pkt, intptr_t arg, int flag)
116229949e86Sstevel {
116329949e86Sstevel #ifdef _MULTI_DATAMODEL
116429949e86Sstevel 	if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
116529949e86Sstevel 		sysc_cfga_cmd32_t sysc_cmd32;
116629949e86Sstevel 
116729949e86Sstevel 		if (ddi_copyin((void *)arg, &sysc_cmd32,
116829949e86Sstevel 		    sizeof (sysc_cfga_cmd32_t), flag) != 0) {
116929949e86Sstevel 			return (EFAULT);
117029949e86Sstevel 		}
117129949e86Sstevel 		pkt->cmd_cfga.force = sysc_cmd32.force;
117229949e86Sstevel 		pkt->cmd_cfga.test = sysc_cmd32.test;
117329949e86Sstevel 		pkt->cmd_cfga.arg = sysc_cmd32.arg;
117429949e86Sstevel 		pkt->cmd_cfga.errtype = sysc_cmd32.errtype;
117529949e86Sstevel 		pkt->cmd_cfga.outputstr =
117629949e86Sstevel 		    (char *)(uintptr_t)sysc_cmd32.outputstr;
117729949e86Sstevel 	} else
117829949e86Sstevel #endif /* _MULTI_DATAMODEL */
117929949e86Sstevel 	if (ddi_copyin((void *)arg, &(pkt->cmd_cfga),
118029949e86Sstevel 	    sizeof (sysc_cfga_cmd_t), flag) != 0) {
118129949e86Sstevel 		return (EFAULT);
118229949e86Sstevel 	}
118329949e86Sstevel 	pkt->errbuf = kmem_zalloc(SYSC_OUTPUT_LEN, KM_SLEEP);
118429949e86Sstevel 	return (0);
118529949e86Sstevel }
118629949e86Sstevel 
118729949e86Sstevel static int
118829949e86Sstevel sysc_pkt_fini(sysc_cfga_pkt_t *pkt, intptr_t arg, int flag)
118929949e86Sstevel {
119029949e86Sstevel 	int ret = TRUE;
119129949e86Sstevel 
119229949e86Sstevel #ifdef _MULTI_DATAMODEL
119329949e86Sstevel 	if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
119429949e86Sstevel 
119529949e86Sstevel 		if (ddi_copyout(&(pkt->cmd_cfga.errtype),
119629949e86Sstevel 		    (void *)&(((sysc_cfga_cmd32_t *)arg)->errtype),
119729949e86Sstevel 		    sizeof (sysc_err_t), flag) != 0) {
119829949e86Sstevel 			ret = FALSE;
119929949e86Sstevel 		}
120029949e86Sstevel 	} else
120129949e86Sstevel #endif
120229949e86Sstevel 	if (ddi_copyout(&(pkt->cmd_cfga.errtype),
120329949e86Sstevel 	    (void *)&(((sysc_cfga_cmd_t *)arg)->errtype),
120429949e86Sstevel 	    sizeof (sysc_err_t), flag) != 0) {
120529949e86Sstevel 		ret = FALSE;
120629949e86Sstevel 	}
120729949e86Sstevel 
120829949e86Sstevel 	if ((ret != FALSE) && ((pkt->cmd_cfga.outputstr != NULL) &&
120929949e86Sstevel 	    (ddi_copyout(pkt->errbuf, pkt->cmd_cfga.outputstr,
121029949e86Sstevel 	    SYSC_OUTPUT_LEN, flag) != 0))) {
121129949e86Sstevel 			ret = FALSE;
121229949e86Sstevel 	}
121329949e86Sstevel 
121429949e86Sstevel 	kmem_free(pkt->errbuf, SYSC_OUTPUT_LEN);
121529949e86Sstevel 	return (ret);
121629949e86Sstevel }
121729949e86Sstevel 
121829949e86Sstevel /* ARGSUSED */
121929949e86Sstevel static int
122029949e86Sstevel sysctrl_ioctl(dev_t devt, int cmd, intptr_t arg, int flag, cred_t *cred_p,
122129949e86Sstevel 		int *rval_p)
122229949e86Sstevel {
122329949e86Sstevel 	struct sysctrl_soft_state *softsp;
122429949e86Sstevel 	sysc_cfga_pkt_t sysc_pkt;
122529949e86Sstevel 	fhc_bd_t *fhc_list = NULL;
122629949e86Sstevel 	sysc_cfga_stat_t *sc_list = NULL;
122729949e86Sstevel 	fhc_bd_t *bdp;
122829949e86Sstevel 	sysc_cfga_stat_t *sc = NULL;
122929949e86Sstevel 	int instance;
123029949e86Sstevel 	int slot;
123129949e86Sstevel 	int retval = 0;
123229949e86Sstevel 	int i;
123329949e86Sstevel 
123429949e86Sstevel 	instance = GETINSTANCE(devt);
123529949e86Sstevel 	softsp = GETSOFTC(instance);
123629949e86Sstevel 	if (softsp == NULL) {
123729949e86Sstevel 		cmn_err(CE_CONT,
123829949e86Sstevel 		    "sysctrl_ioctl(%d): NULL softstate ptr!\n",
123929949e86Sstevel 		    (int)GETSLOT(devt));
124029949e86Sstevel 		return (ENXIO);
124129949e86Sstevel 	}
124229949e86Sstevel 
124329949e86Sstevel 	slot = GETSLOT(devt);
124429949e86Sstevel 
124529949e86Sstevel 	/*
124629949e86Sstevel 	 * First switch is to do correct locking and do ddi_copyin()
124729949e86Sstevel 	 */
124829949e86Sstevel 	switch (cmd) {
124929949e86Sstevel 	case SYSC_CFGA_CMD_GETSTATUS:
125029949e86Sstevel 		/* mutex lock the whole list */
125129949e86Sstevel 		if (sysc_enter_transition(-1) != TRUE) {
125229949e86Sstevel 			retval = EBUSY;
125329949e86Sstevel 			goto cleanup_exit;
125429949e86Sstevel 		}
125529949e86Sstevel 
125629949e86Sstevel 		/* allocate the memory before acquiring mutex */
125729949e86Sstevel 		fhc_list = kmem_zalloc(sizeof (fhc_bd_t) * fhc_max_boards(),
125829949e86Sstevel 		    KM_SLEEP);
125929949e86Sstevel 
126029949e86Sstevel 		sc_list = kmem_zalloc(sizeof (sysc_cfga_stat_t) *
126129949e86Sstevel 		    fhc_max_boards(), KM_SLEEP);
126229949e86Sstevel 
126329949e86Sstevel 		break;
126429949e86Sstevel 
126529949e86Sstevel 	case SYSC_CFGA_CMD_EJECT:
126629949e86Sstevel 	case SYSC_CFGA_CMD_INSERT:
126729949e86Sstevel 		retval = ENOTSUP;
126829949e86Sstevel 		goto cleanup_exit;
126929949e86Sstevel 
127029949e86Sstevel 	case SYSC_CFGA_CMD_CONNECT:
127129949e86Sstevel 	case SYSC_CFGA_CMD_DISCONNECT:
127229949e86Sstevel 	case SYSC_CFGA_CMD_UNCONFIGURE:
127329949e86Sstevel 	case SYSC_CFGA_CMD_CONFIGURE:
127429949e86Sstevel 	case SYSC_CFGA_CMD_TEST:
127529949e86Sstevel 	case SYSC_CFGA_CMD_TEST_SET_COND:
127629949e86Sstevel 	case SYSC_CFGA_CMD_QUIESCE_TEST:
127729949e86Sstevel 
127829949e86Sstevel 		/* ioctls allowed if caller has write permission */
127929949e86Sstevel 		if (!(flag & FWRITE)) {
128029949e86Sstevel 			retval = EPERM;
128129949e86Sstevel 			goto cleanup_exit;
128229949e86Sstevel 		}
128329949e86Sstevel 
128429949e86Sstevel 		retval = sysc_pkt_init(&sysc_pkt, arg, flag);
128529949e86Sstevel 		if (retval != 0)
128629949e86Sstevel 			goto cleanup_exit;
128729949e86Sstevel 
128829949e86Sstevel 		/* grasp lock and set in_transition bit */
128929949e86Sstevel 		if (sysc_enter_transition(cmd == SYSC_CFGA_CMD_QUIESCE_TEST
129029949e86Sstevel 		    ? -1 : slot) != TRUE) {
129129949e86Sstevel 			retval = EBUSY;
129229949e86Sstevel 			SYSC_ERR_SET(&sysc_pkt, SYSC_ERR_INTRANS);
129329949e86Sstevel 			goto cleanup_copyout;
129429949e86Sstevel 		}
129529949e86Sstevel 
129629949e86Sstevel 		/* get the status structure for the slot */
129729949e86Sstevel 		bdp = fhc_bd(slot);
129829949e86Sstevel 		sc = &bdp->sc;
129929949e86Sstevel 		break;
130029949e86Sstevel 
130129949e86Sstevel 	/* POSIX definition: return ENOTTY if unsupported command */
130229949e86Sstevel 	default:
130329949e86Sstevel 		retval = ENOTTY;
130429949e86Sstevel 		goto cleanup_exit;
130529949e86Sstevel 	}
130629949e86Sstevel 
130729949e86Sstevel 	/*
130829949e86Sstevel 	 * Second switch is to call the underlayer workhorse.
130929949e86Sstevel 	 */
131029949e86Sstevel 	switch (cmd) {
131129949e86Sstevel 	case SYSC_CFGA_CMD_GETSTATUS:
131229949e86Sstevel 		for (i = 0; i < fhc_max_boards(); i++) {
131329949e86Sstevel 			if (fhc_bd_valid(i)) {
131429949e86Sstevel 				bdp = fhc_bd(i);
131529949e86Sstevel 				if (fhc_bd_is_jtag_master(i))
131629949e86Sstevel 					bdp->sc.no_detach = 1;
131729949e86Sstevel 				else
131829949e86Sstevel 					bdp->sc.no_detach = 0;
131929949e86Sstevel 				bcopy((caddr_t)&bdp->sc,
132029949e86Sstevel 				    &sc_list[i], sizeof (sysc_cfga_stat_t));
132129949e86Sstevel 			} else {
132229949e86Sstevel 				sc_list[i].board = -1;
132329949e86Sstevel 				sc_list[i].rstate = SYSC_CFGA_RSTATE_EMPTY;
132429949e86Sstevel 			}
132529949e86Sstevel 		}
132629949e86Sstevel 
132729949e86Sstevel 		sysc_exit_transition(-1);
132829949e86Sstevel 
132929949e86Sstevel 		break;
133029949e86Sstevel 
133129949e86Sstevel 	case SYSC_CFGA_CMD_EJECT:
133229949e86Sstevel 	case SYSC_CFGA_CMD_INSERT:
133329949e86Sstevel 		retval = ENOTSUP;
133429949e86Sstevel 		goto cleanup_exit;
133529949e86Sstevel 
133629949e86Sstevel 	case SYSC_CFGA_CMD_CONNECT:
133729949e86Sstevel 		retval = sysc_policy_connect(softsp, &sysc_pkt, sc);
133829949e86Sstevel 		sysc_exit_transition(slot);
133929949e86Sstevel 		break;
134029949e86Sstevel 
134129949e86Sstevel 	case SYSC_CFGA_CMD_DISCONNECT:
134229949e86Sstevel 		retval = sysc_policy_disconnect(softsp, &sysc_pkt, sc);
134329949e86Sstevel 		sysc_exit_transition(slot);
134429949e86Sstevel 		break;
134529949e86Sstevel 
134629949e86Sstevel 	case SYSC_CFGA_CMD_UNCONFIGURE:
134729949e86Sstevel 		retval = sysc_policy_unconfigure(softsp, &sysc_pkt, sc);
134829949e86Sstevel 		sysc_exit_transition(slot);
134929949e86Sstevel 		break;
135029949e86Sstevel 
135129949e86Sstevel 	case SYSC_CFGA_CMD_CONFIGURE:
135229949e86Sstevel 		retval = sysc_policy_configure(softsp, &sysc_pkt, sc);
135329949e86Sstevel 		sysc_exit_transition(slot);
135429949e86Sstevel 		break;
135529949e86Sstevel 
135629949e86Sstevel 	case SYSC_CFGA_CMD_TEST:
135729949e86Sstevel 		retval = fhc_bd_test(slot, &sysc_pkt);
135829949e86Sstevel 		sysc_exit_transition(slot);
135929949e86Sstevel 		break;
136029949e86Sstevel 
136129949e86Sstevel 	case SYSC_CFGA_CMD_TEST_SET_COND:
136229949e86Sstevel 		retval = fhc_bd_test_set_cond(slot, &sysc_pkt);
136329949e86Sstevel 		sysc_exit_transition(slot);
136429949e86Sstevel 		break;
136529949e86Sstevel 
136629949e86Sstevel 	case SYSC_CFGA_CMD_QUIESCE_TEST:
136729949e86Sstevel 		sysctrl_suspend_prepare();
136829949e86Sstevel 		fhc_bdlist_unlock();
136929949e86Sstevel 
137029949e86Sstevel 		if (sysctrl_suspend(&sysc_pkt) == DDI_SUCCESS) {
137129949e86Sstevel 			sysctrl_resume(&sysc_pkt);
137229949e86Sstevel 		} else {
137329949e86Sstevel 			retval = EBUSY;
137429949e86Sstevel 		}
137529949e86Sstevel 
137629949e86Sstevel 		(void) fhc_bdlist_lock(-1);
137729949e86Sstevel 		sysc_exit_transition(-1);
137829949e86Sstevel 		break;
137929949e86Sstevel 
138029949e86Sstevel 	default:
138129949e86Sstevel 		retval = ENOTTY;
138229949e86Sstevel 		goto cleanup_exit;
138329949e86Sstevel 	}
138429949e86Sstevel 
138529949e86Sstevel cleanup_copyout:
138629949e86Sstevel 	/*
138729949e86Sstevel 	 * 3rd switch is to do appropriate copyout and reset locks
138829949e86Sstevel 	 */
138929949e86Sstevel 	switch (cmd) {
139029949e86Sstevel 	case SYSC_CFGA_CMD_GETSTATUS:
139129949e86Sstevel 		if (ddi_copyout(sc_list, (void *)arg,
139229949e86Sstevel 		    sizeof (sysc_cfga_stat_t) * fhc_max_boards(),
139329949e86Sstevel 		    flag) != 0) {
139429949e86Sstevel 			retval = EFAULT;
139529949e86Sstevel 		}
139629949e86Sstevel 
139729949e86Sstevel 		/* cleanup memory */
139829949e86Sstevel 		kmem_free(fhc_list, sizeof (fhc_bd_t) * fhc_max_boards());
139929949e86Sstevel 		kmem_free(sc_list, sizeof (sysc_cfga_stat_t) *
140029949e86Sstevel 		    fhc_max_boards());
140129949e86Sstevel 		break;
140229949e86Sstevel 
140329949e86Sstevel 	case SYSC_CFGA_CMD_EJECT:
140429949e86Sstevel 	case SYSC_CFGA_CMD_INSERT:
140529949e86Sstevel 		retval = ENOTSUP;
140629949e86Sstevel 		break;
140729949e86Sstevel 
140829949e86Sstevel 	case SYSC_CFGA_CMD_CONNECT:
140929949e86Sstevel 	case SYSC_CFGA_CMD_DISCONNECT:
141029949e86Sstevel 	case SYSC_CFGA_CMD_UNCONFIGURE:
141129949e86Sstevel 	case SYSC_CFGA_CMD_CONFIGURE:
141229949e86Sstevel 	case SYSC_CFGA_CMD_TEST:
141329949e86Sstevel 	case SYSC_CFGA_CMD_TEST_SET_COND:
141429949e86Sstevel 	case SYSC_CFGA_CMD_QUIESCE_TEST:
141529949e86Sstevel 		if (sysc_pkt_fini(&sysc_pkt, arg, flag) != TRUE)
141629949e86Sstevel 			return (EFAULT);
141729949e86Sstevel 		break;
141829949e86Sstevel 
141929949e86Sstevel 	default:
142029949e86Sstevel 		retval = ENOTTY;
142129949e86Sstevel 		break;
142229949e86Sstevel 	}
142329949e86Sstevel 
142429949e86Sstevel cleanup_exit:
142529949e86Sstevel 	return (retval);
142629949e86Sstevel }
142729949e86Sstevel 
142829949e86Sstevel /*
142929949e86Sstevel  * system_high_handler()
143029949e86Sstevel  * This routine handles system interrupts.
143129949e86Sstevel  *
143229949e86Sstevel  * This routine goes through all the interrupt sources and masks
143329949e86Sstevel  * off the enable bit if interrupting.  Because of the special
143429949e86Sstevel  * nature of the pps fan source bits, we also cache the state
143529949e86Sstevel  * of the fan bits for that special case.
143629949e86Sstevel  *
143729949e86Sstevel  * The rest of the work is done in the low level handlers
143829949e86Sstevel  */
143929949e86Sstevel static uint_t
144029949e86Sstevel system_high_handler(caddr_t arg)
144129949e86Sstevel {
144229949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
144329949e86Sstevel 	uchar_t csr;
144429949e86Sstevel 	uchar_t status2;
144529949e86Sstevel 	uchar_t tmp_reg;
144629949e86Sstevel 	int serviced = 0;
144729949e86Sstevel 
144829949e86Sstevel 	ASSERT(softsp);
144929949e86Sstevel 
145029949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
145129949e86Sstevel 
145229949e86Sstevel 	/* read in the hardware registers */
145329949e86Sstevel 	csr = *(softsp->csr);
145429949e86Sstevel 	status2 = *(softsp->status2);
145529949e86Sstevel 
145629949e86Sstevel 	if (csr & SYS_AC_PWR_FAIL_EN) {
145729949e86Sstevel 		if (status2 & SYS_AC_FAIL) {
145829949e86Sstevel 
145929949e86Sstevel 			/* save the powerfail state in nvram */
146029949e86Sstevel 			nvram_update_powerfail(softsp);
146129949e86Sstevel 
146229949e86Sstevel 			/* disable this interrupt source */
146329949e86Sstevel 			csr &= ~SYS_AC_PWR_FAIL_EN;
146429949e86Sstevel 
146529949e86Sstevel 			ddi_trigger_softintr(softsp->ac_fail_id);
146629949e86Sstevel 			serviced++;
146729949e86Sstevel 		}
146829949e86Sstevel 	}
146929949e86Sstevel 
147029949e86Sstevel 	if (csr & SYS_PS_FAIL_EN) {
147129949e86Sstevel 		if ((*(softsp->ps_stat) != 0xff) ||
147229949e86Sstevel 		    ((~status2) & (SYS_PPS0_OK | SYS_CLK_33_OK |
147329949e86Sstevel 		    SYS_CLK_50_OK)) ||
147429949e86Sstevel 		    (~(*(softsp->pppsr)) & SYS_PPPSR_BITS)) {
147529949e86Sstevel 
147629949e86Sstevel 			/* disable this interrupt source */
147729949e86Sstevel 			csr &= ~SYS_PS_FAIL_EN;
147829949e86Sstevel 
147929949e86Sstevel 			ddi_trigger_softintr(softsp->ps_fail_int_id);
148029949e86Sstevel 			serviced++;
148129949e86Sstevel 		}
148229949e86Sstevel 	}
148329949e86Sstevel 
148429949e86Sstevel 	if (csr & SYS_PPS_FAN_FAIL_EN) {
148529949e86Sstevel 		if (status2 & SYS_RACK_FANFAIL ||
148629949e86Sstevel 		    !(status2 & SYS_AC_FAN_OK) ||
148729949e86Sstevel 		    !(status2 & SYS_KEYSW_FAN_OK)) {
148829949e86Sstevel 
148929949e86Sstevel 			/*
149029949e86Sstevel 			 * we must cache the fan status because it goes
149129949e86Sstevel 			 * away when we disable interrupts !?!?!
149229949e86Sstevel 			 */
149329949e86Sstevel 			softsp->pps_fan_saved = status2;
149429949e86Sstevel 
149529949e86Sstevel 			/* disable this interrupt source */
149629949e86Sstevel 			csr &= ~SYS_PPS_FAN_FAIL_EN;
149729949e86Sstevel 
149829949e86Sstevel 			ddi_trigger_softintr(softsp->pps_fan_id);
149929949e86Sstevel 			serviced++;
150029949e86Sstevel 		}
150129949e86Sstevel 	}
150229949e86Sstevel 
150329949e86Sstevel 	if (csr & SYS_SBRD_PRES_EN) {
150429949e86Sstevel 		if (!(*(softsp->status1) & SYS_NOT_BRD_PRES)) {
150529949e86Sstevel 
150629949e86Sstevel 			/* disable this interrupt source */
150729949e86Sstevel 			csr &= ~SYS_SBRD_PRES_EN;
150829949e86Sstevel 
150929949e86Sstevel 			ddi_trigger_softintr(softsp->sbrd_pres_id);
151029949e86Sstevel 			serviced++;
151129949e86Sstevel 		}
151229949e86Sstevel 	}
151329949e86Sstevel 
151429949e86Sstevel 	if (!serviced) {
151529949e86Sstevel 
151629949e86Sstevel 		/*
151729949e86Sstevel 		 * if we get here than it is likely that contact bounce
151829949e86Sstevel 		 * is messing with us.  so, we need to shut this interrupt
151929949e86Sstevel 		 * up for a while to let the contacts settle down.
152029949e86Sstevel 		 * Then we will re-enable the interrupts that are enabled
152129949e86Sstevel 		 * right now.  The trick is to disable the appropriate
152229949e86Sstevel 		 * interrupts and then to re-enable them correctly, even
152329949e86Sstevel 		 * though intervening handlers might have been working.
152429949e86Sstevel 		 */
152529949e86Sstevel 
152629949e86Sstevel 		/* remember all interrupts that could have caused it */
152729949e86Sstevel 		softsp->saved_en_state |= csr &
152829949e86Sstevel 		    (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
152929949e86Sstevel 		    SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
153029949e86Sstevel 
153129949e86Sstevel 		/* and then turn them off */
153229949e86Sstevel 		csr &= ~(SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
153329949e86Sstevel 		    SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
153429949e86Sstevel 
153529949e86Sstevel 		/* and then bump the counter */
153629949e86Sstevel 		softsp->spur_count++;
153729949e86Sstevel 
153829949e86Sstevel 		/* and kick off the timeout */
153929949e86Sstevel 		ddi_trigger_softintr(softsp->spur_id);
154029949e86Sstevel 	}
154129949e86Sstevel 
154229949e86Sstevel 	/* update the real csr */
154329949e86Sstevel 	*(softsp->csr) = csr;
154429949e86Sstevel 	tmp_reg = *(softsp->csr);
154529949e86Sstevel #ifdef lint
154629949e86Sstevel 	tmp_reg = tmp_reg;
154729949e86Sstevel #endif
154829949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
154929949e86Sstevel 
155029949e86Sstevel 	return (DDI_INTR_CLAIMED);
155129949e86Sstevel }
155229949e86Sstevel 
155329949e86Sstevel /*
155429949e86Sstevel  * we've detected a spurious interrupt.
155529949e86Sstevel  * determine if we should log a message and if we need another timeout
155629949e86Sstevel  */
155729949e86Sstevel static uint_t
155829949e86Sstevel spur_delay(caddr_t arg)
155929949e86Sstevel {
156029949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
156129949e86Sstevel 
156229949e86Sstevel 	ASSERT(softsp);
156329949e86Sstevel 
156429949e86Sstevel 	/* do we need to complain? */
156529949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
156629949e86Sstevel 
156729949e86Sstevel 	/* NOTE: this is == because we want one message per long timeout */
156829949e86Sstevel 	if (softsp->spur_count == MAX_SPUR_COUNT) {
156929949e86Sstevel 		char buf[128];
157029949e86Sstevel 
157129949e86Sstevel 		/* print out the candidates known at this time */
157229949e86Sstevel 		/* XXX not perfect because of re-entrant nature but close */
157329949e86Sstevel 		buf[0] = '\0';
157429949e86Sstevel 		if (softsp->saved_en_state & SYS_AC_PWR_FAIL_EN)
157529949e86Sstevel 			(void) strcat(buf, "AC FAIL");
157629949e86Sstevel 		if (softsp->saved_en_state & SYS_PPS_FAN_FAIL_EN)
157729949e86Sstevel 			(void) strcat(buf, buf[0] ? "|PPS FANS" : "PPS FANS");
157829949e86Sstevel 		if (softsp->saved_en_state & SYS_PS_FAIL_EN)
157929949e86Sstevel 			(void) strcat(buf, buf[0] ? "|PS FAIL" : "PS FAIL");
158029949e86Sstevel 		if (softsp->saved_en_state & SYS_SBRD_PRES_EN)
158129949e86Sstevel 			(void) strcat(buf,
158229949e86Sstevel 			    buf[0] ? "|BOARD INSERT" : "BOARD INSERT");
158329949e86Sstevel 
158429949e86Sstevel 		/*
158529949e86Sstevel 		 * This is a high level mutex, therefore it needs to be
158629949e86Sstevel 		 * dropped before calling cmn_err.
158729949e86Sstevel 		 */
158829949e86Sstevel 		mutex_exit(&softsp->csr_mutex);
158929949e86Sstevel 
159029949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: unserviced interrupt."
159129949e86Sstevel 		    " possible sources [%s].",
159229949e86Sstevel 		    ddi_get_instance(softsp->dip), buf);
159329949e86Sstevel 	} else
159429949e86Sstevel 		mutex_exit(&softsp->csr_mutex);
159529949e86Sstevel 
159629949e86Sstevel 	mutex_enter(&softsp->spur_int_lock);
159729949e86Sstevel 
159829949e86Sstevel 	/* do we need to start the short timeout? */
159929949e86Sstevel 	if (softsp->spur_timeout_id == 0) {
160029949e86Sstevel 		softsp->spur_timeout_id = timeout(spur_retry, softsp,
160129949e86Sstevel 		    spur_timeout_hz);
160229949e86Sstevel 	}
160329949e86Sstevel 
160429949e86Sstevel 	/* do we need to start the long timeout? */
160529949e86Sstevel 	if (softsp->spur_long_timeout_id == 0) {
160629949e86Sstevel 		softsp->spur_long_timeout_id = timeout(spur_long_timeout,
160729949e86Sstevel 		    softsp, spur_long_timeout_hz);
160829949e86Sstevel 	}
160929949e86Sstevel 
161029949e86Sstevel 	mutex_exit(&softsp->spur_int_lock);
161129949e86Sstevel 
161229949e86Sstevel 	return (DDI_INTR_CLAIMED);
161329949e86Sstevel }
161429949e86Sstevel 
161529949e86Sstevel /*
161629949e86Sstevel  * spur_retry
161729949e86Sstevel  *
161829949e86Sstevel  * this routine simply triggers the interrupt which will re-enable
161929949e86Sstevel  * the interrupts disabled by the spurious int detection.
162029949e86Sstevel  */
162129949e86Sstevel static void
162229949e86Sstevel spur_retry(void *arg)
162329949e86Sstevel {
162429949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
162529949e86Sstevel 
162629949e86Sstevel 	ASSERT(softsp);
162729949e86Sstevel 
162829949e86Sstevel 	ddi_trigger_softintr(softsp->spur_high_id);
162929949e86Sstevel 
163029949e86Sstevel 	mutex_enter(&softsp->spur_int_lock);
163129949e86Sstevel 	softsp->spur_timeout_id = 0;
163229949e86Sstevel 	mutex_exit(&softsp->spur_int_lock);
163329949e86Sstevel }
163429949e86Sstevel 
163529949e86Sstevel /*
163629949e86Sstevel  * spur_reenable
163729949e86Sstevel  *
163829949e86Sstevel  * OK, we've been slient for a while.   Go ahead and re-enable the
163929949e86Sstevel  * interrupts that were enabled at the time of the spurious detection.
164029949e86Sstevel  */
164129949e86Sstevel static uint_t
164229949e86Sstevel spur_reenable(caddr_t arg)
164329949e86Sstevel {
164429949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
164529949e86Sstevel 	uchar_t tmp_reg;
164629949e86Sstevel 
164729949e86Sstevel 	ASSERT(softsp);
164829949e86Sstevel 
164929949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
165029949e86Sstevel 
165129949e86Sstevel 	/* reenable those who were spurious candidates */
165229949e86Sstevel 	*(softsp->csr) |= softsp->saved_en_state &
165329949e86Sstevel 	    (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
165429949e86Sstevel 	    SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
165529949e86Sstevel 	tmp_reg = *(softsp->csr);
165629949e86Sstevel #ifdef lint
165729949e86Sstevel 	tmp_reg = tmp_reg;
165829949e86Sstevel #endif
165929949e86Sstevel 
166029949e86Sstevel 	/* clear out the saved state */
166129949e86Sstevel 	softsp->saved_en_state = 0;
166229949e86Sstevel 
166329949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
166429949e86Sstevel 
166529949e86Sstevel 	return (DDI_INTR_CLAIMED);
166629949e86Sstevel }
166729949e86Sstevel 
166829949e86Sstevel /*
166929949e86Sstevel  * spur_long_timeout
167029949e86Sstevel  *
167129949e86Sstevel  * this routine merely resets the spurious interrupt counter thus ending
167229949e86Sstevel  * the interval of interest.  of course this is done by triggering a
167329949e86Sstevel  * softint because the counter is protected by an interrupt mutex.
167429949e86Sstevel  */
167529949e86Sstevel static void
167629949e86Sstevel spur_long_timeout(void *arg)
167729949e86Sstevel {
167829949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
167929949e86Sstevel 
168029949e86Sstevel 	ASSERT(softsp);
168129949e86Sstevel 
168229949e86Sstevel 	ddi_trigger_softintr(softsp->spur_long_to_id);
168329949e86Sstevel 
168429949e86Sstevel 	mutex_enter(&softsp->spur_int_lock);
168529949e86Sstevel 	softsp->spur_long_timeout_id = 0;
168629949e86Sstevel 	mutex_exit(&softsp->spur_int_lock);
168729949e86Sstevel }
168829949e86Sstevel 
168929949e86Sstevel /*
169029949e86Sstevel  * spur_clear_count
169129949e86Sstevel  *
169229949e86Sstevel  * simply clear out the spurious interrupt counter.
169329949e86Sstevel  *
169429949e86Sstevel  * softint level only
169529949e86Sstevel  */
169629949e86Sstevel static uint_t
169729949e86Sstevel spur_clear_count(caddr_t arg)
169829949e86Sstevel {
169929949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
170029949e86Sstevel 
170129949e86Sstevel 	ASSERT(softsp);
170229949e86Sstevel 
170329949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
170429949e86Sstevel 	softsp->spur_count = 0;
170529949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
170629949e86Sstevel 
170729949e86Sstevel 	return (DDI_INTR_CLAIMED);
170829949e86Sstevel }
170929949e86Sstevel 
171029949e86Sstevel /*
171129949e86Sstevel  * ac_fail_handler
171229949e86Sstevel  *
171329949e86Sstevel  * This routine polls the AC power failure bit in the system status2
171429949e86Sstevel  * register.  If we get to this routine, then we sensed an ac fail
171529949e86Sstevel  * condition.  Note the fact and check again in a few.
171629949e86Sstevel  *
171729949e86Sstevel  * Called as softint from high interrupt.
171829949e86Sstevel  */
171929949e86Sstevel static uint_t
172029949e86Sstevel ac_fail_handler(caddr_t arg)
172129949e86Sstevel {
172229949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
172329949e86Sstevel 
172429949e86Sstevel 	ASSERT(softsp);
172529949e86Sstevel 
172629949e86Sstevel 	cmn_err(CE_WARN, "%s failure detected", ft_str_table[FT_AC_PWR]);
172729949e86Sstevel 	reg_fault(0, FT_AC_PWR, FT_SYSTEM);
172829949e86Sstevel 	(void) timeout(ac_fail_retry, softsp, ac_timeout_hz);
172929949e86Sstevel 
173029949e86Sstevel 	return (DDI_INTR_CLAIMED);
173129949e86Sstevel }
173229949e86Sstevel 
173329949e86Sstevel /*
173429949e86Sstevel  * The timeout from ac_fail_handler() that checks to see if the
173529949e86Sstevel  * condition persists.
173629949e86Sstevel  */
173729949e86Sstevel static void
173829949e86Sstevel ac_fail_retry(void *arg)
173929949e86Sstevel {
174029949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
174129949e86Sstevel 
174229949e86Sstevel 	ASSERT(softsp);
174329949e86Sstevel 
174429949e86Sstevel 	if (*softsp->status2 & SYS_AC_FAIL) {	/* still bad? */
174529949e86Sstevel 		(void) timeout(ac_fail_retry, softsp, ac_timeout_hz);
174629949e86Sstevel 	} else {
174729949e86Sstevel 		cmn_err(CE_NOTE, "%s failure no longer detected",
174829949e86Sstevel 		    ft_str_table[FT_AC_PWR]);
174929949e86Sstevel 		clear_fault(0, FT_AC_PWR, FT_SYSTEM);
175029949e86Sstevel 		ddi_trigger_softintr(softsp->ac_fail_high_id);
175129949e86Sstevel 	}
175229949e86Sstevel }
175329949e86Sstevel 
175429949e86Sstevel /*
175529949e86Sstevel  * The interrupt routine that we use to re-enable the interrupt.
175629949e86Sstevel  * Called from ddi_trigger_softint() in the ac_fail_retry() when
175729949e86Sstevel  * the AC is better.
175829949e86Sstevel  */
175929949e86Sstevel static uint_t
176029949e86Sstevel ac_fail_reenable(caddr_t arg)
176129949e86Sstevel {
176229949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
176329949e86Sstevel 	uchar_t tmp_reg;
176429949e86Sstevel 
176529949e86Sstevel 	ASSERT(softsp);
176629949e86Sstevel 
176729949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
176829949e86Sstevel 	*(softsp->csr) |= SYS_AC_PWR_FAIL_EN;
176929949e86Sstevel 	tmp_reg = *(softsp->csr);
177029949e86Sstevel #ifdef lint
177129949e86Sstevel 	tmp_reg = tmp_reg;
177229949e86Sstevel #endif
177329949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
177429949e86Sstevel 
177529949e86Sstevel 	return (DDI_INTR_CLAIMED);
177629949e86Sstevel }
177729949e86Sstevel 
177829949e86Sstevel /*
177929949e86Sstevel  * ps_fail_int_handler
178029949e86Sstevel  *
178129949e86Sstevel  * Handle power supply failure interrupt.
178229949e86Sstevel  *
178329949e86Sstevel  * This wrapper is called as softint from hardware interrupt routine.
178429949e86Sstevel  */
178529949e86Sstevel static uint_t
178629949e86Sstevel ps_fail_int_handler(caddr_t arg)
178729949e86Sstevel {
178829949e86Sstevel 	return (ps_fail_handler((struct sysctrl_soft_state *)arg, 1));
178929949e86Sstevel }
179029949e86Sstevel 
179129949e86Sstevel /*
179229949e86Sstevel  * ps_fail_poll_handler
179329949e86Sstevel  *
179429949e86Sstevel  * Handle power supply failure interrupt.
179529949e86Sstevel  *
179629949e86Sstevel  * This wrapper is called as softint from power supply poll routine.
179729949e86Sstevel  */
179829949e86Sstevel static uint_t
179929949e86Sstevel ps_fail_poll_handler(caddr_t arg)
180029949e86Sstevel {
180129949e86Sstevel 	return (ps_fail_handler((struct sysctrl_soft_state *)arg, 0));
180229949e86Sstevel }
180329949e86Sstevel 
180429949e86Sstevel /*
180529949e86Sstevel  * ps_fail_handler
180629949e86Sstevel  *
180729949e86Sstevel  * This routine checks all eight of the board power supplies that are
180829949e86Sstevel  * installed plus the Peripheral power supply and the two DC OK. Since the
180929949e86Sstevel  * hardware bits are not enough to indicate Power Supply failure
181029949e86Sstevel  * vs. being turned off via software, the driver must maintain a
181129949e86Sstevel  * shadow state for the Power Supply status and monitor all changes.
181229949e86Sstevel  *
181329949e86Sstevel  * Called as a softint only.
181429949e86Sstevel  */
181529949e86Sstevel static uint_t
181629949e86Sstevel ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint)
181729949e86Sstevel {
181829949e86Sstevel 	int i;
181929949e86Sstevel 	struct ps_state *pstatp;
182029949e86Sstevel 	int poll_needed = 0;
182129949e86Sstevel 	uchar_t ps_stat, ps_pres, status1, status2, pppsr;
182229949e86Sstevel 	uchar_t tmp_reg;
182329949e86Sstevel 	enum power_state current_power_state;
182429949e86Sstevel 
182529949e86Sstevel 	ASSERT(softsp);
182629949e86Sstevel 
182729949e86Sstevel 	/* pre-read the hardware state */
182829949e86Sstevel 	ps_stat = *softsp->ps_stat;
182929949e86Sstevel 	ps_pres = *softsp->ps_pres;
183029949e86Sstevel 	status1 = *softsp->status1;
183129949e86Sstevel 	status2 = *softsp->status2;
183229949e86Sstevel 	pppsr	= *softsp->pppsr;
183329949e86Sstevel 
183429949e86Sstevel 	(void) fhc_bdlist_lock(-1);
183529949e86Sstevel 
183629949e86Sstevel 	mutex_enter(&softsp->ps_fail_lock);
183729949e86Sstevel 
183829949e86Sstevel 	for (i = 0, pstatp = &softsp->ps_stats[0]; i < SYS_PS_COUNT;
183929949e86Sstevel 	    i++, pstatp++) {
184029949e86Sstevel 		int	temp_psok;
184129949e86Sstevel 		int	temp_pres;
184229949e86Sstevel 		int	is_precharge = FALSE;
184329949e86Sstevel 		int	is_fan_assy = FALSE;
184429949e86Sstevel 
184529949e86Sstevel 		/*
184629949e86Sstevel 		 * pre-compute the presence and ok bits for this
184729949e86Sstevel 		 * power supply from the hardware registers.
184829949e86Sstevel 		 * NOTE: 4-slot pps1 is the same as core ps 7...
184929949e86Sstevel 		 */
185029949e86Sstevel 		switch (i) {
185129949e86Sstevel 		/* the core power supplies */
185229949e86Sstevel 		case 0: case 1: case 2: case 3:
185329949e86Sstevel 		case 4: case 5: case 6: case 7:
185429949e86Sstevel 			temp_pres = !((ps_pres >> i) & 0x1);
185529949e86Sstevel 			temp_psok = (ps_stat >> i) & 0x1;
185629949e86Sstevel 			break;
185729949e86Sstevel 
185829949e86Sstevel 		/* the first peripheral power supply */
185929949e86Sstevel 		case SYS_PPS0_INDEX:
186029949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
186129949e86Sstevel 			temp_psok = status2 & SYS_PPS0_OK;
186229949e86Sstevel 			break;
186329949e86Sstevel 
186429949e86Sstevel 		/* shared 3.3v clock power */
186529949e86Sstevel 		case SYS_CLK_33_INDEX:
186629949e86Sstevel 			temp_pres = TRUE;
186729949e86Sstevel 			temp_psok = status2 & SYS_CLK_33_OK;
186829949e86Sstevel 			break;
186929949e86Sstevel 
187029949e86Sstevel 		/* shared 5.0v clock power */
187129949e86Sstevel 		case SYS_CLK_50_INDEX:
187229949e86Sstevel 			temp_pres = TRUE;
187329949e86Sstevel 			temp_psok = status2 & SYS_CLK_50_OK;
187429949e86Sstevel 			break;
187529949e86Sstevel 
187629949e86Sstevel 		/* peripheral 5v */
187729949e86Sstevel 		case SYS_V5_P_INDEX:
187829949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES) ||
187929949e86Sstevel 			    ((IS4SLOT(softsp->nslots) ||
188029949e86Sstevel 			    IS5SLOT(softsp->nslots)) &&
188129949e86Sstevel 			    !(ps_pres & SYS_NOT_PPS1_PRES));
188229949e86Sstevel 			temp_psok = pppsr & SYS_V5_P_OK;
188329949e86Sstevel 			break;
188429949e86Sstevel 
188529949e86Sstevel 		/* peripheral 12v */
188629949e86Sstevel 		case SYS_V12_P_INDEX:
188729949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES) ||
188829949e86Sstevel 			    ((IS4SLOT(softsp->nslots) ||
188929949e86Sstevel 			    IS5SLOT(softsp->nslots)) &&
189029949e86Sstevel 			    !(ps_pres & SYS_NOT_PPS1_PRES));
189129949e86Sstevel 			temp_psok = pppsr & SYS_V12_P_OK;
189229949e86Sstevel 			break;
189329949e86Sstevel 
189429949e86Sstevel 		/* aux 5v */
189529949e86Sstevel 		case SYS_V5_AUX_INDEX:
189629949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
189729949e86Sstevel 			temp_psok = pppsr & SYS_V5_AUX_OK;
189829949e86Sstevel 			break;
189929949e86Sstevel 
190029949e86Sstevel 		/* peripheral 5v precharge */
190129949e86Sstevel 		case SYS_V5_P_PCH_INDEX:
190229949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
190329949e86Sstevel 			temp_psok = pppsr & SYS_V5_P_PCH_OK;
190429949e86Sstevel 			is_precharge = TRUE;
190529949e86Sstevel 			break;
190629949e86Sstevel 
190729949e86Sstevel 		/* peripheral 12v precharge */
190829949e86Sstevel 		case SYS_V12_P_PCH_INDEX:
190929949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
191029949e86Sstevel 			temp_psok = pppsr & SYS_V12_P_PCH_OK;
191129949e86Sstevel 			is_precharge = TRUE;
191229949e86Sstevel 			break;
191329949e86Sstevel 
191429949e86Sstevel 		/* 3.3v precharge */
191529949e86Sstevel 		case SYS_V3_PCH_INDEX:
191629949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
191729949e86Sstevel 			temp_psok = pppsr & SYS_V3_PCH_OK;
191829949e86Sstevel 			is_precharge = TRUE;
191929949e86Sstevel 			break;
192029949e86Sstevel 
192129949e86Sstevel 		/* 5v precharge */
192229949e86Sstevel 		case SYS_V5_PCH_INDEX:
192329949e86Sstevel 			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
192429949e86Sstevel 			temp_psok = pppsr & SYS_V5_PCH_OK;
192529949e86Sstevel 			is_precharge = TRUE;
192629949e86Sstevel 			break;
192729949e86Sstevel 
192829949e86Sstevel 		/* peripheral fan assy */
192929949e86Sstevel 		case SYS_P_FAN_INDEX:
193029949e86Sstevel 			temp_pres = (IS4SLOT(softsp->nslots) ||
193129949e86Sstevel 			    IS5SLOT(softsp->nslots)) &&
193229949e86Sstevel 			    !(status1 & SYS_NOT_P_FAN_PRES);
193329949e86Sstevel 			temp_psok = softsp->pps_fan_saved &
193429949e86Sstevel 			    SYS_AC_FAN_OK;
193529949e86Sstevel 			is_fan_assy = TRUE;
193629949e86Sstevel 			break;
193729949e86Sstevel 		}
193829949e86Sstevel 
193929949e86Sstevel 		/* *** Phase 1 -- power supply presence tests *** */
194029949e86Sstevel 
194129949e86Sstevel 		/* do we know the presence status for this power supply? */
194229949e86Sstevel 		if (pstatp->pshadow == PRES_UNKNOWN) {
194329949e86Sstevel 			pstatp->pshadow = temp_pres ? PRES_IN : PRES_OUT;
194429949e86Sstevel 			pstatp->dcshadow = temp_pres ? PS_BOOT : PS_OUT;
194529949e86Sstevel 		} else {
194629949e86Sstevel 			/* has the ps presence state changed? */
194729949e86Sstevel 			if (!temp_pres ^ (pstatp->pshadow == PRES_IN)) {
194829949e86Sstevel 				pstatp->pctr = 0;
194929949e86Sstevel 			} else {
195029949e86Sstevel 				/* a change! are we counting? */
195129949e86Sstevel 				if (pstatp->pctr == 0) {
195229949e86Sstevel 					pstatp->pctr = PS_PRES_CHANGE_TICKS;
195329949e86Sstevel 				} else if (--pstatp->pctr == 0) {
195429949e86Sstevel 					pstatp->pshadow = temp_pres ?
195529949e86Sstevel 					    PRES_IN : PRES_OUT;
195629949e86Sstevel 					pstatp->dcshadow = temp_pres ?
195729949e86Sstevel 					    PS_UNKNOWN : PS_OUT;
195829949e86Sstevel 
195929949e86Sstevel 					/*
196029949e86Sstevel 					 * Now we know the state has
196129949e86Sstevel 					 * changed, so we should log it.
196229949e86Sstevel 					 */
196329949e86Sstevel 					ps_log_pres_change(softsp,
196429949e86Sstevel 					    i, temp_pres);
196529949e86Sstevel 				}
196629949e86Sstevel 			}
196729949e86Sstevel 		}
196829949e86Sstevel 
196929949e86Sstevel 		/* *** Phase 2 -- power supply status tests *** */
197029949e86Sstevel 
197129949e86Sstevel 		/* check if the Power Supply is removed or same as before */
197229949e86Sstevel 		if ((pstatp->dcshadow == PS_OUT) ||
197329949e86Sstevel 		    ((pstatp->dcshadow == PS_OK) && temp_psok) ||
197429949e86Sstevel 		    ((pstatp->dcshadow == PS_FAIL) && !temp_psok)) {
197529949e86Sstevel 			pstatp->dcctr = 0;
197629949e86Sstevel 		} else {
197729949e86Sstevel 
197829949e86Sstevel 			/* OK, a change, do we start the timer? */
197929949e86Sstevel 			if (pstatp->dcctr == 0) {
198029949e86Sstevel 				switch (pstatp->dcshadow) {
198129949e86Sstevel 				case PS_BOOT:
198229949e86Sstevel 					pstatp->dcctr = PS_FROM_BOOT_TICKS;
198329949e86Sstevel 					break;
198429949e86Sstevel 
198529949e86Sstevel 				case PS_UNKNOWN:
198629949e86Sstevel 					pstatp->dcctr = is_fan_assy ?
198729949e86Sstevel 					    PS_P_FAN_FROM_UNKNOWN_TICKS :
198829949e86Sstevel 					    PS_FROM_UNKNOWN_TICKS;
198929949e86Sstevel 					break;
199029949e86Sstevel 
199129949e86Sstevel 				case PS_OK:
199229949e86Sstevel 					pstatp->dcctr = is_precharge ?
199329949e86Sstevel 					    PS_PCH_FROM_OK_TICKS :
199429949e86Sstevel 					    PS_FROM_OK_TICKS;
199529949e86Sstevel 					break;
199629949e86Sstevel 
199729949e86Sstevel 				case PS_FAIL:
199829949e86Sstevel 					pstatp->dcctr = PS_FROM_FAIL_TICKS;
199929949e86Sstevel 					break;
200029949e86Sstevel 
200129949e86Sstevel 				default:
200229949e86Sstevel 					panic("sysctrl%d: Unknown Power "
200329949e86Sstevel 					    "Supply State %d", pstatp->dcshadow,
200429949e86Sstevel 					    ddi_get_instance(softsp->dip));
200529949e86Sstevel 				}
200629949e86Sstevel 			}
200729949e86Sstevel 
200829949e86Sstevel 			/* has the ticker expired? */
200929949e86Sstevel 			if (--pstatp->dcctr == 0) {
201029949e86Sstevel 
201129949e86Sstevel 				/* we'll skip OK messages during boot */
201229949e86Sstevel 				if (!((pstatp->dcshadow == PS_BOOT) &&
201329949e86Sstevel 				    temp_psok)) {
201429949e86Sstevel 					ps_log_state_change(softsp,
201529949e86Sstevel 					    i, temp_psok);
201629949e86Sstevel 				}
201729949e86Sstevel 
201829949e86Sstevel 				/*
201929949e86Sstevel 				 * remote console interface has to be
202029949e86Sstevel 				 * reinitialized on the rising edge V5_AUX
202129949e86Sstevel 				 * when it is NOT boot. At the boot time an
202229949e86Sstevel 				 * an error condition exists if it was not
202329949e86Sstevel 				 * enabled before.
202429949e86Sstevel 				 */
202529949e86Sstevel 				if ((i == SYS_V5_AUX_INDEX) &&
202629949e86Sstevel 				    (pstatp->dcshadow != PS_BOOT) &&
202729949e86Sstevel 				    (softsp->enable_rcons_atboot)) {
202829949e86Sstevel 					if (temp_psok)
202929949e86Sstevel 						rcons_reinit(softsp);
203029949e86Sstevel 					else
203129949e86Sstevel 						/* disable rconsole */
203229949e86Sstevel 						*(softsp->clk_freq2) &=
203329949e86Sstevel 						    ~RCONS_UART_EN;
203429949e86Sstevel 					tmp_reg = *(softsp->csr);
203529949e86Sstevel #ifdef lint
203629949e86Sstevel 					tmp_reg = tmp_reg;
203729949e86Sstevel #endif
203829949e86Sstevel 
203929949e86Sstevel 				}
204029949e86Sstevel 
204129949e86Sstevel 				/* regardless, update the shadow state */
204229949e86Sstevel 				pstatp->dcshadow = temp_psok ? PS_OK : PS_FAIL;
204329949e86Sstevel 
204429949e86Sstevel 				/* always update board condition */
204529949e86Sstevel 				sysc_policy_update(softsp, NULL,
204629949e86Sstevel 				    SYSC_EVT_BD_PS_CHANGE);
204729949e86Sstevel 
204829949e86Sstevel 			}
204929949e86Sstevel 		}
205029949e86Sstevel 
205129949e86Sstevel 		/*
205229949e86Sstevel 		 * We will need to continue polling for three reasons:
205329949e86Sstevel 		 * - a failing power supply is detected and we haven't yet
205429949e86Sstevel 		 *   determined the power supplies existence.
205529949e86Sstevel 		 * - the power supply is just installed and we're waiting
205629949e86Sstevel 		 *   to give it a change to power up,
205729949e86Sstevel 		 * - a failed power supply state is recognized
205829949e86Sstevel 		 *
205929949e86Sstevel 		 * NOTE: PS_FAIL shadow state is not the same as !temp_psok
206029949e86Sstevel 		 * because of the persistence of PS_FAIL->PS_OK.
206129949e86Sstevel 		 */
206229949e86Sstevel 		if (!temp_psok ||
206329949e86Sstevel 		    (pstatp->dcshadow == PS_UNKNOWN) ||
206429949e86Sstevel 		    (pstatp->dcshadow == PS_FAIL)) {
206529949e86Sstevel 			poll_needed++;
206629949e86Sstevel 		}
206729949e86Sstevel 	}
206829949e86Sstevel 
206929949e86Sstevel 	/*
207029949e86Sstevel 	 * Now, get the current power state for this instance.
207129949e86Sstevel 	 * If the current state is different than what was known, complain.
207229949e86Sstevel 	 */
207329949e86Sstevel 	current_power_state = compute_power_state(softsp, 0);
207429949e86Sstevel 
207529949e86Sstevel 	if (softsp->power_state != current_power_state) {
207629949e86Sstevel 		switch (current_power_state) {
207729949e86Sstevel 		case BELOW_MINIMUM:
207829949e86Sstevel 			cmn_err(CE_WARN,
207929949e86Sstevel 			    "Insufficient power available to system");
208029949e86Sstevel 			if (!disable_insufficient_power_reboot) {
208129949e86Sstevel 				cmn_err(CE_WARN, "System reboot in %d seconds",
208229949e86Sstevel 				    PS_INSUFFICIENT_COUNTDOWN_SEC);
208329949e86Sstevel 			}
208429949e86Sstevel 			reg_fault(1, FT_INSUFFICIENT_POWER, FT_SYSTEM);
208529949e86Sstevel 			softsp->power_countdown = PS_POWER_COUNTDOWN_TICKS;
208629949e86Sstevel 			break;
208729949e86Sstevel 
208829949e86Sstevel 		case MINIMUM:
208929949e86Sstevel 			/* If we came from REDUNDANT, complain */
209029949e86Sstevel 			if (softsp->power_state == REDUNDANT) {
209129949e86Sstevel 				cmn_err(CE_WARN, "Redundant power lost");
209229949e86Sstevel 			/* If we came from BELOW_MINIMUM, hurrah! */
209329949e86Sstevel 			} else if (softsp->power_state == BELOW_MINIMUM) {
209429949e86Sstevel 				cmn_err(CE_NOTE, "Minimum power available");
209529949e86Sstevel 				clear_fault(1, FT_INSUFFICIENT_POWER,
209629949e86Sstevel 				    FT_SYSTEM);
209729949e86Sstevel 			}
209829949e86Sstevel 			break;
209929949e86Sstevel 
210029949e86Sstevel 		case REDUNDANT:
210129949e86Sstevel 			/* If we aren't from boot, spread the good news */
210229949e86Sstevel 			if (softsp->power_state != BOOT) {
210329949e86Sstevel 				cmn_err(CE_NOTE, "Redundant power available");
210429949e86Sstevel 				clear_fault(1, FT_INSUFFICIENT_POWER,
210529949e86Sstevel 				    FT_SYSTEM);
210629949e86Sstevel 			}
210729949e86Sstevel 			break;
210829949e86Sstevel 
210929949e86Sstevel 		default:
211029949e86Sstevel 			break;
211129949e86Sstevel 		}
211229949e86Sstevel 		softsp->power_state = current_power_state;
211329949e86Sstevel 		sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
211429949e86Sstevel 	}
211529949e86Sstevel 
211629949e86Sstevel 	mutex_exit(&softsp->ps_fail_lock);
211729949e86Sstevel 
211829949e86Sstevel 	fhc_bdlist_unlock();
211929949e86Sstevel 
212029949e86Sstevel 	/*
212129949e86Sstevel 	 * Are we in insufficient powerstate?
212229949e86Sstevel 	 * If so, is it time to take action?
212329949e86Sstevel 	 */
212429949e86Sstevel 	if (softsp->power_state == BELOW_MINIMUM &&
212529949e86Sstevel 	    softsp->power_countdown > 0 && --(softsp->power_countdown) == 0 &&
212629949e86Sstevel 	    !disable_insufficient_power_reboot) {
212729949e86Sstevel 		cmn_err(CE_WARN,
212829949e86Sstevel 		    "Insufficient power. System Reboot Started...");
212929949e86Sstevel 
213029949e86Sstevel 		fhc_reboot();
213129949e86Sstevel 	}
213229949e86Sstevel 
213329949e86Sstevel 	/*
213429949e86Sstevel 	 * If we don't have ps problems that need to be polled for, then
213529949e86Sstevel 	 * enable interrupts.
213629949e86Sstevel 	 */
213729949e86Sstevel 	if (!poll_needed) {
213829949e86Sstevel 		mutex_enter(&softsp->csr_mutex);
213929949e86Sstevel 		*(softsp->csr) |= SYS_PS_FAIL_EN;
214029949e86Sstevel 		tmp_reg = *(softsp->csr);
214129949e86Sstevel #ifdef lint
214229949e86Sstevel 		tmp_reg = tmp_reg;
214329949e86Sstevel #endif
214429949e86Sstevel 		mutex_exit(&softsp->csr_mutex);
214529949e86Sstevel 	}
214629949e86Sstevel 
214729949e86Sstevel 	/*
214829949e86Sstevel 	 * Only the polling loop re-triggers the polling loop timeout
214929949e86Sstevel 	 */
215029949e86Sstevel 	if (!fromint) {
215129949e86Sstevel 		(void) timeout(ps_fail_retry, softsp, ps_fail_timeout_hz);
215229949e86Sstevel 	}
215329949e86Sstevel 
215429949e86Sstevel 	return (DDI_INTR_CLAIMED);
215529949e86Sstevel }
215629949e86Sstevel 
215729949e86Sstevel /*
215829949e86Sstevel  * Compute the current power configuration for this system.
215929949e86Sstevel  * Disk boards and Clock boards are not counted.
216029949e86Sstevel  *
216129949e86Sstevel  * This function must be called with the ps_fail_lock held.
216229949e86Sstevel  */
216329949e86Sstevel enum power_state
216429949e86Sstevel compute_power_state(struct sysctrl_soft_state *softsp, int plus_load)
216529949e86Sstevel {
216629949e86Sstevel 	int i;
216729949e86Sstevel 	int ok_supply_count = 0;
216829949e86Sstevel 	int load_count = 0;
216929949e86Sstevel 	int minimum_power_count;
217029949e86Sstevel 	int pps_ok;
217129949e86Sstevel 	fhc_bd_t *list;
217229949e86Sstevel 
217329949e86Sstevel 	ASSERT(mutex_owned(&softsp->ps_fail_lock));
217429949e86Sstevel 
217529949e86Sstevel 	/*
217629949e86Sstevel 	 * Walk down the interesting power supplies and
217729949e86Sstevel 	 * count the operational power units
217829949e86Sstevel 	 */
217929949e86Sstevel 	for (i = 0; i < 8; i++) {
218029949e86Sstevel 		/*
218129949e86Sstevel 		 * power supply id 7 on a 4 or 5 slot system is PPS1.
218229949e86Sstevel 		 * don't include it in the redundant core power calculation.
218329949e86Sstevel 		 */
218429949e86Sstevel 		if (i == 7 &&
218529949e86Sstevel 		    (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)))
218629949e86Sstevel 			continue;
218729949e86Sstevel 
218829949e86Sstevel 		if (softsp->ps_stats[i].dcshadow == PS_OK)
218929949e86Sstevel 			ok_supply_count++;
219029949e86Sstevel 	}
219129949e86Sstevel 
219229949e86Sstevel 	/* Note the state of the PPS... */
219329949e86Sstevel 	pps_ok = (softsp->ps_stats[SYS_PPS0_INDEX].dcshadow == PS_OK);
219429949e86Sstevel 
219529949e86Sstevel 	/*
219629949e86Sstevel 	 * Dynamically compute the load count in the system.
219729949e86Sstevel 	 * Don't count disk boards or boards in low power state.
219829949e86Sstevel 	 */
219929949e86Sstevel 	for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) {
220029949e86Sstevel 		ASSERT(list->sc.type != CLOCK_BOARD);
220129949e86Sstevel 		if (list->sc.rstate == SYSC_CFGA_RSTATE_CONNECTED) {
220229949e86Sstevel 			load_count++;
220329949e86Sstevel 		}
220429949e86Sstevel 	}
220529949e86Sstevel 
220629949e86Sstevel 	load_count += plus_load;
220729949e86Sstevel 	/*
220829949e86Sstevel 	 * If we are 8 slot and we have 7 or 8 boards, then the PPS
220929949e86Sstevel 	 * can count as a power supply...
221029949e86Sstevel 	 */
221129949e86Sstevel 	if (IS8SLOT(softsp->nslots) && load_count >= 7 && pps_ok)
221229949e86Sstevel 		ok_supply_count++;
221329949e86Sstevel 
221429949e86Sstevel 	/*
221529949e86Sstevel 	 * This is to cover the corner case of a UE3500 having 5
221629949e86Sstevel 	 * boards installed and still giving it N+1 power status.
221729949e86Sstevel 	 */
221829949e86Sstevel 	if (IS5SLOT(softsp->nslots) && (load_count >= 5))
221929949e86Sstevel 		ok_supply_count++;
222029949e86Sstevel 
222129949e86Sstevel 	/*
222229949e86Sstevel 	 * Determine our power situation.  This is a simple step
222329949e86Sstevel 	 * function right now:
222429949e86Sstevel 	 *
222529949e86Sstevel 	 * minimum power count = min(7, floor((board count + 1) / 2))
222629949e86Sstevel 	 */
222729949e86Sstevel 	minimum_power_count = (load_count + 1) / 2;
222829949e86Sstevel 	if (minimum_power_count > 7)
222929949e86Sstevel 		minimum_power_count = 7;
223029949e86Sstevel 
223129949e86Sstevel 	if (ok_supply_count > minimum_power_count)
223229949e86Sstevel 		return (REDUNDANT);
223329949e86Sstevel 	else if (ok_supply_count == minimum_power_count)
223429949e86Sstevel 		return (MINIMUM);
223529949e86Sstevel 	else
223629949e86Sstevel 		return (BELOW_MINIMUM);
223729949e86Sstevel }
223829949e86Sstevel 
223929949e86Sstevel /*
224029949e86Sstevel  * log the change of power supply presence
224129949e86Sstevel  */
224229949e86Sstevel static void
224329949e86Sstevel ps_log_pres_change(struct sysctrl_soft_state *softsp, int index, int present)
224429949e86Sstevel {
224529949e86Sstevel 	char	*trans = present ? "Installed" : "Removed";
224629949e86Sstevel 
224729949e86Sstevel 	switch (index) {
224829949e86Sstevel 	/* the core power supplies (except for 7) */
224929949e86Sstevel 	case 0: case 1: case 2: case 3:
225029949e86Sstevel 	case 4: case 5: case 6:
225129949e86Sstevel 		cmn_err(CE_NOTE, "%s %d %s", ft_str_table[FT_CORE_PS], index,
225229949e86Sstevel 		    trans);
225329949e86Sstevel 		if (!present) {
225429949e86Sstevel 			clear_fault(index, FT_CORE_PS, FT_SYSTEM);
225529949e86Sstevel 			sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
225629949e86Sstevel 		}
225729949e86Sstevel 		break;
225829949e86Sstevel 
225929949e86Sstevel 	/* power supply 7 / pps 1 */
226029949e86Sstevel 	case 7:
226129949e86Sstevel 		if (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)) {
226219397407SSherry Moore 			cmn_err(CE_NOTE, "%s 1 %s", ft_str_table[FT_PPS],
226319397407SSherry Moore 			    trans);
226429949e86Sstevel 			if (!present) {
226529949e86Sstevel 			clear_fault(1, FT_PPS, FT_SYSTEM);
226629949e86Sstevel 			}
226729949e86Sstevel 		} else {
226829949e86Sstevel 			cmn_err(CE_NOTE, "%s %d %s", ft_str_table[FT_CORE_PS],
226929949e86Sstevel 			    index, trans);
227029949e86Sstevel 			if (!present) {
227129949e86Sstevel 			clear_fault(7, FT_CORE_PS, FT_SYSTEM);
227229949e86Sstevel 			sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
227329949e86Sstevel 			}
227429949e86Sstevel 		}
227529949e86Sstevel 		break;
227629949e86Sstevel 
227729949e86Sstevel 	/* the peripheral power supply 0 */
227829949e86Sstevel 	case SYS_PPS0_INDEX:
227929949e86Sstevel 		cmn_err(CE_NOTE, "%s 0 %s", ft_str_table[FT_PPS], trans);
228029949e86Sstevel 		if (!present) {
228129949e86Sstevel 			clear_fault(0, FT_PPS, FT_SYSTEM);
228229949e86Sstevel 			sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
228329949e86Sstevel 		}
228429949e86Sstevel 		break;
228529949e86Sstevel 
228629949e86Sstevel 	/* the peripheral rack fan assy */
228729949e86Sstevel 	case SYS_P_FAN_INDEX:
228829949e86Sstevel 		cmn_err(CE_NOTE, "%s %s", ft_str_table[FT_PPS_FAN], trans);
228929949e86Sstevel 		if (!present) {
229029949e86Sstevel 			clear_fault(0, FT_PPS_FAN, FT_SYSTEM);
229129949e86Sstevel 		}
229229949e86Sstevel 		break;
229329949e86Sstevel 
229429949e86Sstevel 	/* we don't mention a change of presence state for any other power */
229529949e86Sstevel 	}
229629949e86Sstevel }
229729949e86Sstevel 
229829949e86Sstevel /*
229929949e86Sstevel  * log the change of power supply status
230029949e86Sstevel  */
230129949e86Sstevel static void
230229949e86Sstevel ps_log_state_change(struct sysctrl_soft_state *softsp, int index, int ps_ok)
230329949e86Sstevel {
230429949e86Sstevel 	int level = ps_ok ? CE_NOTE : CE_WARN;
230529949e86Sstevel 	char *s = ps_ok ? "OK" : "Failing";
230629949e86Sstevel 
230729949e86Sstevel 	switch (index) {
230829949e86Sstevel 	/* the core power supplies (except 7) */
230929949e86Sstevel 	case 0: case 1: case 2: case 3:
231029949e86Sstevel 	case 4: case 5: case 6:
231129949e86Sstevel 		cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS], index, s);
231229949e86Sstevel 		if (ps_ok) {
231329949e86Sstevel 			clear_fault(index, FT_CORE_PS, FT_SYSTEM);
231429949e86Sstevel 		} else {
231529949e86Sstevel 			reg_fault(index, FT_CORE_PS, FT_SYSTEM);
231629949e86Sstevel 		}
231729949e86Sstevel 		break;
231829949e86Sstevel 
231929949e86Sstevel 	/* power supply 7 / pps 1 */
232029949e86Sstevel 	case 7:
232129949e86Sstevel 		if (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)) {
232229949e86Sstevel 			cmn_err(level, "%s 1 %s", ft_str_table[FT_PPS], s);
232329949e86Sstevel 			if (ps_ok) {
232429949e86Sstevel 				clear_fault(1, FT_PPS, FT_SYSTEM);
232529949e86Sstevel 			} else {
232629949e86Sstevel 				reg_fault(1, FT_PPS, FT_SYSTEM);
232729949e86Sstevel 			}
232829949e86Sstevel 		} else {
232929949e86Sstevel 			cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS],
233029949e86Sstevel 			    index, s);
233129949e86Sstevel 			if (ps_ok) {
233229949e86Sstevel 				clear_fault(index, FT_CORE_PS, FT_SYSTEM);
233329949e86Sstevel 			} else {
233429949e86Sstevel 				reg_fault(index, FT_CORE_PS, FT_SYSTEM);
233529949e86Sstevel 			}
233629949e86Sstevel 		}
233729949e86Sstevel 		break;
233829949e86Sstevel 
233929949e86Sstevel 	/* the peripheral power supply */
234029949e86Sstevel 	case SYS_PPS0_INDEX:
234129949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_PPS], s);
234229949e86Sstevel 		if (ps_ok) {
234329949e86Sstevel 			clear_fault(0, FT_PPS, FT_SYSTEM);
234429949e86Sstevel 		} else {
234529949e86Sstevel 			reg_fault(0, FT_PPS, FT_SYSTEM);
234629949e86Sstevel 		}
234729949e86Sstevel 		break;
234829949e86Sstevel 
234929949e86Sstevel 	/* shared 3.3v clock power */
235029949e86Sstevel 	case SYS_CLK_33_INDEX:
235129949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_CLK_33], s);
235229949e86Sstevel 		if (ps_ok) {
235329949e86Sstevel 			clear_fault(0, FT_CLK_33, FT_SYSTEM);
235429949e86Sstevel 		} else {
235529949e86Sstevel 			reg_fault(0, FT_CLK_33, FT_SYSTEM);
235629949e86Sstevel 		}
235729949e86Sstevel 		break;
235829949e86Sstevel 
235929949e86Sstevel 	/* shared 5.0v clock power */
236029949e86Sstevel 	case SYS_CLK_50_INDEX:
236129949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_CLK_50], s);
236229949e86Sstevel 		if (ps_ok) {
236329949e86Sstevel 			clear_fault(0, FT_CLK_50, FT_SYSTEM);
236429949e86Sstevel 		} else {
236529949e86Sstevel 			reg_fault(0, FT_CLK_50, FT_SYSTEM);
236629949e86Sstevel 		}
236729949e86Sstevel 		break;
236829949e86Sstevel 
236929949e86Sstevel 	/* peripheral 5v */
237029949e86Sstevel 	case SYS_V5_P_INDEX:
237129949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V5_P], s);
237229949e86Sstevel 		if (ps_ok) {
237329949e86Sstevel 			clear_fault(0, FT_V5_P, FT_SYSTEM);
237429949e86Sstevel 		} else {
237529949e86Sstevel 			reg_fault(0, FT_V5_P, FT_SYSTEM);
237629949e86Sstevel 		}
237729949e86Sstevel 		break;
237829949e86Sstevel 
237929949e86Sstevel 	/* peripheral 12v */
238029949e86Sstevel 	case SYS_V12_P_INDEX:
238129949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V12_P], s);
238229949e86Sstevel 		if (ps_ok) {
238329949e86Sstevel 			clear_fault(0, FT_V12_P, FT_SYSTEM);
238429949e86Sstevel 		} else {
238529949e86Sstevel 			reg_fault(0, FT_V12_P, FT_SYSTEM);
238629949e86Sstevel 		}
238729949e86Sstevel 		break;
238829949e86Sstevel 
238929949e86Sstevel 	/* aux 5v */
239029949e86Sstevel 	case SYS_V5_AUX_INDEX:
239129949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V5_AUX], s);
239229949e86Sstevel 		if (ps_ok) {
239329949e86Sstevel 			clear_fault(0, FT_V5_AUX, FT_SYSTEM);
239429949e86Sstevel 		} else {
239529949e86Sstevel 			reg_fault(0, FT_V5_AUX, FT_SYSTEM);
239629949e86Sstevel 		}
239729949e86Sstevel 		break;
239829949e86Sstevel 
239929949e86Sstevel 	/* peripheral 5v precharge */
240029949e86Sstevel 	case SYS_V5_P_PCH_INDEX:
240129949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V5_P_PCH], s);
240229949e86Sstevel 		if (ps_ok) {
240329949e86Sstevel 			clear_fault(0, FT_V5_P_PCH, FT_SYSTEM);
240429949e86Sstevel 		} else {
240529949e86Sstevel 			reg_fault(0, FT_V5_P_PCH, FT_SYSTEM);
240629949e86Sstevel 		}
240729949e86Sstevel 		break;
240829949e86Sstevel 
240929949e86Sstevel 	/* peripheral 12v precharge */
241029949e86Sstevel 	case SYS_V12_P_PCH_INDEX:
241129949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V12_P_PCH], s);
241229949e86Sstevel 		if (ps_ok) {
241329949e86Sstevel 			clear_fault(0, FT_V12_P_PCH, FT_SYSTEM);
241429949e86Sstevel 		} else {
241529949e86Sstevel 			reg_fault(0, FT_V12_P_PCH, FT_SYSTEM);
241629949e86Sstevel 		}
241729949e86Sstevel 		break;
241829949e86Sstevel 
241929949e86Sstevel 	/* 3.3v precharge */
242029949e86Sstevel 	case SYS_V3_PCH_INDEX:
242129949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V3_PCH], s);
242229949e86Sstevel 		if (ps_ok) {
242329949e86Sstevel 			clear_fault(0, FT_V3_PCH, FT_SYSTEM);
242429949e86Sstevel 		} else {
242529949e86Sstevel 			reg_fault(0, FT_V3_PCH, FT_SYSTEM);
242629949e86Sstevel 		}
242729949e86Sstevel 		break;
242829949e86Sstevel 
242929949e86Sstevel 	/* 5v precharge */
243029949e86Sstevel 	case SYS_V5_PCH_INDEX:
243129949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_V5_PCH], s);
243229949e86Sstevel 		if (ps_ok) {
243329949e86Sstevel 			clear_fault(0, FT_V5_PCH, FT_SYSTEM);
243429949e86Sstevel 		} else {
243529949e86Sstevel 			reg_fault(0, FT_V5_PCH, FT_SYSTEM);
243629949e86Sstevel 		}
243729949e86Sstevel 		break;
243829949e86Sstevel 
243929949e86Sstevel 	/* peripheral power supply fans */
244029949e86Sstevel 	case SYS_P_FAN_INDEX:
244129949e86Sstevel 		cmn_err(level, "%s %s", ft_str_table[FT_PPS_FAN], s);
244229949e86Sstevel 		if (ps_ok) {
244329949e86Sstevel 			clear_fault(0, FT_PPS_FAN, FT_SYSTEM);
244429949e86Sstevel 		} else {
244529949e86Sstevel 			reg_fault(0, FT_PPS_FAN, FT_SYSTEM);
244629949e86Sstevel 		}
244729949e86Sstevel 		break;
244829949e86Sstevel 	}
244929949e86Sstevel }
245029949e86Sstevel 
245129949e86Sstevel /*
245229949e86Sstevel  * The timeout from ps_fail_handler() that simply re-triggers a check
245329949e86Sstevel  * of the ps condition.
245429949e86Sstevel  */
245529949e86Sstevel static void
245629949e86Sstevel ps_fail_retry(void *arg)
245729949e86Sstevel {
245829949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
245929949e86Sstevel 
246029949e86Sstevel 	ASSERT(softsp);
246129949e86Sstevel 
246229949e86Sstevel 	ddi_trigger_softintr(softsp->ps_fail_poll_id);
246329949e86Sstevel }
246429949e86Sstevel 
246529949e86Sstevel /*
246629949e86Sstevel  * pps_fanfail_handler
246729949e86Sstevel  *
246829949e86Sstevel  * This routine is called from the high level handler.
246929949e86Sstevel  */
247029949e86Sstevel static uint_t
247129949e86Sstevel pps_fanfail_handler(caddr_t arg)
247229949e86Sstevel {
247329949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
247429949e86Sstevel 
247529949e86Sstevel 	ASSERT(softsp);
247629949e86Sstevel 
247729949e86Sstevel 	/* always check again in a bit by re-enabling the fan interrupt */
247829949e86Sstevel 	(void) timeout(pps_fanfail_retry, softsp, pps_fan_timeout_hz);
247929949e86Sstevel 
248029949e86Sstevel 	return (DDI_INTR_CLAIMED);
248129949e86Sstevel }
248229949e86Sstevel 
248329949e86Sstevel /*
248429949e86Sstevel  * After a bit of waiting, we simply re-enable the interrupt to
248529949e86Sstevel  * see if we get another one.  The softintr triggered routine does
248629949e86Sstevel  * the dirty work for us since it runs in the interrupt context.
248729949e86Sstevel  */
248829949e86Sstevel static void
248929949e86Sstevel pps_fanfail_retry(void *arg)
249029949e86Sstevel {
249129949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
249229949e86Sstevel 
249329949e86Sstevel 	ASSERT(softsp);
249429949e86Sstevel 
249529949e86Sstevel 	ddi_trigger_softintr(softsp->pps_fan_high_id);
249629949e86Sstevel }
249729949e86Sstevel 
249829949e86Sstevel /*
249929949e86Sstevel  * The other half of the retry handler run from the interrupt context
250029949e86Sstevel  */
250129949e86Sstevel static uint_t
250229949e86Sstevel pps_fanfail_reenable(caddr_t arg)
250329949e86Sstevel {
250429949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
250529949e86Sstevel 	uchar_t tmp_reg;
250629949e86Sstevel 
250729949e86Sstevel 	ASSERT(softsp);
250829949e86Sstevel 
250929949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
251029949e86Sstevel 
251129949e86Sstevel 	/*
251229949e86Sstevel 	 * re-initialize the bit field for all pps fans to assumed good.
251329949e86Sstevel 	 * If the fans are still bad, we're going to get an immediate system
251429949e86Sstevel 	 * interrupt which will put the correct state back anyway.
251529949e86Sstevel 	 *
251629949e86Sstevel 	 * NOTE: the polling routines that use this state understand the
251729949e86Sstevel 	 * pulse resulting from above...
251829949e86Sstevel 	 */
251929949e86Sstevel 	softsp->pps_fan_saved = SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK;
252029949e86Sstevel 
252129949e86Sstevel 	*(softsp->csr) |= SYS_PPS_FAN_FAIL_EN;
252229949e86Sstevel 	tmp_reg = *(softsp->csr);
252329949e86Sstevel #ifdef lint
252429949e86Sstevel 	tmp_reg = tmp_reg;
252529949e86Sstevel #endif
252629949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
252729949e86Sstevel 
252829949e86Sstevel 	return (DDI_INTR_CLAIMED);
252929949e86Sstevel }
253029949e86Sstevel 
253129949e86Sstevel /*
253229949e86Sstevel  *
253329949e86Sstevel  * Poll the hardware shadow state to determine the pps fan status.
253429949e86Sstevel  * The shadow state is maintained by the system_high handler and its
253529949e86Sstevel  * associated pps_* functions (above).
253629949e86Sstevel  *
253729949e86Sstevel  * There is a short time interval where the shadow state is pulsed to
253829949e86Sstevel  * the OK state even when the fans are bad.  However, this polling
253929949e86Sstevel  * routine has some built in hysteresis to filter out those _normal_
254029949e86Sstevel  * events.
254129949e86Sstevel  */
254229949e86Sstevel static void
254329949e86Sstevel pps_fan_poll(void *arg)
254429949e86Sstevel {
254529949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
254629949e86Sstevel 	int i;
254729949e86Sstevel 
254829949e86Sstevel 	ASSERT(softsp);
254929949e86Sstevel 
255029949e86Sstevel 	for (i = 0; i < SYS_PPS_FAN_COUNT; i++) {
255129949e86Sstevel 		int fanfail = FALSE;
255229949e86Sstevel 
255329949e86Sstevel 		/* determine fan status */
255429949e86Sstevel 		switch (i) {
255529949e86Sstevel 		case RACK:
255629949e86Sstevel 			fanfail = softsp->pps_fan_saved & SYS_RACK_FANFAIL;
255729949e86Sstevel 			break;
255829949e86Sstevel 
255929949e86Sstevel 		case AC:
256029949e86Sstevel 			/*
256129949e86Sstevel 			 * Don't bother polling the AC fan on 4 and 5 slot
256229949e86Sstevel 			 * systems.
256329949e86Sstevel 			 * Rather, it is handled by the power supply loop.
256429949e86Sstevel 			 */
256529949e86Sstevel 			fanfail = !(IS4SLOT(softsp->nslots) ||
256629949e86Sstevel 			    IS5SLOT(softsp->nslots)) &&
256729949e86Sstevel 			    !(softsp->pps_fan_saved & SYS_AC_FAN_OK);
256829949e86Sstevel 			break;
256929949e86Sstevel 
257029949e86Sstevel 		case KEYSW:
257129949e86Sstevel 			/*
257229949e86Sstevel 			 * This signal is not usable if aux5v is missing
257329949e86Sstevel 			 * so we will synthesize a failed fan when aux5v
257429949e86Sstevel 			 * fails or when pps0 is out.
257529949e86Sstevel 			 * The 4 and 5 slot systems behave the same.
257629949e86Sstevel 			 */
257729949e86Sstevel 			fanfail = (!(IS4SLOT(softsp->nslots) ||
257829949e86Sstevel 			    IS5SLOT(softsp->nslots)) &&
257929949e86Sstevel 			    (softsp->ps_stats[SYS_V5_AUX_INDEX].dcshadow !=
258029949e86Sstevel 			    PS_OK)) ||
258129949e86Sstevel 			    !(softsp->pps_fan_saved & SYS_KEYSW_FAN_OK);
258229949e86Sstevel 			break;
258329949e86Sstevel 
258429949e86Sstevel 		}
258529949e86Sstevel 
258629949e86Sstevel 		/* is the fan bad? */
258729949e86Sstevel 		if (fanfail) {
258829949e86Sstevel 
258929949e86Sstevel 			/* is this condition different than we know? */
259029949e86Sstevel 			if (softsp->pps_fan_state_count[i] == 0) {
259129949e86Sstevel 
259229949e86Sstevel 				/* log the change to failed */
259329949e86Sstevel 				pps_fan_state_change(softsp, i, FALSE);
259429949e86Sstevel 			}
259529949e86Sstevel 
259629949e86Sstevel 			/* always restart the fan OK counter */
259729949e86Sstevel 			softsp->pps_fan_state_count[i] = PPS_FROM_FAIL_TICKS;
259829949e86Sstevel 		} else {
259929949e86Sstevel 
260029949e86Sstevel 			/* do we currently know the fan is bad? */
260129949e86Sstevel 			if (softsp->pps_fan_state_count[i]) {
260229949e86Sstevel 
260329949e86Sstevel 				/* yes, but has it been stable? */
260429949e86Sstevel 				if (--softsp->pps_fan_state_count[i] == 0) {
260529949e86Sstevel 
260629949e86Sstevel 					/* log the change to OK */
260729949e86Sstevel 					pps_fan_state_change(softsp, i, TRUE);
260829949e86Sstevel 				}
260929949e86Sstevel 			}
261029949e86Sstevel 		}
261129949e86Sstevel 	}
261229949e86Sstevel 
261329949e86Sstevel 	/* always check again in a bit by re-enabling the fan interrupt */
261429949e86Sstevel 	(void) timeout(pps_fan_poll, softsp, pps_fan_timeout_hz);
261529949e86Sstevel }
261629949e86Sstevel 
261729949e86Sstevel /*
261829949e86Sstevel  * pps_fan_state_change()
261929949e86Sstevel  *
262029949e86Sstevel  * Log the changed fan condition and update the external status.
262129949e86Sstevel  */
262229949e86Sstevel static void
262329949e86Sstevel pps_fan_state_change(struct sysctrl_soft_state *softsp, int index, int fan_ok)
262429949e86Sstevel {
262529949e86Sstevel 	char *fan_type;
262629949e86Sstevel 	char *state = fan_ok ? "fans OK" : "fan failure detected";
262729949e86Sstevel 
262829949e86Sstevel 	switch (index) {
262929949e86Sstevel 	case RACK:
263029949e86Sstevel 		/* 4 and 5 slot systems behave the same */
263129949e86Sstevel 		fan_type = (IS4SLOT(softsp->nslots) ||
263229949e86Sstevel 		    IS5SLOT(softsp->nslots)) ?
263329949e86Sstevel 		    "Disk Drive" : "Rack Exhaust";
263429949e86Sstevel 		if (fan_ok) {
263529949e86Sstevel 			softsp->pps_fan_external_state &= ~SYS_RACK_FANFAIL;
263629949e86Sstevel 			clear_fault(0, (IS4SLOT(softsp->nslots) ||
263729949e86Sstevel 			    IS5SLOT(softsp->nslots)) ? FT_DSK_FAN :
263829949e86Sstevel 			    FT_RACK_EXH, FT_SYSTEM);
263929949e86Sstevel 		} else {
264029949e86Sstevel 			softsp->pps_fan_external_state |= SYS_RACK_FANFAIL;
264129949e86Sstevel 			reg_fault(0, (IS4SLOT(softsp->nslots) ||
264229949e86Sstevel 			    IS5SLOT(softsp->nslots)) ? FT_DSK_FAN :
264329949e86Sstevel 			    FT_RACK_EXH, FT_SYSTEM);
264429949e86Sstevel 		}
264529949e86Sstevel 		break;
264629949e86Sstevel 
264729949e86Sstevel 	case AC:
264829949e86Sstevel 		fan_type = "AC Box";
264929949e86Sstevel 		if (fan_ok) {
265029949e86Sstevel 			softsp->pps_fan_external_state |= SYS_AC_FAN_OK;
265129949e86Sstevel 			clear_fault(0, FT_AC_FAN, FT_SYSTEM);
265229949e86Sstevel 		} else {
265329949e86Sstevel 			softsp->pps_fan_external_state &= ~SYS_AC_FAN_OK;
265429949e86Sstevel 			reg_fault(0, FT_AC_FAN, FT_SYSTEM);
265529949e86Sstevel 		}
265629949e86Sstevel 		break;
265729949e86Sstevel 
265829949e86Sstevel 	case KEYSW:
265929949e86Sstevel 		fan_type = "Keyswitch";
266029949e86Sstevel 		if (fan_ok) {
266129949e86Sstevel 			softsp->pps_fan_external_state |= SYS_KEYSW_FAN_OK;
266229949e86Sstevel 			clear_fault(0, FT_KEYSW_FAN, FT_SYSTEM);
266329949e86Sstevel 		} else {
266429949e86Sstevel 			softsp->pps_fan_external_state &= ~SYS_KEYSW_FAN_OK;
266529949e86Sstevel 			reg_fault(0, FT_KEYSW_FAN, FT_SYSTEM);
266629949e86Sstevel 		}
266729949e86Sstevel 		break;
266829949e86Sstevel 	default:
266929949e86Sstevel 		fan_type = "[invalid fan id]";
267029949e86Sstevel 		break;
267129949e86Sstevel 	}
267229949e86Sstevel 
267329949e86Sstevel 	/* now log the state change */
267429949e86Sstevel 	cmn_err(fan_ok ? CE_NOTE : CE_WARN, "%s %s", fan_type, state);
267529949e86Sstevel }
267629949e86Sstevel 
267729949e86Sstevel static uint_t
267829949e86Sstevel bd_insert_handler(caddr_t arg)
267929949e86Sstevel {
268029949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
268129949e86Sstevel 
268229949e86Sstevel 	ASSERT(softsp);
268329949e86Sstevel 
268429949e86Sstevel 	DPRINTF(SYSCTRL_ATTACH_DEBUG, ("bd_insert_handler()"));
268529949e86Sstevel 
268629949e86Sstevel 	(void) timeout(bd_insert_timeout, softsp, bd_insert_delay_hz);
268729949e86Sstevel 
268829949e86Sstevel 	return (DDI_INTR_CLAIMED);
268929949e86Sstevel }
269029949e86Sstevel 
269129949e86Sstevel void
269229949e86Sstevel bd_remove_poll(struct sysctrl_soft_state *softsp)
269329949e86Sstevel {
269429949e86Sstevel 	ASSERT(fhc_bdlist_locked());
269529949e86Sstevel 
269629949e86Sstevel 	if (!bd_remove_to_id) {
269729949e86Sstevel 		bd_remove_to_id = timeout(bd_remove_timeout, softsp,
269829949e86Sstevel 		    bd_remove_timeout_hz);
269929949e86Sstevel 	} else {
270029949e86Sstevel 		DPRINTF(SYSCTRL_ATTACH_DEBUG,
270129949e86Sstevel 		    ("bd_remove_poll ignoring start request"));
270229949e86Sstevel 	}
270329949e86Sstevel }
270429949e86Sstevel 
270529949e86Sstevel /*
270629949e86Sstevel  * bd_insert_timeout()
270729949e86Sstevel  *
270829949e86Sstevel  * This routine handles the board insert interrupt. It is called from a
270929949e86Sstevel  * timeout so that it does not run at interrupt level. The main job
271029949e86Sstevel  * of this routine is to find hotplugged boards and de-assert the
271129949e86Sstevel  * board insert interrupt coming from the board. For hotplug phase I,
271229949e86Sstevel  * the routine also powers down the board.
271329949e86Sstevel  * JTAG scan is used to find boards which have been inserted.
271429949e86Sstevel  * All other control of the boards is also done by JTAG scan.
271529949e86Sstevel  */
271629949e86Sstevel static void
271729949e86Sstevel bd_insert_timeout(void *arg)
271829949e86Sstevel {
271929949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
272029949e86Sstevel 	int found;
272129949e86Sstevel 
272229949e86Sstevel 	ASSERT(softsp);
272329949e86Sstevel 
272429949e86Sstevel 	if (sysctrl_hotplug_disabled) {
272529949e86Sstevel 		sysc_policy_update(softsp, NULL, SYSC_EVT_BD_HP_DISABLED);
272629949e86Sstevel 	} else {
272729949e86Sstevel 		/*
272829949e86Sstevel 		 * Lock the board list mutex. Keep it locked until all work
272929949e86Sstevel 		 * is done.
273029949e86Sstevel 		 */
273129949e86Sstevel 		(void) fhc_bdlist_lock(-1);
273229949e86Sstevel 
273329949e86Sstevel 		found = fhc_bd_insert_scan();
273429949e86Sstevel 
273529949e86Sstevel 		if (found) {
273629949e86Sstevel 			DPRINTF(SYSCTRL_ATTACH_DEBUG,
273729949e86Sstevel 			    ("bd_insert_timeout starting bd_remove_poll()"));
273829949e86Sstevel 			bd_remove_poll(softsp);
273929949e86Sstevel 		}
274029949e86Sstevel 
274129949e86Sstevel 		fhc_bdlist_unlock();
274229949e86Sstevel 	}
274329949e86Sstevel 
274429949e86Sstevel 	/*
274529949e86Sstevel 	 * Enable interrupts.
274629949e86Sstevel 	 */
274729949e86Sstevel 	ddi_trigger_softintr(softsp->sbrd_gone_id);
274829949e86Sstevel }
274929949e86Sstevel 
275029949e86Sstevel static void
275129949e86Sstevel bd_remove_timeout(void *arg)
275229949e86Sstevel {
275329949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
275429949e86Sstevel 	int keep_polling;
275529949e86Sstevel 
275629949e86Sstevel 	ASSERT(softsp);
275729949e86Sstevel 
275829949e86Sstevel 	/*
275929949e86Sstevel 	 * Lock the board list mutex. Keep it locked until all work
276029949e86Sstevel 	 * is done.
276129949e86Sstevel 	 */
276229949e86Sstevel 	(void) fhc_bdlist_lock(-1);
276329949e86Sstevel 
276429949e86Sstevel 	bd_remove_to_id = 0;	/* delete our timeout ID */
276529949e86Sstevel 
276629949e86Sstevel 	keep_polling = fhc_bd_remove_scan();
276729949e86Sstevel 
276829949e86Sstevel 	if (keep_polling) {
276929949e86Sstevel 		bd_remove_poll(softsp);
277029949e86Sstevel 	} else {
277129949e86Sstevel 		DPRINTF(SYSCTRL_ATTACH_DEBUG, ("exiting bd_remove_poll."));
277229949e86Sstevel 	}
277329949e86Sstevel 
277429949e86Sstevel 	fhc_bdlist_unlock();
277529949e86Sstevel }
277629949e86Sstevel 
277729949e86Sstevel static uint_t
277829949e86Sstevel bd_insert_normal(caddr_t arg)
277929949e86Sstevel {
278029949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
278129949e86Sstevel 	uchar_t tmp_reg;
278229949e86Sstevel 
278329949e86Sstevel 	ASSERT(softsp);
278429949e86Sstevel 
278529949e86Sstevel 	/* has the condition been removed? */
278629949e86Sstevel 	/* XXX add deglitch state machine here */
278729949e86Sstevel 	if (!(*(softsp->status1) & SYS_NOT_BRD_PRES)) {
278829949e86Sstevel 		/* check again in a few */
278929949e86Sstevel 		(void) timeout(bd_insert_timeout, softsp, bd_insert_retry_hz);
279029949e86Sstevel 	} else {
279129949e86Sstevel 		/* Turn on the enable bit for this interrupt */
279229949e86Sstevel 		mutex_enter(&softsp->csr_mutex);
279329949e86Sstevel 		*(softsp->csr) |= SYS_SBRD_PRES_EN;
279429949e86Sstevel 		/* flush the hardware store buffer */
279529949e86Sstevel 		tmp_reg = *(softsp->csr);
279629949e86Sstevel #ifdef lint
279729949e86Sstevel 		tmp_reg = tmp_reg;
279829949e86Sstevel #endif
279929949e86Sstevel 		mutex_exit(&softsp->csr_mutex);
280029949e86Sstevel 	}
280129949e86Sstevel 
280229949e86Sstevel 	return (DDI_INTR_CLAIMED);
280329949e86Sstevel }
280429949e86Sstevel 
280529949e86Sstevel /*
280629949e86Sstevel  * blink LED handler.
280729949e86Sstevel  *
280829949e86Sstevel  * The actual bit manipulation needs to occur at interrupt level
280929949e86Sstevel  * because we need access to the CSR with its CSR mutex
281029949e86Sstevel  */
281129949e86Sstevel static uint_t
281229949e86Sstevel blink_led_handler(caddr_t arg)
281329949e86Sstevel {
281429949e86Sstevel 	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
281529949e86Sstevel 	uchar_t tmp_reg;
281629949e86Sstevel 
281729949e86Sstevel 	ASSERT(softsp);
281829949e86Sstevel 
281929949e86Sstevel 	mutex_enter(&softsp->csr_mutex);
282029949e86Sstevel 
282129949e86Sstevel 	/*
282229949e86Sstevel 	 * XXX - The lock for the sys_led is not held here. If more
282329949e86Sstevel 	 * complicated tasks are done with the System LED, then
282429949e86Sstevel 	 * locking should be done here.
282529949e86Sstevel 	 */
282629949e86Sstevel 
282729949e86Sstevel 	/* read the hardware register. */
282829949e86Sstevel 	tmp_reg = *(softsp->csr);
282929949e86Sstevel 
283029949e86Sstevel 	/* Only turn on the OS System LED bit if the softsp state is on. */
283129949e86Sstevel 	if (softsp->sys_led) {
283229949e86Sstevel 		tmp_reg |= SYS_LED_RIGHT;
283329949e86Sstevel 	} else {
283429949e86Sstevel 		tmp_reg &= ~SYS_LED_RIGHT;
283529949e86Sstevel 	}
283629949e86Sstevel 
283729949e86Sstevel 	/* Turn on the yellow LED if system fault status is set. */
283829949e86Sstevel 	if (softsp->sys_fault) {
283929949e86Sstevel 		tmp_reg |= SYS_LED_MID;
284029949e86Sstevel 	} else {
284129949e86Sstevel 		tmp_reg &= ~SYS_LED_MID;
284229949e86Sstevel 	}
284329949e86Sstevel 
284429949e86Sstevel 	/* write to the hardware register */
284529949e86Sstevel 	*(softsp->csr) = tmp_reg;
284629949e86Sstevel 
284729949e86Sstevel 	/* flush the hardware store buffer */
284829949e86Sstevel 	tmp_reg = *(softsp->csr);
284929949e86Sstevel #ifdef lint
285029949e86Sstevel 	tmp_reg = tmp_reg;
285129949e86Sstevel #endif
285229949e86Sstevel 	mutex_exit(&softsp->csr_mutex);
285329949e86Sstevel 
285429949e86Sstevel 	(void) timeout(blink_led_timeout, softsp, blink_led_timeout_hz);
285529949e86Sstevel 
285629949e86Sstevel 	return (DDI_INTR_CLAIMED);
285729949e86Sstevel }
285829949e86Sstevel 
285929949e86Sstevel /*
286029949e86Sstevel  * simply re-trigger the interrupt handler on led timeout
286129949e86Sstevel  */
286229949e86Sstevel static void
286329949e86Sstevel blink_led_timeout(void *arg)
286429949e86Sstevel {
286529949e86Sstevel 	struct sysctrl_soft_state *softsp = arg;
286629949e86Sstevel 	int led_state;
286729949e86Sstevel 
286829949e86Sstevel 	ASSERT(softsp);
286929949e86Sstevel 
287029949e86Sstevel 	/*
287129949e86Sstevel 	 * Process the system fault list here. This is where the driver
287229949e86Sstevel 	 * must decide what yellow LEDs to turn on if any. The fault
287329949e86Sstevel 	 * list is walked and each fhc_list entry is updated with it's
287429949e86Sstevel 	 * yellow LED status. This info is used later by the routine
287529949e86Sstevel 	 * toggle_board_green_leds().
287629949e86Sstevel 	 *
287729949e86Sstevel 	 * The variable system_fault is non-zero if any non-
287829949e86Sstevel 	 * suppressed faults are found in the system.
287929949e86Sstevel 	 */
288029949e86Sstevel 	softsp->sys_fault = process_fault_list();
288129949e86Sstevel 
288229949e86Sstevel 	/* blink the system board OS LED */
288329949e86Sstevel 	mutex_enter(&softsp->sys_led_lock);
288429949e86Sstevel 	softsp->sys_led = !softsp->sys_led;
288529949e86Sstevel 	led_state = softsp->sys_led;
288629949e86Sstevel 	mutex_exit(&softsp->sys_led_lock);
288729949e86Sstevel 
288829949e86Sstevel 	toggle_board_green_leds(led_state);
288929949e86Sstevel 
289029949e86Sstevel 	ddi_trigger_softintr(softsp->blink_led_id);
289129949e86Sstevel }
289229949e86Sstevel 
289329949e86Sstevel void
289429949e86Sstevel toggle_board_green_leds(int led_state)
289529949e86Sstevel {
289629949e86Sstevel 	fhc_bd_t *list;
289729949e86Sstevel 
289829949e86Sstevel 	(void) fhc_bdlist_lock(-1);
289929949e86Sstevel 	for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) {
290029949e86Sstevel 		uint_t value = 0;
290129949e86Sstevel 
290229949e86Sstevel 		if (list->sc.in_transition ||
290329949e86Sstevel 		    (list->sc.rstate != SYSC_CFGA_RSTATE_CONNECTED))
290429949e86Sstevel 			continue;
290529949e86Sstevel 
290629949e86Sstevel 		ASSERT(list->sc.type != CLOCK_BOARD);
290729949e86Sstevel 		ASSERT(list->sc.type != DISK_BOARD);
290829949e86Sstevel 		ASSERT(list->softsp);
290929949e86Sstevel 
291029949e86Sstevel 		if ((list->sc.ostate == SYSC_CFGA_OSTATE_CONFIGURED) &&
291129949e86Sstevel 		    led_state)
291229949e86Sstevel 			value |= FHC_LED_RIGHT;
291329949e86Sstevel 
291429949e86Sstevel 		if (list->fault)
291529949e86Sstevel 			value |= FHC_LED_MID;
291629949e86Sstevel 		else
291729949e86Sstevel 			value &= ~FHC_LED_MID;
291829949e86Sstevel 
291929949e86Sstevel 		update_board_leds(list, FHC_LED_RIGHT|FHC_LED_MID, value);
292029949e86Sstevel 	}
292129949e86Sstevel 	fhc_bdlist_unlock();
292229949e86Sstevel }
292329949e86Sstevel 
292429949e86Sstevel /*
292529949e86Sstevel  * timestamp an AC power failure in nvram
292629949e86Sstevel  */
292729949e86Sstevel static void
292829949e86Sstevel nvram_update_powerfail(struct sysctrl_soft_state *softsp)
292929949e86Sstevel {
293029949e86Sstevel 	char buf[80];
293129949e86Sstevel 	int len = 0;
293229949e86Sstevel 
293329949e86Sstevel 	numtos(gethrestime_sec(), buf);
293429949e86Sstevel 
293529949e86Sstevel 	if (softsp->options_nodeid) {
293629949e86Sstevel 		len = prom_setprop(softsp->options_nodeid, "powerfail-time",
293729949e86Sstevel 		    buf, strlen(buf)+1);
293829949e86Sstevel 	}
293929949e86Sstevel 
294029949e86Sstevel 	if (len <= 0) {
294129949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: failed to set powerfail-time "
294229949e86Sstevel 		    "to %s\n", ddi_get_instance(softsp->dip), buf);
294329949e86Sstevel 	}
294429949e86Sstevel }
294529949e86Sstevel 
294629949e86Sstevel void
294729949e86Sstevel sysctrl_add_kstats(struct sysctrl_soft_state *softsp)
294829949e86Sstevel {
294929949e86Sstevel 	struct kstat	*ksp;		/* Generic sysctrl kstats */
295029949e86Sstevel 	struct kstat	*pksp;		/* Power Supply kstat */
295129949e86Sstevel 	struct kstat	*tksp;		/* Sysctrl temperatrure kstat */
295229949e86Sstevel 	struct kstat	*ttsp;		/* Sysctrl temperature test kstat */
295329949e86Sstevel 
295429949e86Sstevel 	if ((ksp = kstat_create("unix", ddi_get_instance(softsp->dip),
295529949e86Sstevel 	    SYSCTRL_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED,
295629949e86Sstevel 	    sizeof (struct sysctrl_kstat) / sizeof (kstat_named_t),
295729949e86Sstevel 	    KSTAT_FLAG_PERSISTENT)) == NULL) {
295829949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
295929949e86Sstevel 		    ddi_get_instance(softsp->dip));
296029949e86Sstevel 	} else {
296129949e86Sstevel 		struct sysctrl_kstat *sysksp;
296229949e86Sstevel 
296329949e86Sstevel 		sysksp = (struct sysctrl_kstat *)(ksp->ks_data);
296429949e86Sstevel 
296529949e86Sstevel 		/* now init the named kstats */
296629949e86Sstevel 		kstat_named_init(&sysksp->csr, CSR_KSTAT_NAMED,
296729949e86Sstevel 		    KSTAT_DATA_CHAR);
296829949e86Sstevel 
296929949e86Sstevel 		kstat_named_init(&sysksp->status1, STAT1_KSTAT_NAMED,
297029949e86Sstevel 		    KSTAT_DATA_CHAR);
297129949e86Sstevel 
297229949e86Sstevel 		kstat_named_init(&sysksp->status2, STAT2_KSTAT_NAMED,
297329949e86Sstevel 		    KSTAT_DATA_CHAR);
297429949e86Sstevel 
297529949e86Sstevel 		kstat_named_init(&sysksp->clk_freq2, CLK_FREQ2_KSTAT_NAMED,
297629949e86Sstevel 		    KSTAT_DATA_CHAR);
297729949e86Sstevel 
297829949e86Sstevel 		kstat_named_init(&sysksp->fan_status, FAN_KSTAT_NAMED,
297929949e86Sstevel 		    KSTAT_DATA_CHAR);
298029949e86Sstevel 
298129949e86Sstevel 		kstat_named_init(&sysksp->key_status, KEY_KSTAT_NAMED,
298229949e86Sstevel 		    KSTAT_DATA_CHAR);
298329949e86Sstevel 
298429949e86Sstevel 		kstat_named_init(&sysksp->power_state, POWER_KSTAT_NAMED,
298529949e86Sstevel 		    KSTAT_DATA_INT32);
298629949e86Sstevel 
298729949e86Sstevel 		kstat_named_init(&sysksp->clk_ver, CLK_VER_KSTAT_NAME,
298829949e86Sstevel 		    KSTAT_DATA_CHAR);
298929949e86Sstevel 
299029949e86Sstevel 		ksp->ks_update = sysctrl_kstat_update;
299129949e86Sstevel 		ksp->ks_private = (void *)softsp;
299229949e86Sstevel 		kstat_install(ksp);
299329949e86Sstevel 	}
299429949e86Sstevel 
299529949e86Sstevel 	if ((tksp = kstat_create("unix", CLOCK_BOARD_INDEX,
299629949e86Sstevel 	    OVERTEMP_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
299729949e86Sstevel 	    sizeof (struct temp_stats), KSTAT_FLAG_PERSISTENT)) == NULL) {
299829949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
299929949e86Sstevel 			ddi_get_instance(softsp->dip));
300029949e86Sstevel 	} else {
300129949e86Sstevel 		tksp->ks_update = overtemp_kstat_update;
300229949e86Sstevel 		tksp->ks_private = (void *)&softsp->tempstat;
300329949e86Sstevel 		kstat_install(tksp);
300429949e86Sstevel 	}
300529949e86Sstevel 
300629949e86Sstevel 	if ((ttsp = kstat_create("unix", CLOCK_BOARD_INDEX,
300729949e86Sstevel 	    TEMP_OVERRIDE_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, sizeof (short),
300829949e86Sstevel 	    KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
300929949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
301029949e86Sstevel 		    ddi_get_instance(softsp->dip));
301129949e86Sstevel 	} else {
301229949e86Sstevel 		ttsp->ks_update = temp_override_kstat_update;
301329949e86Sstevel 		ttsp->ks_private = (void *)&softsp->tempstat.override;
301429949e86Sstevel 		kstat_install(ttsp);
301529949e86Sstevel 	}
301629949e86Sstevel 
301729949e86Sstevel 	if ((pksp = kstat_create("unix", ddi_get_instance(softsp->dip),
301829949e86Sstevel 	    PSSHAD_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
301929949e86Sstevel 	    SYS_PS_COUNT, KSTAT_FLAG_PERSISTENT)) == NULL) {
302029949e86Sstevel 		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
302129949e86Sstevel 		    ddi_get_instance(softsp->dip));
302229949e86Sstevel 	} else {
302329949e86Sstevel 		pksp->ks_update = psstat_kstat_update;
302429949e86Sstevel 		pksp->ks_private = (void *)softsp;
302529949e86Sstevel 		kstat_install(pksp);
302629949e86Sstevel 	}
302729949e86Sstevel }
302829949e86Sstevel 
302929949e86Sstevel static int
303029949e86Sstevel sysctrl_kstat_update(kstat_t *ksp, int rw)
303129949e86Sstevel {
303229949e86Sstevel 	struct sysctrl_kstat *sysksp;
303329949e86Sstevel 	struct sysctrl_soft_state *softsp;
303429949e86Sstevel 
303529949e86Sstevel 	sysksp = (struct sysctrl_kstat *)(ksp->ks_data);
303629949e86Sstevel 	softsp = (struct sysctrl_soft_state *)(ksp->ks_private);
303729949e86Sstevel 
303829949e86Sstevel 	/* this is a read-only kstat. Exit on a write */
303929949e86Sstevel 
304029949e86Sstevel 	if (rw == KSTAT_WRITE) {
304129949e86Sstevel 		return (EACCES);
304229949e86Sstevel 	} else {
304329949e86Sstevel 		/*
304429949e86Sstevel 		 * copy the current state of the hardware into the
304529949e86Sstevel 		 * kstat structure.
304629949e86Sstevel 		 */
304729949e86Sstevel 		sysksp->csr.value.c[0] = *(softsp->csr);
304829949e86Sstevel 		sysksp->status1.value.c[0] = *(softsp->status1);
304929949e86Sstevel 		sysksp->status2.value.c[0] = *(softsp->status2);
305029949e86Sstevel 		sysksp->clk_freq2.value.c[0] = *(softsp->clk_freq2);
305129949e86Sstevel 
305229949e86Sstevel 		sysksp->fan_status.value.c[0] = softsp->pps_fan_external_state;
305329949e86Sstevel 		sysksp->key_status.value.c[0] = softsp->key_shadow;
305429949e86Sstevel 		sysksp->power_state.value.i32 = softsp->power_state;
305529949e86Sstevel 
305629949e86Sstevel 		/*
305729949e86Sstevel 		 * non-existence of the clock version register returns the
305829949e86Sstevel 		 * value 0xff when the hardware register location is read
305929949e86Sstevel 		 */
306029949e86Sstevel 		if (softsp->clk_ver != NULL)
306129949e86Sstevel 			sysksp->clk_ver.value.c[0] = *(softsp->clk_ver);
306229949e86Sstevel 		else
306329949e86Sstevel 			sysksp->clk_ver.value.c[0] = (char)0xff;
306429949e86Sstevel 	}
306529949e86Sstevel 	return (0);
306629949e86Sstevel }
306729949e86Sstevel 
306829949e86Sstevel static int
306929949e86Sstevel psstat_kstat_update(kstat_t *ksp, int rw)
307029949e86Sstevel {
307129949e86Sstevel 	struct sysctrl_soft_state *softsp;
307229949e86Sstevel 	uchar_t *ptr = (uchar_t *)(ksp->ks_data);
307329949e86Sstevel 	int ps;
307429949e86Sstevel 
307529949e86Sstevel 	softsp = (struct sysctrl_soft_state *)(ksp->ks_private);
307629949e86Sstevel 
307729949e86Sstevel 	if (rw == KSTAT_WRITE) {
307829949e86Sstevel 		return (EACCES);
307929949e86Sstevel 	} else {
308029949e86Sstevel 		for (ps = 0; ps < SYS_PS_COUNT; ps++) {
308129949e86Sstevel 			*ptr++ = softsp->ps_stats[ps].dcshadow;
308229949e86Sstevel 		}
308329949e86Sstevel 	}
308429949e86Sstevel 	return (0);
308529949e86Sstevel }
308629949e86Sstevel 
308729949e86Sstevel static void
308829949e86Sstevel sysctrl_thread_wakeup(void *arg)
308929949e86Sstevel {
309029949e86Sstevel 	int type = (int)(uintptr_t)arg;
309129949e86Sstevel 
309229949e86Sstevel 	/*
309329949e86Sstevel 	 * grab mutex to guarantee that our wakeup call
309429949e86Sstevel 	 * arrives after we go to sleep -- so we can't sleep forever.
309529949e86Sstevel 	 */
309629949e86Sstevel 	mutex_enter(&sslist_mutex);
309729949e86Sstevel 	switch (type) {
309829949e86Sstevel 	case OVERTEMP_POLL:
309929949e86Sstevel 		cv_signal(&overtemp_cv);
310029949e86Sstevel 		break;
310129949e86Sstevel 	case KEYSWITCH_POLL:
310229949e86Sstevel 		cv_signal(&keyswitch_cv);
310329949e86Sstevel 		break;
310429949e86Sstevel 	default:
310529949e86Sstevel 		cmn_err(CE_WARN, "sysctrl: invalid type %d to wakeup\n", type);
310629949e86Sstevel 		break;
310729949e86Sstevel 	}
310829949e86Sstevel 	mutex_exit(&sslist_mutex);
310929949e86Sstevel }
311029949e86Sstevel 
311129949e86Sstevel static void
311229949e86Sstevel sysctrl_overtemp_poll(void)
311329949e86Sstevel {
311429949e86Sstevel 	struct sysctrl_soft_state *list;
311529949e86Sstevel 	callb_cpr_t cprinfo;
311629949e86Sstevel 
311729949e86Sstevel 	CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "overtemp");
311829949e86Sstevel 
311929949e86Sstevel 	/* The overtemp data structures are protected by a mutex. */
312029949e86Sstevel 	mutex_enter(&sslist_mutex);
312129949e86Sstevel 
312229949e86Sstevel 	while (sysctrl_do_overtemp_thread) {
312329949e86Sstevel 
312429949e86Sstevel 		for (list = sys_list; list != NULL; list = list->next) {
312529949e86Sstevel 			if (list->temp_reg != NULL) {
312629949e86Sstevel 				update_temp(list->pdip, &list->tempstat,
312729949e86Sstevel 				    *(list->temp_reg));
312829949e86Sstevel 			}
312929949e86Sstevel 		}
313029949e86Sstevel 
313129949e86Sstevel 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
313229949e86Sstevel 
313329949e86Sstevel 		/* now have this thread sleep for a while */
313429949e86Sstevel 		(void) timeout(sysctrl_thread_wakeup, (void *)OVERTEMP_POLL,
313529949e86Sstevel 		    overtemp_timeout_hz);
313629949e86Sstevel 
313729949e86Sstevel 		cv_wait(&overtemp_cv, &sslist_mutex);
313829949e86Sstevel 
313929949e86Sstevel 		CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex);
314029949e86Sstevel 	}
314129949e86Sstevel 	CALLB_CPR_EXIT(&cprinfo);
314229949e86Sstevel 	thread_exit();
314329949e86Sstevel 	/* NOTREACHED */
314429949e86Sstevel }
314529949e86Sstevel 
314629949e86Sstevel static void
314729949e86Sstevel sysctrl_keyswitch_poll(void)
314829949e86Sstevel {
314929949e86Sstevel 	struct sysctrl_soft_state *list;
315029949e86Sstevel 	callb_cpr_t cprinfo;
315129949e86Sstevel 
315229949e86Sstevel 	CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "keyswitch");
315329949e86Sstevel 
315429949e86Sstevel 	/* The keyswitch data strcutures are protected by a mutex. */
315529949e86Sstevel 	mutex_enter(&sslist_mutex);
315629949e86Sstevel 
315729949e86Sstevel 	while (sysctrl_do_keyswitch_thread) {
315829949e86Sstevel 
315929949e86Sstevel 		for (list = sys_list; list != NULL; list = list->next) {
316029949e86Sstevel 			if (list->status1 != NULL)
316129949e86Sstevel 				update_key_state(list);
316229949e86Sstevel 		}
316329949e86Sstevel 
316429949e86Sstevel 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
316529949e86Sstevel 
316629949e86Sstevel 		/* now have this thread sleep for a while */
316729949e86Sstevel 		(void) timeout(sysctrl_thread_wakeup, (void *)KEYSWITCH_POLL,
316829949e86Sstevel 		    keyswitch_timeout_hz);
316929949e86Sstevel 
317029949e86Sstevel 		cv_wait(&keyswitch_cv, &sslist_mutex);
317129949e86Sstevel 
317229949e86Sstevel 		CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex);
317329949e86Sstevel 	}
317429949e86Sstevel 	CALLB_CPR_EXIT(&cprinfo);
317529949e86Sstevel 	thread_exit();
317629949e86Sstevel 	/* NOTREACHED */
317729949e86Sstevel }
317829949e86Sstevel 
317929949e86Sstevel /*
318029949e86Sstevel  * check the key switch position for state changes
318129949e86Sstevel  */
318229949e86Sstevel static void
318329949e86Sstevel update_key_state(struct sysctrl_soft_state *list)
318429949e86Sstevel {
318529949e86Sstevel 	enum keyswitch_state key;
318629949e86Sstevel 
318729949e86Sstevel 	/*
318829949e86Sstevel 	 * snapshot current hardware key position
318929949e86Sstevel 	 */
319029949e86Sstevel 	if (*(list->status1) & SYS_NOT_SECURE)
319129949e86Sstevel 		key = KEY_NOT_SECURE;
319229949e86Sstevel 	else
319329949e86Sstevel 		key = KEY_SECURE;
319429949e86Sstevel 
319529949e86Sstevel 	/*
319629949e86Sstevel 	 * check for state transition
319729949e86Sstevel 	 */
319829949e86Sstevel 	if (key != list->key_shadow) {
319929949e86Sstevel 
320029949e86Sstevel 		/*
320129949e86Sstevel 		 * handle state transition
320229949e86Sstevel 		 */
320329949e86Sstevel 		switch (list->key_shadow) {
320429949e86Sstevel 		case KEY_BOOT:
320529949e86Sstevel 			cmn_err(CE_CONT, "?sysctrl%d: Key switch is%sin the "
320629949e86Sstevel 			    "secure position\n", ddi_get_instance(list->dip),
320729949e86Sstevel 			    (key == KEY_SECURE) ? " " : " not ");
320829949e86Sstevel 			list->key_shadow = key;
320929949e86Sstevel 			break;
321029949e86Sstevel 		case KEY_SECURE:
321129949e86Sstevel 		case KEY_NOT_SECURE:
321229949e86Sstevel 			cmn_err(CE_NOTE, "sysctrl%d: Key switch has changed"
321329949e86Sstevel 			    " to the %s position",
321429949e86Sstevel 			    ddi_get_instance(list->dip),
321529949e86Sstevel 			    (key == KEY_SECURE) ? "secure" : "not-secure");
321629949e86Sstevel 			list->key_shadow = key;
321729949e86Sstevel 			break;
321829949e86Sstevel 		default:
321929949e86Sstevel 			cmn_err(CE_CONT,
322029949e86Sstevel 			    "?sysctrl%d: Key switch is in an unknown position,"
322129949e86Sstevel 			    "treated as being in the %s position\n",
322229949e86Sstevel 			    ddi_get_instance(list->dip),
322329949e86Sstevel 			    (list->key_shadow == KEY_SECURE) ?
322429949e86Sstevel 			    "secure" : "not-secure");
322529949e86Sstevel 			break;
322629949e86Sstevel 		}
322729949e86Sstevel 	}
322829949e86Sstevel }
322929949e86Sstevel 
323029949e86Sstevel /*
323129949e86Sstevel  * consider key switch position when handling an abort sequence
323229949e86Sstevel  */
323329949e86Sstevel static void
323429949e86Sstevel sysctrl_abort_seq_handler(char *msg)
323529949e86Sstevel {
323629949e86Sstevel 	struct sysctrl_soft_state *list;
323729949e86Sstevel 	uint_t secure = 0;
323829949e86Sstevel 	char buf[64], inst[4];
323929949e86Sstevel 
324029949e86Sstevel 
324129949e86Sstevel 	/*
324229949e86Sstevel 	 * if any of the key switch positions are secure,
324329949e86Sstevel 	 * then disallow entry to the prom/debugger
324429949e86Sstevel 	 */
324529949e86Sstevel 	mutex_enter(&sslist_mutex);
324629949e86Sstevel 	buf[0] = (char)0;
324729949e86Sstevel 	for (list = sys_list; list != NULL; list = list->next) {
324829949e86Sstevel 		if (!(*(list->status1) & SYS_NOT_SECURE)) {
324929949e86Sstevel 			if (secure++)
325029949e86Sstevel 				(void) strcat(buf, ",");
325129949e86Sstevel 			/*
325229949e86Sstevel 			 * XXX: later, replace instance number with nodeid
325329949e86Sstevel 			 */
325429949e86Sstevel 			(void) sprintf(inst, "%d", ddi_get_instance(list->dip));
325529949e86Sstevel 			(void) strcat(buf, inst);
325629949e86Sstevel 		}
325729949e86Sstevel 	}
325829949e86Sstevel 	mutex_exit(&sslist_mutex);
325929949e86Sstevel 
326029949e86Sstevel 	if (secure) {
326129949e86Sstevel 		cmn_err(CE_CONT,
326229949e86Sstevel 		    "!sysctrl(%s): ignoring debug enter sequence\n", buf);
326329949e86Sstevel 	} else {
326429949e86Sstevel 		cmn_err(CE_CONT, "!sysctrl: allowing debug enter\n");
326529949e86Sstevel 		debug_enter(msg);
326629949e86Sstevel 	}
326729949e86Sstevel }
326829949e86Sstevel 
326929949e86Sstevel #define	TABLE_END	0xFF
327029949e86Sstevel 
327129949e86Sstevel struct uart_cmd {
327229949e86Sstevel 	uchar_t reg;
327329949e86Sstevel 	uchar_t data;
327429949e86Sstevel };
327529949e86Sstevel 
327629949e86Sstevel /*
327729949e86Sstevel  * Time constant defined by this formula:
327829949e86Sstevel  *	((4915200/32)/(baud) -2)
327929949e86Sstevel  */
328029949e86Sstevel 
328129949e86Sstevel struct uart_cmd uart_table[] = {
328229949e86Sstevel 	{ 0x09, 0xc0 },	/* Force hardware reset */
328329949e86Sstevel 	{ 0x04, 0x46 },	/* X16 clock mode, 1 stop bit/char, no parity */
328429949e86Sstevel 	{ 0x03, 0xc0 },	/* Rx is 8 bits/char */
328529949e86Sstevel 	{ 0x05, 0xe2 },	/* DTR, Tx is 8 bits/char, RTS */
328629949e86Sstevel 	{ 0x09, 0x02 },	/* No vector returned on interrupt */
328729949e86Sstevel 	{ 0x0b, 0x55 },	/* Rx Clock = Tx Clock = BR generator = ~TRxC OUT */
328829949e86Sstevel 	{ 0x0c, 0x0e },	/* Time Constant = 0x000e for 9600 baud */
328929949e86Sstevel 	{ 0x0d, 0x00 },	/* High byte of time constant */
329029949e86Sstevel 	{ 0x0e, 0x02 },	/* BR generator comes from Z-SCC's PCLK input */
329129949e86Sstevel 	{ 0x03, 0xc1 },	/* Rx is 8 bits/char, Rx is enabled */
329229949e86Sstevel 	{ 0x05, 0xea },	/* DTR, Tx is 8 bits/char, Tx is enabled, RTS */
329329949e86Sstevel 	{ 0x0e, 0x03 },	/* BR comes from PCLK, BR generator is enabled */
329429949e86Sstevel 	{ 0x00, 0x30 },	/* Error reset */
329529949e86Sstevel 	{ 0x00, 0x30 },	/* Error reset */
329629949e86Sstevel 	{ 0x00, 0x10 },	/* external status reset */
329729949e86Sstevel 	{ 0x03, 0xc1 },	/* Rx is 8 bits/char, Rx is enabled */
329829949e86Sstevel 	{ TABLE_END, 0x0 }
329929949e86Sstevel };
330029949e86Sstevel 
330129949e86Sstevel static void
330229949e86Sstevel init_remote_console_uart(struct sysctrl_soft_state *softsp)
330329949e86Sstevel {
330429949e86Sstevel 	int i = 0;
330529949e86Sstevel 
330629949e86Sstevel 	/*
330729949e86Sstevel 	 * Serial chip expects software to write to the control
330829949e86Sstevel 	 * register first with the desired register number. Then
330929949e86Sstevel 	 * write to the control register with the desired data.
331029949e86Sstevel 	 * So walk thru table writing the register/data pairs to
331129949e86Sstevel 	 * the serial port chip.
331229949e86Sstevel 	 */
331329949e86Sstevel 	while (uart_table[i].reg != TABLE_END) {
331429949e86Sstevel 		*(softsp->rcons_ctl) = uart_table[i].reg;
331529949e86Sstevel 		*(softsp->rcons_ctl) = uart_table[i].data;
331629949e86Sstevel 		i++;
331729949e86Sstevel 	}
331829949e86Sstevel }
331929949e86Sstevel 
332029949e86Sstevel /*
332129949e86Sstevel  * return the slot information of the system
332229949e86Sstevel  *
332329949e86Sstevel  * function take a sysctrl_soft_state, so it's ready for sunfire+
332429949e86Sstevel  * change which requires 2 registers to decide the system type.
332529949e86Sstevel  */
332629949e86Sstevel static void
332729949e86Sstevel sysc_slot_info(int nslots, int *start, int *limit, int *incr)
332829949e86Sstevel {
332929949e86Sstevel 	switch (nslots) {
333029949e86Sstevel 	case 8:
333129949e86Sstevel 		*start = 0;
333229949e86Sstevel 		*limit = 8;
333329949e86Sstevel 		*incr = 1;
333429949e86Sstevel 		break;
333529949e86Sstevel 	case 5:
333629949e86Sstevel 		*start = 1;
333729949e86Sstevel 		*limit = 10;
333829949e86Sstevel 		*incr = 2;
333929949e86Sstevel 		break;
334029949e86Sstevel 	case 4:
334129949e86Sstevel 		*start = 1;
334229949e86Sstevel 		*limit = 8;
334329949e86Sstevel 		*incr = 2;
334429949e86Sstevel 		break;
334529949e86Sstevel 	case 0:
334629949e86Sstevel 	case 16:
334729949e86Sstevel 	default:
334829949e86Sstevel 		*start = 0;
334929949e86Sstevel 		*limit = 16;
335029949e86Sstevel 		*incr = 1;
335129949e86Sstevel 		break;
335229949e86Sstevel 	}
335329949e86Sstevel }
335429949e86Sstevel 
335529949e86Sstevel /*
335629949e86Sstevel  * reinitialize the Remote Console on the clock board
335729949e86Sstevel  *
335829949e86Sstevel  * with V5_AUX power outage the Remote Console ends up in
335929949e86Sstevel  * unknown state and has to be reinitilized if it was enabled
336029949e86Sstevel  * initially.
336129949e86Sstevel  */
336229949e86Sstevel static void
336329949e86Sstevel rcons_reinit(struct sysctrl_soft_state *softsp)
336429949e86Sstevel {
336529949e86Sstevel 	uchar_t tmp_reg;
336629949e86Sstevel 
336729949e86Sstevel 	if (!(softsp->rcons_ctl))
336829949e86Sstevel 		/*
336929949e86Sstevel 		 * There is no OBP register set for the remote console UART,
337029949e86Sstevel 		 * so offset from the last register set, the misc register
337129949e86Sstevel 		 * set, in order to map in the remote console UART.
337229949e86Sstevel 		 */
337329949e86Sstevel 		if (ddi_map_regs(softsp->dip, 1, (caddr_t *)&softsp->rcons_ctl,
337429949e86Sstevel 		    RMT_CONS_OFFSET, RMT_CONS_LEN)) {
337529949e86Sstevel 			cmn_err(CE_WARN, "Unable to reinitialize "
337629949e86Sstevel 			    "remote console.");
337729949e86Sstevel 			return;
337829949e86Sstevel 		}
337929949e86Sstevel 
338029949e86Sstevel 
338129949e86Sstevel 	/* Disable the remote console reset control bits. */
338229949e86Sstevel 	*(softsp->clk_freq2) &= ~RCONS_UART_EN;
338329949e86Sstevel 
338429949e86Sstevel 	/* flush the hardware buffers */
338529949e86Sstevel 	tmp_reg = *(softsp->csr);
338629949e86Sstevel 
338729949e86Sstevel 	/*
338829949e86Sstevel 	 * Program the UART to watch ttya console.
338929949e86Sstevel 	 */
339029949e86Sstevel 	init_remote_console_uart(softsp);
339129949e86Sstevel 
339229949e86Sstevel 	/* Now enable the remote console reset control bits. */
339329949e86Sstevel 	*(softsp->clk_freq2) |= RCONS_UART_EN;
339429949e86Sstevel 
339529949e86Sstevel 	/* flush the hardware buffers */
339629949e86Sstevel 	tmp_reg = *(softsp->csr);
339729949e86Sstevel 
339829949e86Sstevel 	/* print some info for user to watch */
339929949e86Sstevel 	cmn_err(CE_NOTE, "Remote console reinitialized");
340029949e86Sstevel #ifdef lint
340129949e86Sstevel 	tmp_reg = tmp_reg;
340229949e86Sstevel #endif
340329949e86Sstevel }
3404