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