129949e8stevel/*
229949e8stevel * CDDL HEADER START
329949e8stevel *
429949e8stevel * The contents of this file are subject to the terms of the
529949e8stevel * Common Development and Distribution License (the "License").
629949e8stevel * You may not use this file except in compliance with the License.
729949e8stevel *
829949e8stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
929949e8stevel * or http://www.opensolaris.org/os/licensing.
1029949e8stevel * See the License for the specific language governing permissions
1129949e8stevel * and limitations under the License.
1229949e8stevel *
1329949e8stevel * When distributing Covered Code, include this CDDL HEADER in each
1429949e8stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1529949e8stevel * If applicable, add the following below this CDDL HEADER, with the
1629949e8stevel * fields enclosed by brackets "[]" replaced with your own identifying
1729949e8stevel * information: Portions Copyright [yyyy] [name of copyright owner]
1829949e8stevel *
1929949e8stevel * CDDL HEADER END
2029949e8stevel */
2129949e8stevel
2229949e8stevel/*
2307d06daSurya Prakki * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2429949e8stevel * Use is subject to license terms.
2589b4368Bayard Bell * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
2629949e8stevel */
2729949e8stevel
2829949e8stevel
2929949e8stevel#include <sys/types.h>
3029949e8stevel#include <sys/conf.h>
3129949e8stevel#include <sys/ddi.h>
3229949e8stevel#include <sys/sunddi.h>
3329949e8stevel#include <sys/ddi_impldefs.h>
3429949e8stevel#include <sys/sunndi.h>
3529949e8stevel#include <sys/ndi_impldefs.h>
3629949e8stevel#include <sys/obpdefs.h>
3729949e8stevel#include <sys/cmn_err.h>
3829949e8stevel#include <sys/errno.h>
3929949e8stevel#include <sys/kmem.h>
4029949e8stevel#include <sys/debug.h>
4129949e8stevel#include <sys/sysmacros.h>
4229949e8stevel#include <sys/ivintr.h>
4329949e8stevel#include <sys/autoconf.h>
4429949e8stevel#include <sys/intreg.h>
4529949e8stevel#include <sys/proc.h>
4629949e8stevel#include <sys/modctl.h>
4729949e8stevel#include <sys/callb.h>
4829949e8stevel#include <sys/file.h>
4929949e8stevel#include <sys/open.h>
5029949e8stevel#include <sys/stat.h>
5129949e8stevel#include <sys/fhc.h>
5229949e8stevel#include <sys/sysctrl.h>
5329949e8stevel#include <sys/jtag.h>
5429949e8stevel#include <sys/ac.h>
5529949e8stevel#include <sys/simmstat.h>
5629949e8stevel#include <sys/clock.h>
5729949e8stevel#include <sys/promif.h>
5829949e8stevel#include <sys/promimpl.h>
5929949e8stevel#include <sys/sunndi.h>
6029949e8stevel#include <sys/machsystm.h>
6129949e8stevel
6229949e8stevel/* Useful debugging Stuff */
6329949e8stevel#ifdef DEBUG
6429949e8stevelint sysc_debug_info = 1;
6529949e8stevelint sysc_debug_print_level = 0;
6629949e8stevel#endif
6729949e8stevel
6829949e8stevel/*
6929949e8stevel * Function prototypes
7029949e8stevel */
7129949e8stevelstatic int sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
7229949e8stevel		void **result);
7329949e8stevel
7429949e8stevelstatic int sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
7529949e8stevel
7629949e8stevelstatic int sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
7729949e8stevel
7829949e8stevelstatic int sysctrl_open(dev_t *, int, int, cred_t *);
7929949e8stevel
8029949e8stevelstatic int sysctrl_close(dev_t, int, int, cred_t *);
8129949e8stevel
8229949e8stevelstatic int sysctrl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
8329949e8stevel
8429949e8stevelstatic uint_t system_high_handler(caddr_t arg);
8529949e8stevel
8629949e8stevelstatic uint_t spur_delay(caddr_t arg);
8729949e8stevel
8829949e8stevelstatic void spur_retry(void *);
8929949e8stevel
9029949e8stevelstatic uint_t spur_reenable(caddr_t arg);
9129949e8stevel
9229949e8stevelstatic void spur_long_timeout(void *);
9329949e8stevel
9429949e8stevelstatic uint_t spur_clear_count(caddr_t arg);
9529949e8stevel
9629949e8stevelstatic uint_t ac_fail_handler(caddr_t arg);
9729949e8stevel
9829949e8stevelstatic void ac_fail_retry(void *);
9929949e8stevel
10029949e8stevelstatic uint_t ac_fail_reenable(caddr_t arg);
10129949e8stevel
10229949e8stevelstatic uint_t ps_fail_int_handler(caddr_t arg);
10329949e8stevel
10429949e8stevelstatic uint_t ps_fail_poll_handler(caddr_t arg);
10529949e8stevel
10629949e8stevelstatic uint_t ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint);
10729949e8stevel
10829949e8stevelenum power_state compute_power_state(struct sysctrl_soft_state *softsp,
10929949e8stevel					int plus_load);
11029949e8stevel
11129949e8stevelstatic void ps_log_state_change(struct sysctrl_soft_state *softsp,
11229949e8stevel					int index, int present);
11329949e8stevel
11429949e8stevelstatic void ps_log_pres_change(struct sysctrl_soft_state *softsp,
11529949e8stevel					int index, int present);
11629949e8stevel
11729949e8stevelstatic void ps_fail_retry(void *);
11829949e8stevel
11929949e8stevelstatic uint_t pps_fanfail_handler(caddr_t arg);
12029949e8stevel
12129949e8stevelstatic void pps_fanfail_retry(void *);
12229949e8stevel
12329949e8stevelstatic uint_t pps_fanfail_reenable(caddr_t arg);
12429949e8stevel
12529949e8stevelstatic void pps_fan_poll(void *);
12629949e8stevel
12729949e8stevelstatic void pps_fan_state_change(struct sysctrl_soft_state *softsp,
12829949e8stevel					int index, int fan_ok);
12929949e8stevel
13029949e8stevelstatic uint_t bd_insert_handler(caddr_t arg);
13129949e8stevel
13229949e8stevelstatic void bd_insert_timeout(void *);
13329949e8stevel
13429949e8stevelstatic void bd_remove_timeout(void *);
13529949e8stevel
13629949e8stevelstatic uint_t bd_insert_normal(caddr_t arg);
13729949e8stevel
13829949e8stevelstatic void sysctrl_add_kstats(struct sysctrl_soft_state *softsp);
13929949e8stevel
14029949e8stevelstatic int sysctrl_kstat_update(kstat_t *ksp, int rw);
14129949e8stevel
14229949e8stevelstatic int psstat_kstat_update(kstat_t *, int);
14329949e8stevel
14429949e8stevelstatic void init_remote_console_uart(struct sysctrl_soft_state *);
14529949e8stevel
14629949e8stevelstatic void blink_led_timeout(void *);
14729949e8stevel
14829949e8stevelstatic uint_t blink_led_handler(caddr_t arg);
14929949e8stevel
15029949e8stevelstatic void sysctrl_thread_wakeup(void *type);
15129949e8stevel
15229949e8stevelstatic void sysctrl_overtemp_poll(void);
15329949e8stevel
15429949e8stevelstatic void sysctrl_keyswitch_poll(void);
15529949e8stevel
15629949e8stevelstatic void update_key_state(struct sysctrl_soft_state *);
15729949e8stevel
15829949e8stevelstatic void sysctrl_abort_seq_handler(char *msg);
15929949e8stevel
16029949e8stevelstatic void nvram_update_powerfail(struct sysctrl_soft_state *softsp);
16129949e8stevel
16229949e8stevelstatic void toggle_board_green_leds(int);
16329949e8stevel
16429949e8stevelvoid bd_remove_poll(struct sysctrl_soft_state *);
16529949e8stevel
16629949e8stevelstatic void sysc_slot_info(int nslots, int *start, int *limit, int *incr);
16729949e8stevel
16829949e8stevelextern void sysc_board_connect_supported_init(void);
16929949e8stevel
17029949e8stevelstatic void rcons_reinit(struct sysctrl_soft_state *softsp);
17129949e8stevel
17229949e8stevel/*
17329949e8stevel * Configuration data structures
17429949e8stevel */
17529949e8stevelstatic struct cb_ops sysctrl_cb_ops = {
17629949e8stevel	sysctrl_open,		/* open */
17729949e8stevel	sysctrl_close,		/* close */
17829949e8stevel	nulldev,		/* strategy */
17929949e8stevel	nulldev,		/* print */
18029949e8stevel	nulldev,		/* dump */
18129949e8stevel	nulldev,		/* read */
18229949e8stevel	nulldev,		/* write */
18329949e8stevel	sysctrl_ioctl,		/* ioctl */
18429949e8stevel	nodev,			/* devmap */
18529949e8stevel	nodev,			/* mmap */
18629949e8stevel	nodev,			/* segmap */
18729949e8stevel	nochpoll,		/* poll */
18829949e8stevel	ddi_prop_op,		/* cb_prop_op */
18929949e8stevel	0,			/* streamtab */
19029949e8stevel	D_MP|D_NEW,		/* Driver compatibility flag */
19129949e8stevel	CB_REV,			/* rev */
19229949e8stevel	nodev,			/* cb_aread */
19329949e8stevel	nodev			/* cb_awrite */
19429949e8stevel};
19529949e8stevel
19629949e8stevelstatic struct dev_ops sysctrl_ops = {
19729949e8stevel	DEVO_REV,		/* devo_rev */
19829949e8stevel	0,			/* refcnt */
19929949e8stevel	sysctrl_info,		/* getinfo */
20029949e8stevel	nulldev,		/* identify */
20129949e8stevel	nulldev,		/* probe */
20229949e8stevel	sysctrl_attach,		/* attach */
20329949e8stevel	sysctrl_detach,		/* detach */
20429949e8stevel	nulldev,		/* reset */
20529949e8stevel	&sysctrl_cb_ops,	/* cb_ops */
20629949e8stevel	(struct bus_ops *)0,	/* bus_ops */
2071939740Sherry Moore	nulldev,		/* power */
2081939740Sherry Moore	ddi_quiesce_not_supported,	/* devo_quiesce */
20929949e8stevel};
21029949e8stevel
21129949e8stevelvoid *sysctrlp;				/* sysctrl soft state hook */
21229949e8stevel
21329949e8stevel/* # of ticks to silence spurious interrupts */
21429949e8stevelstatic clock_t spur_timeout_hz;
21529949e8stevel
21629949e8stevel/* # of ticks to count spurious interrupts to print message */
21729949e8stevelstatic clock_t spur_long_timeout_hz;
21829949e8stevel
21929949e8stevel/* # of ticks between AC failure polling */
22029949e8stevelstatic clock_t ac_timeout_hz;
22129949e8stevel
22229949e8stevel/* # of ticks between Power Supply Failure polling */
22329949e8stevelstatic clock_t ps_fail_timeout_hz;
22429949e8stevel
22529949e8stevel/*
22629949e8stevel * # of ticks between Peripheral Power Supply failure polling
22729949e8stevel * (used both for interrupt retry timeout and polling function)
22829949e8stevel */
22929949e8stevelstatic clock_t pps_fan_timeout_hz;
23029949e8stevel
23129949e8stevel/* # of ticks delay after board insert interrupt */
23229949e8stevelstatic clock_t bd_insert_delay_hz;
23329949e8stevel
23429949e8stevel/* # of secs to wait before restarting poll if we cannot clear interrupts */
23529949e8stevelstatic clock_t bd_insert_retry_hz;
23629949e8stevel
23729949e8stevel/* # of secs between Board Removal polling */
23829949e8stevelstatic clock_t bd_remove_timeout_hz;
23929949e8stevel
24029949e8stevel/* # of secs between toggle of OS LED */
24129949e8stevelstatic clock_t blink_led_timeout_hz;
24229949e8stevel
24329949e8stevel/* overtemp polling routine timeout delay */
24429949e8stevelstatic clock_t overtemp_timeout_hz;
24529949e8stevel
24629949e8stevel/* key switch polling routine timeout delay */
24729949e8stevelstatic clock_t keyswitch_timeout_hz;
24829949e8stevel
24929949e8stevel/* Specify which system interrupt condition to monitor */
25029949e8stevelint enable_sys_interrupt = SYS_AC_PWR_FAIL_EN | SYS_PPS_FAN_FAIL_EN |
25129949e8stevel			SYS_PS_FAIL_EN | SYS_SBRD_PRES_EN;
25229949e8stevel
25329949e8stevel/* Should the overtemp_poll thread be running? */
25429949e8stevelstatic int sysctrl_do_overtemp_thread = 1;
25529949e8stevel
25629949e8stevel/* Should the keyswitch_poll thread be running? */
25729949e8stevelstatic int sysctrl_do_keyswitch_thread = 1;
25829949e8stevel
25929949e8stevel/*
26029949e8stevel * This timeout ID is for board remove polling routine. It is
26129949e8stevel * protected by the fhc_bdlist mutex.
26229949e8stevel * XXX - This will not work for wildfire. A different scheme must be
26329949e8stevel * used since there will be multiple sysctrl nodes, each with its
26429949e8stevel * own list of hotplugged boards to scan.
26529949e8stevel */
26629949e8stevelstatic timeout_id_t bd_remove_to_id = 0;
26729949e8stevel
26829949e8stevel/*
26929949e8stevel * If this is set, the system will not shutdown when insufficient power
27029949e8stevel * condition persists.
27129949e8stevel */
27229949e8stevelint disable_insufficient_power_reboot = 0;
27329949e8stevel
27429949e8stevel/*
27529949e8stevel * Set this to enable suspend/resume
27629949e8stevel */
27729949e8stevelint sysctrl_enable_detach_suspend = 0;
27829949e8stevel
27929949e8stevel/*
28029949e8stevel * Set this to reflect the OBP initialized HOTPLUG_DISABLED_PROPERTY and
28129949e8stevel * during dynamic detection
28229949e8stevel */
28329949e8stevelint sysctrl_hotplug_disabled = FALSE;
28429949e8stevel
28529949e8stevel/* Indicates whether or not the overtemp thread has been started */
28629949e8stevelstatic int sysctrl_overtemp_thread_started = 0;
28729949e8stevel
28829949e8stevel/* Indicates whether or not the key switch thread has been started */
28929949e8stevelstatic int sysctrl_keyswitch_thread_started = 0;
29029949e8stevel
29129949e8stevel/* *Mutex used to protect the soft state list */
29229949e8stevelstatic kmutex_t sslist_mutex;
29329949e8stevel
29429949e8stevel/* The CV is used to wakeup the overtemp thread when needed. */
29529949e8stevelstatic kcondvar_t overtemp_cv;
29629949e8stevel
29729949e8stevel/* The CV is used to wakeup the key switch thread when needed. */
29829949e8stevelstatic kcondvar_t keyswitch_cv;
29929949e8stevel
30029949e8stevel/* This mutex is used to protect the sysctrl_ddi_branch_init variable */
30129949e8stevelstatic kmutex_t sysctrl_branch_mutex;
30229949e8stevel
30329949e8stevel/*
30429949e8stevel * This variable is set after all existing branches in the system have
30529949e8stevel * been discovered and held via e_ddi_branch_hold(). This happens on
30629949e8stevel * first open() of any sysctrl minor node.
30729949e8stevel */
30829949e8stevelstatic int sysctrl_ddi_branch_init;
30929949e8stevel
31029949e8stevel/*
31129949e8stevel * Linked list of all syctrl soft state structures.
31229949e8stevel * Used for polling sysctrl state changes, i.e. temperature.
31329949e8stevel */
31429949e8stevelstruct sysctrl_soft_state *sys_list = NULL;
31529949e8stevel
31629949e8stevelextern struct mod_ops mod_driverops;
31729949e8stevel
31829949e8stevelstatic struct modldrv modldrv = {
31929949e8stevel	&mod_driverops,		/* Type of module.  This one is a driver */
3201939740Sherry Moore	"Clock Board",		/* name of module */
32129949e8stevel	&sysctrl_ops,		/* driver ops */
32229949e8stevel};
32329949e8stevel
32429949e8stevelstatic struct modlinkage modlinkage = {
32529949e8stevel	MODREV_1,		/* rev */
32629949e8stevel	(void *)&modldrv,
32729949e8stevel	NULL
32829949e8stevel};
32929949e8stevel
33029949e8stevel/*
33129949e8stevel * These are the module initialization routines.
33229949e8stevel */
33329949e8stevel
33429949e8stevelint
33529949e8stevel_init(void)
33629949e8stevel{
33729949e8stevel	int error;
33829949e8stevel
33929949e8stevel	if ((error = ddi_soft_state_init(&sysctrlp,
34029949e8stevel	    sizeof (struct sysctrl_soft_state), 1)) != 0)
34129949e8stevel		return (error);
34229949e8stevel
34329949e8stevel	error = mod_install(&modlinkage);
34429949e8stevel	if (error != 0) {
34529949e8stevel		ddi_soft_state_fini(&sysctrlp);
34629949e8stevel		return (error);
34729949e8stevel	}
34829949e8stevel
34929949e8stevel	mutex_init(&sysctrl_branch_mutex, NULL, MUTEX_DRIVER, NULL);
35029949e8stevel
35129949e8stevel	return (0);
35229949e8stevel}
35329949e8stevel
35429949e8stevelint
35529949e8stevel_fini(void)
35629949e8stevel{
35729949e8stevel	int error;
35829949e8stevel
35929949e8stevel	if ((error = mod_remove(&modlinkage)) != 0)
36029949e8stevel		return (error);
36129949e8stevel
36229949e8stevel	ddi_soft_state_fini(&sysctrlp);
36329949e8stevel
36429949e8stevel	mutex_destroy(&sysctrl_branch_mutex);
36529949e8stevel
36629949e8stevel	return (0);
36729949e8stevel}
36829949e8stevel
36929949e8stevelint
37029949e8stevel_info(struct modinfo *modinfop)
37129949e8stevel{
37229949e8stevel	return (mod_info(&modlinkage, modinfop));
37329949e8stevel}
37429949e8stevel
37529949e8stevel/* ARGSUSED */
37629949e8stevelstatic int
37729949e8stevelsysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
37829949e8stevel{
37929949e8stevel	dev_t	dev;
38029949e8stevel	int	instance;
38129949e8stevel
38229949e8stevel	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
38329949e8stevel		dev = (dev_t)arg;
38429949e8stevel		instance = GETINSTANCE(dev);
38529949e8stevel		*result = (void *)(uintptr_t)instance;
38629949e8stevel		return (DDI_SUCCESS);
38729949e8stevel	}
38829949e8stevel	return (DDI_FAILURE);
38929949e8stevel}
39029949e8stevel
39129949e8stevelstatic int
39229949e8stevelsysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
39329949e8stevel{
39429949e8stevel	struct sysctrl_soft_state *softsp;
39529949e8stevel	int instance;
39629949e8stevel	uchar_t tmp_reg;
39729949e8stevel	dev_info_t *dip;
39829949e8stevel	char *propval;
39929949e8stevel	int proplen;
40029949e8stevel	int slot_num;
40129949e8stevel	int start;		/* start index for scan loop */
40229949e8stevel	int limit;		/* board number limit for scan loop */
40329949e8stevel	int incr;		/* amount to incr each pass thru loop */
40429949e8stevel	void set_clockbrd_info(void);
40529949e8stevel
40629949e8stevel
40729949e8stevel	switch (cmd) {
40829949e8stevel	case DDI_ATTACH:
40929949e8stevel		break;
41029949e8stevel
41129949e8stevel	case DDI_RESUME:
41229949e8stevel		/* XXX see sysctrl:DDI_SUSPEND for special h/w treatment */
41329949e8stevel		return (DDI_SUCCESS);
41429949e8stevel
41529949e8stevel	default:
41629949e8stevel		return (DDI_FAILURE);
41729949e8stevel	}
41829949e8stevel
41929949e8stevel	instance = ddi_get_instance(devi);
42029949e8stevel
42129949e8stevel	if (ddi_soft_state_zalloc(sysctrlp, instance) != DDI_SUCCESS)
42229949e8stevel		return (DDI_FAILURE);
42329949e8stevel
42429949e8stevel	softsp = GETSOFTC(instance);
42529949e8stevel
42629949e8stevel	/* Set the dip in the soft state */
42729949e8stevel	softsp->dip = devi;
42829949e8stevel
42929949e8stevel	/* Set up the parent dip */
43029949e8stevel	softsp->pdip = ddi_get_parent(softsp->dip);
43129949e8stevel
43229949e8stevel	DPRINTF(SYSCTRL_ATTACH_DEBUG, ("sysctrl: devi= 0x%p\n, softsp=0x%p\n",
43307d06daSurya Prakki	    (void *)devi, (void *)softsp));
43429949e8stevel
43529949e8stevel	/* First set all of the timeout values */
43629949e8stevel	spur_timeout_hz = drv_usectohz(SPUR_TIMEOUT_USEC);
43729949e8stevel	spur_long_timeout_hz = drv_usectohz(SPUR_LONG_TIMEOUT_USEC);
43829949e8stevel	ac_timeout_hz = drv_usectohz(AC_TIMEOUT_USEC);
43929949e8stevel	ps_fail_timeout_hz = drv_usectohz(PS_FAIL_TIMEOUT_USEC);
44029949e8stevel	pps_fan_timeout_hz = drv_usectohz(PPS_FAN_TIMEOUT_USEC);
44129949e8stevel	bd_insert_delay_hz = drv_usectohz(BRD_INSERT_DELAY_USEC);
44229949e8stevel	bd_insert_retry_hz = drv_usectohz(BRD_INSERT_RETRY_USEC);
44329949e8stevel	bd_remove_timeout_hz = drv_usectohz(BRD_REMOVE_TIMEOUT_USEC);
44429949e8stevel	blink_led_timeout_hz = drv_usectohz(BLINK_LED_TIMEOUT_USEC);
44529949e8stevel	overtemp_timeout_hz = drv_usectohz(OVERTEMP_TIMEOUT_SEC * MICROSEC);
44629949e8stevel	keyswitch_timeout_hz = drv_usectohz(KEYSWITCH_TIMEOUT_USEC);
44729949e8stevel
44829949e8stevel	/*
44929949e8stevel	 * Map in the registers sets that OBP hands us. According
45029949e8stevel	 * to the sun4u device tree spec., the register sets are as
45129949e8stevel	 * follows:
45229949e8stevel	 *
45329949e8stevel	 *	0	Clock Frequency Registers (contains the bit
45429949e8stevel	 *		for enabling the remote console reset)
45529949e8stevel	 *	1	Misc (has all the registers that we need
45629949e8stevel	 *	2	Clock Version Register
45729949e8stevel	 */
45829949e8stevel	if (ddi_map_regs(softsp->dip, 0,
45929949e8stevel	    (caddr_t *)&softsp->clk_freq1, 0, 0)) {
46029949e8stevel		cmn_err(CE_WARN, "sysctrl%d: unable to map clock frequency "
4611939740Sherry Moore		    "registers", instance);
46229949e8stevel		goto bad0;
46329949e8stevel	}
46429949e8stevel
46529949e8stevel	if (ddi_map_regs(softsp->dip, 1,
46629949e8stevel	    (caddr_t *)&softsp->csr, 0, 0)) {
46729949e8stevel		cmn_err(CE_WARN, "sysctrl%d: unable to map internal"
4681939740Sherry Moore		    "registers", instance);
46929949e8stevel		goto bad1;
47029949e8stevel	}
47129949e8stevel
47229949e8stevel	/*
47329949e8stevel	 * There is a new register for newer vintage clock board nodes,
47429949e8stevel	 * OBP register set 2 in the clock board node.
47529949e8stevel	 *
47629949e8stevel	 */
47729949e8stevel	(void) ddi_map_regs(softsp->dip, 2, (caddr_t *)&softsp->clk_ver, 0, 0);
47829949e8stevel
47929949e8stevel	/*
48029949e8stevel	 * Fill in the virtual addresses of the registers in the
48129949e8stevel	 * sysctrl_soft_state structure. We do not want to calculate
48229949e8stevel	 * them on the fly. This way we waste a little memory, but
48329949e8stevel	 * avoid bugs down the road.
48429949e8stevel	 */
48529949e8stevel	softsp->clk_freq2 = (uchar_t *)((caddr_t)softsp->clk_freq1 +
4861939740Sherry Moore	    SYS_OFF_CLK_FREQ2);
48729949e8stevel
48829949e8stevel	softsp->status1 = (uchar_t *)((caddr_t)softsp->csr +
4891939740Sherry Moore	    SYS_OFF_STAT1);
49029949e8stevel
49129949e8stevel	softsp->status2 = (uchar_t *)((caddr_t)softsp->csr +
4921939740Sherry Moore	    SYS_OFF_STAT2);
49329949e8stevel
49429949e8stevel	softsp->ps_stat = (uchar_t *)((caddr_t)softsp->csr +
4951939740Sherry Moore	    SYS_OFF_PSSTAT);
49629949e8stevel
49729949e8stevel	softsp->ps_pres = (uchar_t *)((caddr_t)softsp->csr +
4981939740Sherry Moore	    SYS_OFF_PSPRES);
49929949e8stevel
50029949e8stevel	softsp->pppsr = (uchar_t *)((caddr_t)softsp->csr +
5011939740Sherry Moore	    SYS_OFF_PPPSR);
50229949e8stevel
50329949e8stevel	softsp->temp_reg = (uchar_t *)((caddr_t)softsp->csr +
5041939740Sherry Moore	    SYS_OFF_TEMP);
50529949e8stevel
50629949e8stevel	set_clockbrd_info();
50729949e8stevel
50829949e8stevel	/*
50929949e8stevel	 * Enable the hardware watchdog gate on the clock board if
51029949e8stevel	 * map_wellknown has detected that watchdog timer is available
51129949e8stevel	 * and user wants it to be enabled.
51229949e8stevel	 */
51329949e8stevel	if (watchdog_available && watchdog_enable)
51429949e8stevel		*(softsp->clk_freq2) |= TOD_RESET_EN;
51529949e8stevel	else
51629949e8stevel		*(softsp->clk_freq2) &= ~TOD_RESET_EN;
51729949e8stevel
51829949e8stevel	/* Check for inherited faults from the PROM. */
51929949e8stevel	if (*softsp->csr & SYS_LED_MID) {
52029949e8stevel		reg_fault(0, FT_PROM, FT_SYSTEM);
52129949e8stevel	}
52229949e8stevel
52329949e8stevel	/*
52429949e8stevel	 * calculate and cache the number of slots on this system
52529949e8stevel	 */
52629949e8stevel	switch (SYS_TYPE(*softsp->status1)) {
52729949e8stevel	case SYS_16_SLOT:
52829949e8stevel		softsp->nslots = 16;
52929949e8stevel		break;
53029949e8stevel
53129949e8stevel	case SYS_8_SLOT:
53229949e8stevel		softsp->nslots = 8;
53329949e8stevel		break;
53429949e8stevel
53529949e8stevel	case SYS_4_SLOT:
53629949e8stevel		/* check the clk_version register - if the ptr is valid */
53729949e8stevel		if ((softsp->clk_ver != NULL) &&
53829949e8stevel		    (SYS_TYPE2(*softsp->clk_ver) == SYS_PLUS_SYSTEM)) {
53929949e8stevel			softsp->nslots = 5;
54029949e8stevel		} else {
54129949e8stevel			softsp->nslots = 4;
54229949e8stevel		}
54329949e8stevel		break;
54429949e8stevel
54529949e8stevel	case SYS_TESTBED:
54629949e8stevel	default:
54729949e8stevel		softsp->nslots = 0;
54829949e8stevel		break;
54929949e8stevel	}
55029949e8stevel
55129949e8stevel
55229949e8stevel	/* create the fault list kstat */
55329949e8stevel	create_ft_kstats(instance);
55429949e8stevel
55529949e8stevel	/*
55629949e8stevel	 * Do a priming read on the ADC, and throw away the first value
55729949e8stevel	 * read. This is a feature of the ADC hardware. After a power cycle
55829949e8stevel	 * it does not contains valid data until a read occurs.
55929949e8stevel	 */
56029949e8stevel	tmp_reg = *(softsp->temp_reg);
56129949e8stevel
56229949e8stevel	/* Wait 30 usec for ADC hardware to stabilize. */
56329949e8stevel	DELAY(30);
56429949e8stevel
56529949e8stevel	/* shut off all interrupt sources */
56629949e8stevel	*(softsp->csr) &= ~(SYS_PPS_FAN_FAIL_EN | SYS_PS_FAIL_EN |
5671939740Sherry Moore	    SYS_AC_PWR_FAIL_EN | SYS_SBRD_PRES_EN);
56829949e8stevel	tmp_reg = *(softsp->csr);
56929949e8stevel#ifdef lint
57029949e8stevel	tmp_reg = tmp_reg;
57129949e8stevel#endif
57229949e8stevel
57329949e8stevel	/*
57429949e8stevel	 * Now register our high interrupt with the system.
57529949e8stevel	 */
57629949e8stevel	if (ddi_add_intr(devi, 0, &softsp->iblock,
57729949e8stevel	    &softsp->idevice, (uint_t (*)(caddr_t))nulldev, NULL) !=
57829949e8stevel	    DDI_SUCCESS)
57929949e8stevel		goto bad2;
58029949e8stevel
58129949e8stevel	mutex_init(&softsp->csr_mutex, NULL, MUTEX_DRIVER,
58229949e8stevel	    (void *)softsp->iblock);
58329949e8stevel
58429949e8stevel	ddi_remove_intr(devi, 0, softsp->iblock);
58529949e8stevel
58629949e8stevel	if (ddi_add_intr(devi, 0, &softsp->iblock,
58729949e8stevel	    &softsp->idevice, system_high_handler, (caddr_t)softsp) !=
58829949e8stevel	    DDI_SUCCESS)
58929949e8stevel		goto bad3;
59029949e8stevel
59129949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_id,
59229949e8stevel	    &softsp->spur_int_c, NULL, spur_delay, (caddr_t)softsp) !=
59329949e8stevel	    DDI_SUCCESS)
59429949e8stevel		goto bad4;
59529949e8stevel
59629949e8stevel	mutex_init(&softsp->spur_int_lock, NULL, MUTEX_DRIVER,
5971939740Sherry Moore	    (void *)softsp->spur_int_c);
59829949e8stevel
59929949e8stevel
60029949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_high_id,
60129949e8stevel	    NULL, NULL, spur_reenable, (caddr_t)softsp) != DDI_SUCCESS)
60229949e8stevel		goto bad5;
60329949e8stevel
60429949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_long_to_id,
60529949e8stevel	    NULL, NULL, spur_clear_count, (caddr_t)softsp) != DDI_SUCCESS)
60629949e8stevel		goto bad6;
60729949e8stevel
60829949e8stevel	/*
60929949e8stevel	 * Now register low-level ac fail handler
61029949e8stevel	 */
61129949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ac_fail_id,
61229949e8stevel	    NULL, NULL, ac_fail_handler, (caddr_t)softsp) != DDI_SUCCESS)
61329949e8stevel		goto bad7;
61429949e8stevel
61529949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ac_fail_high_id,
61629949e8stevel	    NULL, NULL, ac_fail_reenable, (caddr_t)softsp) != DDI_SUCCESS)
61729949e8stevel		goto bad8;
61829949e8stevel
61929949e8stevel	/*
62029949e8stevel	 * Now register low-level ps fail handler
62129949e8stevel	 */
62229949e8stevel
62329949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ps_fail_int_id,
62429949e8stevel	    &softsp->ps_fail_c, NULL, ps_fail_int_handler, (caddr_t)softsp) !=
62529949e8stevel	    DDI_SUCCESS)
62629949e8stevel		goto bad9;
62729949e8stevel
62829949e8stevel	mutex_init(&softsp->ps_fail_lock, NULL, MUTEX_DRIVER,
6291939740Sherry Moore	    (void *)softsp->ps_fail_c);
63029949e8stevel
63129949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ps_fail_poll_id,
63229949e8stevel	    NULL, NULL, ps_fail_poll_handler, (caddr_t)softsp) !=
63329949e8stevel	    DDI_SUCCESS)
63429949e8stevel		goto bad10;
63529949e8stevel
63629949e8stevel	/*
63729949e8stevel	 * Now register low-level pps fan fail handler
63829949e8stevel	 */
63929949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_id,
64029949e8stevel	    NULL, NULL, pps_fanfail_handler, (caddr_t)softsp) !=
64129949e8stevel	    DDI_SUCCESS)
64229949e8stevel		goto bad11;
64329949e8stevel
64429949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_high_id,
64529949e8stevel	    NULL, NULL, pps_fanfail_reenable, (caddr_t)softsp) !=
64629949e8stevel	    DDI_SUCCESS)
64729949e8stevel		goto bad12;
64829949e8stevel
64929949e8stevel	/*
65029949e8stevel	 * Based upon a check for a current share backplane, advise
65129949e8stevel	 * that system does not support hot plug
65229949e8stevel	 *
65329949e8stevel	 */
65429949e8stevel	if ((*(softsp->pppsr) & SYS_NOT_CURRENT_S) != 0) {
65529949e8stevel		cmn_err(CE_NOTE, "Hot Plug not supported in this system");
65629949e8stevel		sysctrl_hotplug_disabled = TRUE;
65729949e8stevel	}
65829949e8stevel
65929949e8stevel	/*
66029949e8stevel	 * If the trigger circuit is busted or the NOT_BRD_PRES line
66129949e8stevel	 * is stuck then OBP will publish this property stating that
66229949e8stevel	 * hot plug is not available.  If this happens we will complain
66329949e8stevel	 * to the console and register a system fault.  We will also
66429949e8stevel	 * not enable the board insert interrupt for this session.
66529949e8stevel	 */
66629949e8stevel	if (ddi_prop_op(DDI_DEV_T_ANY, softsp->dip, PROP_LEN_AND_VAL_ALLOC,
66729949e8stevel	    DDI_PROP_DONTPASS, HOTPLUG_DISABLED_PROPERTY,
66829949e8stevel	    (caddr_t)&propval, &proplen) == DDI_PROP_SUCCESS) {
66929949e8stevel		cmn_err(CE_WARN, "Hot Plug Unavailable [%s]", propval);
67029949e8stevel		reg_fault(0, FT_HOT_PLUG, FT_SYSTEM);
67129949e8stevel		sysctrl_hotplug_disabled = TRUE;
67229949e8stevel		enable_sys_interrupt &= ~SYS_SBRD_PRES_EN;
67329949e8stevel		kmem_free(propval, proplen);
67429949e8stevel	}
67529949e8stevel
67629949e8stevel	sysc_board_connect_supported_init();
67729949e8stevel
67829949e8stevel	fhc_bd_sc_register(sysc_policy_update, softsp);
67929949e8stevel
68029949e8stevel	sysc_slot_info(softsp->nslots, &start, &limit, &incr);
68129949e8stevel
68229949e8stevel	/* Prime the board list. */
68329949e8stevel	fhc_bdlist_prime(start, limit, incr);
68429949e8stevel
68529949e8stevel	/*
68629949e8stevel	 * Set up a board remove timeout call.
68729949e8stevel	 */
68829949e8stevel	(void) fhc_bdlist_lock(-1);
68929949e8stevel
69029949e8stevel	DPRINTF(SYSCTRL_ATTACH_DEBUG,
6911939740Sherry Moore	    ("attach: start bd_remove_poll()..."));
69229949e8stevel
69329949e8stevel	bd_remove_poll(softsp);
69429949e8stevel	fhc_bdlist_unlock();
69529949e8stevel
69629949e8stevel	/*
69729949e8stevel	 * Now register low-level board insert handler
69829949e8stevel	 */
69929949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_pres_id,
70029949e8stevel	    NULL, NULL, bd_insert_handler, (caddr_t)softsp) != DDI_SUCCESS)
70129949e8stevel		goto bad13;
70229949e8stevel
70329949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_gone_id,
70429949e8stevel	    NULL, NULL, bd_insert_normal, (caddr_t)softsp) != DDI_SUCCESS)
70529949e8stevel		goto bad14;
70629949e8stevel
70729949e8stevel	/*
70829949e8stevel	 * Now register led blink handler (interrupt level)
70929949e8stevel	 */
71029949e8stevel	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->blink_led_id,
71129949e8stevel	    &softsp->sys_led_c, NULL, blink_led_handler, (caddr_t)softsp) !=
71229949e8stevel	    DDI_SUCCESS)
71329949e8stevel		goto bad15;
71429949e8stevel	mutex_init(&softsp->sys_led_lock, NULL, MUTEX_DRIVER,
7151939740Sherry Moore	    (void *)softsp->sys_led_c);
71629949e8stevel
71729949e8stevel	/* initialize the bit field for all pps fans to assumed good */
71829949e8stevel	softsp->pps_fan_saved = softsp->pps_fan_external_state =
7191939740Sherry Moore	    SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK;
72029949e8stevel
72129949e8stevel	/* prime the power supply state machines */
72229949e8stevel	if (enable_sys_interrupt & SYS_PS_FAIL_EN)
72329949e8stevel		ddi_trigger_softintr(softsp->ps_fail_poll_id);
72429949e8stevel
72529949e8stevel
72629949e8stevel	/* kick off the OS led blinker */
72729949e8stevel	softsp->sys_led = FALSE;
72829949e8stevel	ddi_trigger_softintr(softsp->blink_led_id);
72929949e8stevel
73029949e8stevel	/* Now enable selected interrupt sources */
73129949e8stevel	mutex_enter(&softsp->csr_mutex);
73229949e8stevel	*(softsp->csr) |= enable_sys_interrupt &
7331939740Sherry Moore	    (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
7341939740Sherry Moore	    SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
73529949e8stevel	tmp_reg = *(softsp->csr);
73629949e8stevel#ifdef lint
73729949e8stevel	tmp_reg = tmp_reg;
73829949e8stevel#endif
73929949e8stevel	mutex_exit(&softsp->csr_mutex);
74029949e8stevel
74129949e8stevel	/* Initialize the temperature */
74229949e8stevel	init_temp_arrays(&softsp->tempstat);
74329949e8stevel
74429949e8stevel	/*
74529949e8stevel	 * initialize key switch shadow state
74629949e8stevel	 */
74729949e8stevel	softsp->key_shadow = KEY_BOOT;
74829949e8stevel
74929949e8stevel	/*
75029949e8stevel	 * Now add this soft state structure to the front of the linked list
75129949e8stevel	 * of soft state structures.
75229949e8stevel	 */
75329949e8stevel	if (sys_list == (struct sysctrl_soft_state *)NULL) {
75429949e8stevel		mutex_init(&sslist_mutex, NULL, MUTEX_DEFAULT, NULL);
75529949e8stevel	}
75629949e8stevel	mutex_enter(&sslist_mutex);
75729949e8stevel	softsp->next = sys_list;
75829949e8stevel	sys_list = softsp;
75929949e8stevel	mutex_exit(&sslist_mutex);
76029949e8stevel
76129949e8stevel	/* Setup the kstats for this device */
76229949e8stevel	sysctrl_add_kstats(softsp);
76329949e8stevel
76429949e8stevel	/* kick off the PPS fan poll routine */
76529949e8stevel	pps_fan_poll(softsp);
76629949e8stevel
76729949e8stevel	if (sysctrl_overtemp_thread_started == 0) {
76829949e8stevel		/*
76929949e8stevel		 * set up the overtemp condition variable before
77029949e8stevel		 * starting the thread.
77129949e8stevel		 */
77229949e8stevel		cv_init(&overtemp_cv, NULL, CV_DRIVER, NULL);
77329949e8stevel
77429949e8stevel		/*
77529949e8stevel		 * start up the overtemp polling thread
77629949e8stevel		 */
77729949e8stevel		(void) thread_create(NULL, 0, (void (*)())sysctrl_overtemp_poll,
77829949e8stevel		    NULL, 0, &p0, TS_RUN, minclsyspri);
77929949e8stevel		sysctrl_overtemp_thread_started++;
78029949e8stevel	}
78129949e8stevel
78229949e8stevel	if (sysctrl_keyswitch_thread_started == 0) {
78329949e8stevel		extern void (*abort_seq_handler)();
78429949e8stevel
78529949e8stevel		/*
78629949e8stevel		 * interpose sysctrl's abort sequence handler
78729949e8stevel		 */
78829949e8stevel		abort_seq_handler = sysctrl_abort_seq_handler;
78929949e8stevel
79029949e8stevel		/*
79129949e8stevel		 * set up the key switch condition variable before
79229949e8stevel		 * starting the thread
79329949e8stevel		 */
79429949e8stevel		cv_init(&keyswitch_cv, NULL, CV_DRIVER, NULL);
79529949e8stevel
79629949e8stevel		/*
79729949e8stevel		 * start up the key switch polling thread
79829949e8stevel		 */
79929949e8stevel		(void) thread_create(NULL, 0,
80029949e8stevel		    (void (*)())sysctrl_keyswitch_poll, NULL, 0, &p0,
80129949e8stevel		    TS_RUN, minclsyspri);
80229949e8stevel		sysctrl_keyswitch_thread_started++;
80329949e8stevel	}
80429949e8stevel
80529949e8stevel	/*
80629949e8stevel	 * perform initialization to allow setting of powerfail-time
80729949e8stevel	 */
80829949e8stevel	if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL)
80929949e8stevel		softsp->options_nodeid = (pnode_t)NULL;
81029949e8stevel	else
81129949e8stevel		softsp->options_nodeid = (pnode_t)ddi_get_nodeid(dip);
81229949e8stevel
81329949e8stevel	DPRINTF(SYSCTRL_ATTACH_DEBUG,
8141939740Sherry Moore	    ("sysctrl: Creating devices start:%d, limit:%d, incr:%d\n",
8151939740Sherry Moore	    start, limit, incr));
81629949e8stevel
81729949e8stevel	/*
81829949e8stevel	 * Create minor node for each system attachment points
81929949e8stevel	 */
82029949e8stevel	for (slot_num = start; slot_num < limit; slot_num = slot_num + incr) {
82129949e8stevel		char name[30];
82229949e8stevel		(void) sprintf(name, "slot%d", slot_num);
82329949e8stevel		if (ddi_create_minor_node(devi, name, S_IFCHR,
82429949e8stevel		    (PUTINSTANCE(instance) | slot_num),
82529949e8stevel		    DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
82629949e8stevel			cmn_err(CE_WARN, "sysctrl%d: \"%s\" "
8271939740Sherry Moore			    "ddi_create_minor_node failed",
828