11341Sstevel /*
21341Sstevel * CDDL HEADER START
31341Sstevel *
41341Sstevel * The contents of this file are subject to the terms of the
51341Sstevel * Common Development and Distribution License (the "License").
61341Sstevel * You may not use this file except in compliance with the License.
71341Sstevel *
81341Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91341Sstevel * or http://www.opensolaris.org/os/licensing.
101341Sstevel * See the License for the specific language governing permissions
111341Sstevel * and limitations under the License.
121341Sstevel *
131341Sstevel * When distributing Covered Code, include this CDDL HEADER in each
141341Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151341Sstevel * If applicable, add the following below this CDDL HEADER, with the
161341Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
171341Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
181341Sstevel *
191341Sstevel * CDDL HEADER END
201341Sstevel */
211341Sstevel
221341Sstevel /*
23*11311SSurya.Prakki@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241341Sstevel * Use is subject to license terms.
251341Sstevel */
261341Sstevel
271341Sstevel
281341Sstevel #include <sys/types.h>
291341Sstevel #include <sys/conf.h>
301341Sstevel #include <sys/ddi.h>
311341Sstevel #include <sys/sunddi.h>
321341Sstevel #include <sys/ddi_impldefs.h>
331341Sstevel #include <sys/sunndi.h>
341341Sstevel #include <sys/ndi_impldefs.h>
351341Sstevel #include <sys/obpdefs.h>
361341Sstevel #include <sys/cmn_err.h>
371341Sstevel #include <sys/errno.h>
381341Sstevel #include <sys/kmem.h>
391341Sstevel #include <sys/debug.h>
401341Sstevel #include <sys/sysmacros.h>
411341Sstevel #include <sys/ivintr.h>
421341Sstevel #include <sys/autoconf.h>
431341Sstevel #include <sys/intreg.h>
441341Sstevel #include <sys/proc.h>
451341Sstevel #include <sys/modctl.h>
461341Sstevel #include <sys/callb.h>
471341Sstevel #include <sys/file.h>
481341Sstevel #include <sys/open.h>
491341Sstevel #include <sys/stat.h>
501341Sstevel #include <sys/fhc.h>
511341Sstevel #include <sys/sysctrl.h>
521341Sstevel #include <sys/jtag.h>
531341Sstevel #include <sys/ac.h>
541341Sstevel #include <sys/simmstat.h>
551341Sstevel #include <sys/clock.h>
561341Sstevel #include <sys/promif.h>
571341Sstevel #include <sys/promimpl.h>
581341Sstevel #include <sys/sunndi.h>
591341Sstevel #include <sys/machsystm.h>
601341Sstevel
611341Sstevel /* Useful debugging Stuff */
621341Sstevel #ifdef DEBUG
631341Sstevel int sysc_debug_info = 1;
641341Sstevel int sysc_debug_print_level = 0;
651341Sstevel #endif
661341Sstevel
671341Sstevel /*
681341Sstevel * Function prototypes
691341Sstevel */
701341Sstevel static int sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
711341Sstevel void **result);
721341Sstevel
731341Sstevel static int sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
741341Sstevel
751341Sstevel static int sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
761341Sstevel
771341Sstevel static int sysctrl_open(dev_t *, int, int, cred_t *);
781341Sstevel
791341Sstevel static int sysctrl_close(dev_t, int, int, cred_t *);
801341Sstevel
811341Sstevel static int sysctrl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
821341Sstevel
831341Sstevel static uint_t system_high_handler(caddr_t arg);
841341Sstevel
851341Sstevel static uint_t spur_delay(caddr_t arg);
861341Sstevel
871341Sstevel static void spur_retry(void *);
881341Sstevel
891341Sstevel static uint_t spur_reenable(caddr_t arg);
901341Sstevel
911341Sstevel static void spur_long_timeout(void *);
921341Sstevel
931341Sstevel static uint_t spur_clear_count(caddr_t arg);
941341Sstevel
951341Sstevel static uint_t ac_fail_handler(caddr_t arg);
961341Sstevel
971341Sstevel static void ac_fail_retry(void *);
981341Sstevel
991341Sstevel static uint_t ac_fail_reenable(caddr_t arg);
1001341Sstevel
1011341Sstevel static uint_t ps_fail_int_handler(caddr_t arg);
1021341Sstevel
1031341Sstevel static uint_t ps_fail_poll_handler(caddr_t arg);
1041341Sstevel
1051341Sstevel static uint_t ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint);
1061341Sstevel
1071341Sstevel enum power_state compute_power_state(struct sysctrl_soft_state *softsp,
1081341Sstevel int plus_load);
1091341Sstevel
1101341Sstevel static void ps_log_state_change(struct sysctrl_soft_state *softsp,
1111341Sstevel int index, int present);
1121341Sstevel
1131341Sstevel static void ps_log_pres_change(struct sysctrl_soft_state *softsp,
1141341Sstevel int index, int present);
1151341Sstevel
1161341Sstevel static void ps_fail_retry(void *);
1171341Sstevel
1181341Sstevel static uint_t pps_fanfail_handler(caddr_t arg);
1191341Sstevel
1201341Sstevel static void pps_fanfail_retry(void *);
1211341Sstevel
1221341Sstevel static uint_t pps_fanfail_reenable(caddr_t arg);
1231341Sstevel
1241341Sstevel static void pps_fan_poll(void *);
1251341Sstevel
1261341Sstevel static void pps_fan_state_change(struct sysctrl_soft_state *softsp,
1271341Sstevel int index, int fan_ok);
1281341Sstevel
1291341Sstevel static uint_t bd_insert_handler(caddr_t arg);
1301341Sstevel
1311341Sstevel static void bd_insert_timeout(void *);
1321341Sstevel
1331341Sstevel static void bd_remove_timeout(void *);
1341341Sstevel
1351341Sstevel static uint_t bd_insert_normal(caddr_t arg);
1361341Sstevel
1371341Sstevel static void sysctrl_add_kstats(struct sysctrl_soft_state *softsp);
1381341Sstevel
1391341Sstevel static int sysctrl_kstat_update(kstat_t *ksp, int rw);
1401341Sstevel
1411341Sstevel static int psstat_kstat_update(kstat_t *, int);
1421341Sstevel
1431341Sstevel static void init_remote_console_uart(struct sysctrl_soft_state *);
1441341Sstevel
1451341Sstevel static void blink_led_timeout(void *);
1461341Sstevel
1471341Sstevel static uint_t blink_led_handler(caddr_t arg);
1481341Sstevel
1491341Sstevel static void sysctrl_thread_wakeup(void *type);
1501341Sstevel
1511341Sstevel static void sysctrl_overtemp_poll(void);
1521341Sstevel
1531341Sstevel static void sysctrl_keyswitch_poll(void);
1541341Sstevel
1551341Sstevel static void update_key_state(struct sysctrl_soft_state *);
1561341Sstevel
1571341Sstevel static void sysctrl_abort_seq_handler(char *msg);
1581341Sstevel
1591341Sstevel static void nvram_update_powerfail(struct sysctrl_soft_state *softsp);
1601341Sstevel
1611341Sstevel static void toggle_board_green_leds(int);
1621341Sstevel
1631341Sstevel void bd_remove_poll(struct sysctrl_soft_state *);
1641341Sstevel
1651341Sstevel static void sysc_slot_info(int nslots, int *start, int *limit, int *incr);
1661341Sstevel
1671341Sstevel extern void sysc_board_connect_supported_init(void);
1681341Sstevel
1691341Sstevel static void rcons_reinit(struct sysctrl_soft_state *softsp);
1701341Sstevel
1711341Sstevel /*
1721341Sstevel * Configuration data structures
1731341Sstevel */
1741341Sstevel static struct cb_ops sysctrl_cb_ops = {
1751341Sstevel sysctrl_open, /* open */
1761341Sstevel sysctrl_close, /* close */
1771341Sstevel nulldev, /* strategy */
1781341Sstevel nulldev, /* print */
1791341Sstevel nulldev, /* dump */
1801341Sstevel nulldev, /* read */
1811341Sstevel nulldev, /* write */
1821341Sstevel sysctrl_ioctl, /* ioctl */
1831341Sstevel nodev, /* devmap */
1841341Sstevel nodev, /* mmap */
1851341Sstevel nodev, /* segmap */
1861341Sstevel nochpoll, /* poll */
1871341Sstevel ddi_prop_op, /* cb_prop_op */
1881341Sstevel 0, /* streamtab */
1891341Sstevel D_MP|D_NEW, /* Driver compatibility flag */
1901341Sstevel CB_REV, /* rev */
1911341Sstevel nodev, /* cb_aread */
1921341Sstevel nodev /* cb_awrite */
1931341Sstevel };
1941341Sstevel
1951341Sstevel static struct dev_ops sysctrl_ops = {
1961341Sstevel DEVO_REV, /* devo_rev */
1971341Sstevel 0, /* refcnt */
1981341Sstevel sysctrl_info, /* getinfo */
1991341Sstevel nulldev, /* identify */
2001341Sstevel nulldev, /* probe */
2011341Sstevel sysctrl_attach, /* attach */
2021341Sstevel sysctrl_detach, /* detach */
2031341Sstevel nulldev, /* reset */
2041341Sstevel &sysctrl_cb_ops, /* cb_ops */
2051341Sstevel (struct bus_ops *)0, /* bus_ops */
2067656SSherry.Moore@Sun.COM nulldev, /* power */
2077656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */
2081341Sstevel };
2091341Sstevel
2101341Sstevel void *sysctrlp; /* sysctrl soft state hook */
2111341Sstevel
2121341Sstevel /* # of ticks to silence spurious interrupts */
2131341Sstevel static clock_t spur_timeout_hz;
2141341Sstevel
2151341Sstevel /* # of ticks to count spurious interrupts to print message */
2161341Sstevel static clock_t spur_long_timeout_hz;
2171341Sstevel
2181341Sstevel /* # of ticks between AC failure polling */
2191341Sstevel static clock_t ac_timeout_hz;
2201341Sstevel
2211341Sstevel /* # of ticks between Power Supply Failure polling */
2221341Sstevel static clock_t ps_fail_timeout_hz;
2231341Sstevel
2241341Sstevel /*
2251341Sstevel * # of ticks between Peripheral Power Supply failure polling
2261341Sstevel * (used both for interrupt retry timeout and polling function)
2271341Sstevel */
2281341Sstevel static clock_t pps_fan_timeout_hz;
2291341Sstevel
2301341Sstevel /* # of ticks delay after board insert interrupt */
2311341Sstevel static clock_t bd_insert_delay_hz;
2321341Sstevel
2331341Sstevel /* # of secs to wait before restarting poll if we cannot clear interrupts */
2341341Sstevel static clock_t bd_insert_retry_hz;
2351341Sstevel
2361341Sstevel /* # of secs between Board Removal polling */
2371341Sstevel static clock_t bd_remove_timeout_hz;
2381341Sstevel
2391341Sstevel /* # of secs between toggle of OS LED */
2401341Sstevel static clock_t blink_led_timeout_hz;
2411341Sstevel
2421341Sstevel /* overtemp polling routine timeout delay */
2431341Sstevel static clock_t overtemp_timeout_hz;
2441341Sstevel
2451341Sstevel /* key switch polling routine timeout delay */
2461341Sstevel static clock_t keyswitch_timeout_hz;
2471341Sstevel
2481341Sstevel /* Specify which system interrupt condition to monitor */
2491341Sstevel int enable_sys_interrupt = SYS_AC_PWR_FAIL_EN | SYS_PPS_FAN_FAIL_EN |
2501341Sstevel SYS_PS_FAIL_EN | SYS_SBRD_PRES_EN;
2511341Sstevel
2521341Sstevel /* Should the overtemp_poll thread be running? */
2531341Sstevel static int sysctrl_do_overtemp_thread = 1;
2541341Sstevel
2551341Sstevel /* Should the keyswitch_poll thread be running? */
2561341Sstevel static int sysctrl_do_keyswitch_thread = 1;
2571341Sstevel
2581341Sstevel /*
2591341Sstevel * This timeout ID is for board remove polling routine. It is
2601341Sstevel * protected by the fhc_bdlist mutex.
2611341Sstevel * XXX - This will not work for wildfire. A different scheme must be
2621341Sstevel * used since there will be multiple sysctrl nodes, each with its
2631341Sstevel * own list of hotplugged boards to scan.
2641341Sstevel */
2651341Sstevel static timeout_id_t bd_remove_to_id = 0;
2661341Sstevel
2671341Sstevel /*
2681341Sstevel * If this is set, the system will not shutdown when insufficient power
2691341Sstevel * condition persists.
2701341Sstevel */
2711341Sstevel int disable_insufficient_power_reboot = 0;
2721341Sstevel
2731341Sstevel /*
2741341Sstevel * Set this to enable suspend/resume
2751341Sstevel */
2761341Sstevel int sysctrl_enable_detach_suspend = 0;
2771341Sstevel
2781341Sstevel /*
2791341Sstevel * Set this to reflect the OBP initialized HOTPLUG_DISABLED_PROPERTY and
2801341Sstevel * during dynamic detection
2811341Sstevel */
2821341Sstevel int sysctrl_hotplug_disabled = FALSE;
2831341Sstevel
2841341Sstevel /* Indicates whether or not the overtemp thread has been started */
2851341Sstevel static int sysctrl_overtemp_thread_started = 0;
2861341Sstevel
2871341Sstevel /* Indicates whether or not the key switch thread has been started */
2881341Sstevel static int sysctrl_keyswitch_thread_started = 0;
2891341Sstevel
2901341Sstevel /* *Mutex used to protect the soft state list */
2911341Sstevel static kmutex_t sslist_mutex;
2921341Sstevel
2931341Sstevel /* The CV is used to wakeup the overtemp thread when needed. */
2941341Sstevel static kcondvar_t overtemp_cv;
2951341Sstevel
2961341Sstevel /* The CV is used to wakeup the key switch thread when needed. */
2971341Sstevel static kcondvar_t keyswitch_cv;
2981341Sstevel
2991341Sstevel /* This mutex is used to protect the sysctrl_ddi_branch_init variable */
3001341Sstevel static kmutex_t sysctrl_branch_mutex;
3011341Sstevel
3021341Sstevel /*
3031341Sstevel * This variable is set after all existing branches in the system have
3041341Sstevel * been discovered and held via e_ddi_branch_hold(). This happens on
3051341Sstevel * first open() of any sysctrl minor node.
3061341Sstevel */
3071341Sstevel static int sysctrl_ddi_branch_init;
3081341Sstevel
3091341Sstevel /*
3101341Sstevel * Linked list of all syctrl soft state structures.
3111341Sstevel * Used for polling sysctrl state changes, i.e. temperature.
3121341Sstevel */
3131341Sstevel struct sysctrl_soft_state *sys_list = NULL;
3141341Sstevel
3151341Sstevel extern struct mod_ops mod_driverops;
3161341Sstevel
3171341Sstevel static struct modldrv modldrv = {
3181341Sstevel &mod_driverops, /* Type of module. This one is a driver */
3197656SSherry.Moore@Sun.COM "Clock Board", /* name of module */
3201341Sstevel &sysctrl_ops, /* driver ops */
3211341Sstevel };
3221341Sstevel
3231341Sstevel static struct modlinkage modlinkage = {
3241341Sstevel MODREV_1, /* rev */
3251341Sstevel (void *)&modldrv,
3261341Sstevel NULL
3271341Sstevel };
3281341Sstevel
3291341Sstevel #ifndef lint
3301366Spetede char _depends_on[] = "drv/fhc";
3311341Sstevel #endif /* lint */
3321341Sstevel
3331341Sstevel /*
3341341Sstevel * These are the module initialization routines.
3351341Sstevel */
3361341Sstevel
3371341Sstevel int
_init(void)3381341Sstevel _init(void)
3391341Sstevel {
3401341Sstevel int error;
3411341Sstevel
3421341Sstevel if ((error = ddi_soft_state_init(&sysctrlp,
3431341Sstevel sizeof (struct sysctrl_soft_state), 1)) != 0)
3441341Sstevel return (error);
3451341Sstevel
3461341Sstevel error = mod_install(&modlinkage);
3471341Sstevel if (error != 0) {
3481341Sstevel ddi_soft_state_fini(&sysctrlp);
3491341Sstevel return (error);
3501341Sstevel }
3511341Sstevel
3521341Sstevel mutex_init(&sysctrl_branch_mutex, NULL, MUTEX_DRIVER, NULL);
3531341Sstevel
3541341Sstevel return (0);
3551341Sstevel }
3561341Sstevel
3571341Sstevel int
_fini(void)3581341Sstevel _fini(void)
3591341Sstevel {
3601341Sstevel int error;
3611341Sstevel
3621341Sstevel if ((error = mod_remove(&modlinkage)) != 0)
3631341Sstevel return (error);
3641341Sstevel
3651341Sstevel ddi_soft_state_fini(&sysctrlp);
3661341Sstevel
3671341Sstevel mutex_destroy(&sysctrl_branch_mutex);
3681341Sstevel
3691341Sstevel return (0);
3701341Sstevel }
3711341Sstevel
3721341Sstevel int
_info(struct modinfo * modinfop)3731341Sstevel _info(struct modinfo *modinfop)
3741341Sstevel {
3751341Sstevel return (mod_info(&modlinkage, modinfop));
3761341Sstevel }
3771341Sstevel
3781341Sstevel /* ARGSUSED */
3791341Sstevel static int
sysctrl_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)3801341Sstevel sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
3811341Sstevel {
3821341Sstevel dev_t dev;
3831341Sstevel int instance;
3841341Sstevel
3851341Sstevel if (infocmd == DDI_INFO_DEVT2INSTANCE) {
3861341Sstevel dev = (dev_t)arg;
3871341Sstevel instance = GETINSTANCE(dev);
3881341Sstevel *result = (void *)(uintptr_t)instance;
3891341Sstevel return (DDI_SUCCESS);
3901341Sstevel }
3911341Sstevel return (DDI_FAILURE);
3921341Sstevel }
3931341Sstevel
3941341Sstevel static int
sysctrl_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)3951341Sstevel sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
3961341Sstevel {
3971341Sstevel struct sysctrl_soft_state *softsp;
3981341Sstevel int instance;
3991341Sstevel uchar_t tmp_reg;
4001341Sstevel dev_info_t *dip;
4011341Sstevel char *propval;
4021341Sstevel int proplen;
4031341Sstevel int slot_num;
4041341Sstevel int start; /* start index for scan loop */
4051341Sstevel int limit; /* board number limit for scan loop */
4061341Sstevel int incr; /* amount to incr each pass thru loop */
4071341Sstevel void set_clockbrd_info(void);
4081341Sstevel
4091341Sstevel
4101341Sstevel switch (cmd) {
4111341Sstevel case DDI_ATTACH:
4121341Sstevel break;
4131341Sstevel
4141341Sstevel case DDI_RESUME:
4151341Sstevel /* XXX see sysctrl:DDI_SUSPEND for special h/w treatment */
4161341Sstevel return (DDI_SUCCESS);
4171341Sstevel
4181341Sstevel default:
4191341Sstevel return (DDI_FAILURE);
4201341Sstevel }
4211341Sstevel
4221341Sstevel instance = ddi_get_instance(devi);
4231341Sstevel
4241341Sstevel if (ddi_soft_state_zalloc(sysctrlp, instance) != DDI_SUCCESS)
4251341Sstevel return (DDI_FAILURE);
4261341Sstevel
4271341Sstevel softsp = GETSOFTC(instance);
4281341Sstevel
4291341Sstevel /* Set the dip in the soft state */
4301341Sstevel softsp->dip = devi;
4311341Sstevel
4321341Sstevel /* Set up the parent dip */
4331341Sstevel softsp->pdip = ddi_get_parent(softsp->dip);
4341341Sstevel
4351341Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, ("sysctrl: devi= 0x%p\n, softsp=0x%p\n",
436*11311SSurya.Prakki@Sun.COM (void *)devi, (void *)softsp));
4371341Sstevel
4381341Sstevel /* First set all of the timeout values */
4391341Sstevel spur_timeout_hz = drv_usectohz(SPUR_TIMEOUT_USEC);
4401341Sstevel spur_long_timeout_hz = drv_usectohz(SPUR_LONG_TIMEOUT_USEC);
4411341Sstevel ac_timeout_hz = drv_usectohz(AC_TIMEOUT_USEC);
4421341Sstevel ps_fail_timeout_hz = drv_usectohz(PS_FAIL_TIMEOUT_USEC);
4431341Sstevel pps_fan_timeout_hz = drv_usectohz(PPS_FAN_TIMEOUT_USEC);
4441341Sstevel bd_insert_delay_hz = drv_usectohz(BRD_INSERT_DELAY_USEC);
4451341Sstevel bd_insert_retry_hz = drv_usectohz(BRD_INSERT_RETRY_USEC);
4461341Sstevel bd_remove_timeout_hz = drv_usectohz(BRD_REMOVE_TIMEOUT_USEC);
4471341Sstevel blink_led_timeout_hz = drv_usectohz(BLINK_LED_TIMEOUT_USEC);
4481341Sstevel overtemp_timeout_hz = drv_usectohz(OVERTEMP_TIMEOUT_SEC * MICROSEC);
4491341Sstevel keyswitch_timeout_hz = drv_usectohz(KEYSWITCH_TIMEOUT_USEC);
4501341Sstevel
4511341Sstevel /*
4521341Sstevel * Map in the registers sets that OBP hands us. According
4531341Sstevel * to the sun4u device tree spec., the register sets are as
4541341Sstevel * follows:
4551341Sstevel *
4561341Sstevel * 0 Clock Frequency Registers (contains the bit
4571341Sstevel * for enabling the remote console reset)
4581341Sstevel * 1 Misc (has all the registers that we need
4591341Sstevel * 2 Clock Version Register
4601341Sstevel */
4611341Sstevel if (ddi_map_regs(softsp->dip, 0,
4621341Sstevel (caddr_t *)&softsp->clk_freq1, 0, 0)) {
4631341Sstevel cmn_err(CE_WARN, "sysctrl%d: unable to map clock frequency "
4647656SSherry.Moore@Sun.COM "registers", instance);
4651341Sstevel goto bad0;
4661341Sstevel }
4671341Sstevel
4681341Sstevel if (ddi_map_regs(softsp->dip, 1,
4691341Sstevel (caddr_t *)&softsp->csr, 0, 0)) {
4701341Sstevel cmn_err(CE_WARN, "sysctrl%d: unable to map internal"
4717656SSherry.Moore@Sun.COM "registers", instance);
4721341Sstevel goto bad1;
4731341Sstevel }
4741341Sstevel
4751341Sstevel /*
4761341Sstevel * There is a new register for newer vintage clock board nodes,
4771341Sstevel * OBP register set 2 in the clock board node.
4781341Sstevel *
4791341Sstevel */
4801341Sstevel (void) ddi_map_regs(softsp->dip, 2, (caddr_t *)&softsp->clk_ver, 0, 0);
4811341Sstevel
4821341Sstevel /*
4831341Sstevel * Fill in the virtual addresses of the registers in the
4841341Sstevel * sysctrl_soft_state structure. We do not want to calculate
4851341Sstevel * them on the fly. This way we waste a little memory, but
4861341Sstevel * avoid bugs down the road.
4871341Sstevel */
4881341Sstevel softsp->clk_freq2 = (uchar_t *)((caddr_t)softsp->clk_freq1 +
4897656SSherry.Moore@Sun.COM SYS_OFF_CLK_FREQ2);
4901341Sstevel
4911341Sstevel softsp->status1 = (uchar_t *)((caddr_t)softsp->csr +
4927656SSherry.Moore@Sun.COM SYS_OFF_STAT1);
4931341Sstevel
4941341Sstevel softsp->status2 = (uchar_t *)((caddr_t)softsp->csr +
4957656SSherry.Moore@Sun.COM SYS_OFF_STAT2);
4961341Sstevel
4971341Sstevel softsp->ps_stat = (uchar_t *)((caddr_t)softsp->csr +
4987656SSherry.Moore@Sun.COM SYS_OFF_PSSTAT);
4991341Sstevel
5001341Sstevel softsp->ps_pres = (uchar_t *)((caddr_t)softsp->csr +
5017656SSherry.Moore@Sun.COM SYS_OFF_PSPRES);
5021341Sstevel
5031341Sstevel softsp->pppsr = (uchar_t *)((caddr_t)softsp->csr +
5047656SSherry.Moore@Sun.COM SYS_OFF_PPPSR);
5051341Sstevel
5061341Sstevel softsp->temp_reg = (uchar_t *)((caddr_t)softsp->csr +
5077656SSherry.Moore@Sun.COM SYS_OFF_TEMP);
5081341Sstevel
5091341Sstevel set_clockbrd_info();
5101341Sstevel
5111341Sstevel /*
5121341Sstevel * Enable the hardware watchdog gate on the clock board if
5131341Sstevel * map_wellknown has detected that watchdog timer is available
5141341Sstevel * and user wants it to be enabled.
5151341Sstevel */
5161341Sstevel if (watchdog_available && watchdog_enable)
5171341Sstevel *(softsp->clk_freq2) |= TOD_RESET_EN;
5181341Sstevel else
5191341Sstevel *(softsp->clk_freq2) &= ~TOD_RESET_EN;
5201341Sstevel
5211341Sstevel /* Check for inherited faults from the PROM. */
5221341Sstevel if (*softsp->csr & SYS_LED_MID) {
5231341Sstevel reg_fault(0, FT_PROM, FT_SYSTEM);
5241341Sstevel }
5251341Sstevel
5261341Sstevel /*
5271341Sstevel * calculate and cache the number of slots on this system
5281341Sstevel */
5291341Sstevel switch (SYS_TYPE(*softsp->status1)) {
5301341Sstevel case SYS_16_SLOT:
5311341Sstevel softsp->nslots = 16;
5321341Sstevel break;
5331341Sstevel
5341341Sstevel case SYS_8_SLOT:
5351341Sstevel softsp->nslots = 8;
5361341Sstevel break;
5371341Sstevel
5381341Sstevel case SYS_4_SLOT:
5391341Sstevel /* check the clk_version register - if the ptr is valid */
5401341Sstevel if ((softsp->clk_ver != NULL) &&
5411341Sstevel (SYS_TYPE2(*softsp->clk_ver) == SYS_PLUS_SYSTEM)) {
5421341Sstevel softsp->nslots = 5;
5431341Sstevel } else {
5441341Sstevel softsp->nslots = 4;
5451341Sstevel }
5461341Sstevel break;
5471341Sstevel
5481341Sstevel case SYS_TESTBED:
5491341Sstevel default:
5501341Sstevel softsp->nslots = 0;
5511341Sstevel break;
5521341Sstevel }
5531341Sstevel
5541341Sstevel
5551341Sstevel /* create the fault list kstat */
5561341Sstevel create_ft_kstats(instance);
5571341Sstevel
5581341Sstevel /*
5591341Sstevel * Do a priming read on the ADC, and throw away the first value
5601341Sstevel * read. This is a feature of the ADC hardware. After a power cycle
5611341Sstevel * it does not contains valid data until a read occurs.
5621341Sstevel */
5631341Sstevel tmp_reg = *(softsp->temp_reg);
5641341Sstevel
5651341Sstevel /* Wait 30 usec for ADC hardware to stabilize. */
5661341Sstevel DELAY(30);
5671341Sstevel
5681341Sstevel /* shut off all interrupt sources */
5691341Sstevel *(softsp->csr) &= ~(SYS_PPS_FAN_FAIL_EN | SYS_PS_FAIL_EN |
5707656SSherry.Moore@Sun.COM SYS_AC_PWR_FAIL_EN | SYS_SBRD_PRES_EN);
5711341Sstevel tmp_reg = *(softsp->csr);
5721341Sstevel #ifdef lint
5731341Sstevel tmp_reg = tmp_reg;
5741341Sstevel #endif
5751341Sstevel
5761341Sstevel /*
5771341Sstevel * Now register our high interrupt with the system.
5781341Sstevel */
5791341Sstevel if (ddi_add_intr(devi, 0, &softsp->iblock,
5801341Sstevel &softsp->idevice, (uint_t (*)(caddr_t))nulldev, NULL) !=
5811341Sstevel DDI_SUCCESS)
5821341Sstevel goto bad2;
5831341Sstevel
5841341Sstevel mutex_init(&softsp->csr_mutex, NULL, MUTEX_DRIVER,
5851341Sstevel (void *)softsp->iblock);
5861341Sstevel
5871341Sstevel ddi_remove_intr(devi, 0, softsp->iblock);
5881341Sstevel
5891341Sstevel if (ddi_add_intr(devi, 0, &softsp->iblock,
5901341Sstevel &softsp->idevice, system_high_handler, (caddr_t)softsp) !=
5911341Sstevel DDI_SUCCESS)
5921341Sstevel goto bad3;
5931341Sstevel
5941341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_id,
5951341Sstevel &softsp->spur_int_c, NULL, spur_delay, (caddr_t)softsp) !=
5961341Sstevel DDI_SUCCESS)
5971341Sstevel goto bad4;
5981341Sstevel
5991341Sstevel mutex_init(&softsp->spur_int_lock, NULL, MUTEX_DRIVER,
6007656SSherry.Moore@Sun.COM (void *)softsp->spur_int_c);
6011341Sstevel
6021341Sstevel
6031341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_high_id,
6041341Sstevel NULL, NULL, spur_reenable, (caddr_t)softsp) != DDI_SUCCESS)
6051341Sstevel goto bad5;
6061341Sstevel
6071341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_long_to_id,
6081341Sstevel NULL, NULL, spur_clear_count, (caddr_t)softsp) != DDI_SUCCESS)
6091341Sstevel goto bad6;
6101341Sstevel
6111341Sstevel /*
6121341Sstevel * Now register low-level ac fail handler
6131341Sstevel */
6141341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ac_fail_id,
6151341Sstevel NULL, NULL, ac_fail_handler, (caddr_t)softsp) != DDI_SUCCESS)
6161341Sstevel goto bad7;
6171341Sstevel
6181341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ac_fail_high_id,
6191341Sstevel NULL, NULL, ac_fail_reenable, (caddr_t)softsp) != DDI_SUCCESS)
6201341Sstevel goto bad8;
6211341Sstevel
6221341Sstevel /*
6231341Sstevel * Now register low-level ps fail handler
6241341Sstevel */
6251341Sstevel
6261341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ps_fail_int_id,
6271341Sstevel &softsp->ps_fail_c, NULL, ps_fail_int_handler, (caddr_t)softsp) !=
6281341Sstevel DDI_SUCCESS)
6291341Sstevel goto bad9;
6301341Sstevel
6311341Sstevel mutex_init(&softsp->ps_fail_lock, NULL, MUTEX_DRIVER,
6327656SSherry.Moore@Sun.COM (void *)softsp->ps_fail_c);
6331341Sstevel
6341341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ps_fail_poll_id,
6351341Sstevel NULL, NULL, ps_fail_poll_handler, (caddr_t)softsp) !=
6361341Sstevel DDI_SUCCESS)
6371341Sstevel goto bad10;
6381341Sstevel
6391341Sstevel /*
6401341Sstevel * Now register low-level pps fan fail handler
6411341Sstevel */
6421341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_id,
6431341Sstevel NULL, NULL, pps_fanfail_handler, (caddr_t)softsp) !=
6441341Sstevel DDI_SUCCESS)
6451341Sstevel goto bad11;
6461341Sstevel
6471341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_high_id,
6481341Sstevel NULL, NULL, pps_fanfail_reenable, (caddr_t)softsp) !=
6491341Sstevel DDI_SUCCESS)
6501341Sstevel goto bad12;
6511341Sstevel
6521341Sstevel /*
6531341Sstevel * Based upon a check for a current share backplane, advise
6541341Sstevel * that system does not support hot plug
6551341Sstevel *
6561341Sstevel */
6571341Sstevel if ((*(softsp->pppsr) & SYS_NOT_CURRENT_S) != 0) {
6581341Sstevel cmn_err(CE_NOTE, "Hot Plug not supported in this system");
6591341Sstevel sysctrl_hotplug_disabled = TRUE;
6601341Sstevel }
6611341Sstevel
6621341Sstevel /*
6631341Sstevel * If the trigger circuit is busted or the NOT_BRD_PRES line
6641341Sstevel * is stuck then OBP will publish this property stating that
6651341Sstevel * hot plug is not available. If this happens we will complain
6661341Sstevel * to the console and register a system fault. We will also
6671341Sstevel * not enable the board insert interrupt for this session.
6681341Sstevel */
6691341Sstevel if (ddi_prop_op(DDI_DEV_T_ANY, softsp->dip, PROP_LEN_AND_VAL_ALLOC,
6701341Sstevel DDI_PROP_DONTPASS, HOTPLUG_DISABLED_PROPERTY,
6711341Sstevel (caddr_t)&propval, &proplen) == DDI_PROP_SUCCESS) {
6721341Sstevel cmn_err(CE_WARN, "Hot Plug Unavailable [%s]", propval);
6731341Sstevel reg_fault(0, FT_HOT_PLUG, FT_SYSTEM);
6741341Sstevel sysctrl_hotplug_disabled = TRUE;
6751341Sstevel enable_sys_interrupt &= ~SYS_SBRD_PRES_EN;
6761341Sstevel kmem_free(propval, proplen);
6771341Sstevel }
6781341Sstevel
6791341Sstevel sysc_board_connect_supported_init();
6801341Sstevel
6811341Sstevel fhc_bd_sc_register(sysc_policy_update, softsp);
6821341Sstevel
6831341Sstevel sysc_slot_info(softsp->nslots, &start, &limit, &incr);
6841341Sstevel
6851341Sstevel /* Prime the board list. */
6861341Sstevel fhc_bdlist_prime(start, limit, incr);
6871341Sstevel
6881341Sstevel /*
6891341Sstevel * Set up a board remove timeout call.
6901341Sstevel */
6911341Sstevel (void) fhc_bdlist_lock(-1);
6921341Sstevel
6931341Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG,
6947656SSherry.Moore@Sun.COM ("attach: start bd_remove_poll()..."));
6951341Sstevel
6961341Sstevel bd_remove_poll(softsp);
6971341Sstevel fhc_bdlist_unlock();
6981341Sstevel
6991341Sstevel /*
7001341Sstevel * Now register low-level board insert handler
7011341Sstevel */
7021341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_pres_id,
7031341Sstevel NULL, NULL, bd_insert_handler, (caddr_t)softsp) != DDI_SUCCESS)
7041341Sstevel goto bad13;
7051341Sstevel
7061341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_gone_id,
7071341Sstevel NULL, NULL, bd_insert_normal, (caddr_t)softsp) != DDI_SUCCESS)
7081341Sstevel goto bad14;
7091341Sstevel
7101341Sstevel /*
7111341Sstevel * Now register led blink handler (interrupt level)
7121341Sstevel */
7131341Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->blink_led_id,
7141341Sstevel &softsp->sys_led_c, NULL, blink_led_handler, (caddr_t)softsp) !=
7151341Sstevel DDI_SUCCESS)
7161341Sstevel goto bad15;
7171341Sstevel mutex_init(&softsp->sys_led_lock, NULL, MUTEX_DRIVER,
7187656SSherry.Moore@Sun.COM (void *)softsp->sys_led_c);
7191341Sstevel
7201341Sstevel /* initialize the bit field for all pps fans to assumed good */
7211341Sstevel softsp->pps_fan_saved = softsp->pps_fan_external_state =
7227656SSherry.Moore@Sun.COM SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK;
7231341Sstevel
7241341Sstevel /* prime the power supply state machines */
7251341Sstevel if (enable_sys_interrupt & SYS_PS_FAIL_EN)
7261341Sstevel ddi_trigger_softintr(softsp->ps_fail_poll_id);
7271341Sstevel
7281341Sstevel
7291341Sstevel /* kick off the OS led blinker */
7301341Sstevel softsp->sys_led = FALSE;
7311341Sstevel ddi_trigger_softintr(softsp->blink_led_id);
7321341Sstevel
7331341Sstevel /* Now enable selected interrupt sources */
7341341Sstevel mutex_enter(&softsp->csr_mutex);
7351341Sstevel *(softsp->csr) |= enable_sys_interrupt &
7367656SSherry.Moore@Sun.COM (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
7377656SSherry.Moore@Sun.COM SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
7381341Sstevel tmp_reg = *(softsp->csr);
7391341Sstevel #ifdef lint
7401341Sstevel tmp_reg = tmp_reg;
7411341Sstevel #endif
7421341Sstevel mutex_exit(&softsp->csr_mutex);
7431341Sstevel
7441341Sstevel /* Initialize the temperature */
7451341Sstevel init_temp_arrays(&softsp->tempstat);
7461341Sstevel
7471341Sstevel /*
7481341Sstevel * initialize key switch shadow state
7491341Sstevel */
7501341Sstevel softsp->key_shadow = KEY_BOOT;
7511341Sstevel
7521341Sstevel /*
7531341Sstevel * Now add this soft state structure to the front of the linked list
7541341Sstevel * of soft state structures.
7551341Sstevel */
7561341Sstevel if (sys_list == (struct sysctrl_soft_state *)NULL) {
7571341Sstevel mutex_init(&sslist_mutex, NULL, MUTEX_DEFAULT, NULL);
7581341Sstevel }
7591341Sstevel mutex_enter(&sslist_mutex);
7601341Sstevel softsp->next = sys_list;
7611341Sstevel sys_list = softsp;
7621341Sstevel mutex_exit(&sslist_mutex);
7631341Sstevel
7641341Sstevel /* Setup the kstats for this device */
7651341Sstevel sysctrl_add_kstats(softsp);
7661341Sstevel
7671341Sstevel /* kick off the PPS fan poll routine */
7681341Sstevel pps_fan_poll(softsp);
7691341Sstevel
7701341Sstevel if (sysctrl_overtemp_thread_started == 0) {
7711341Sstevel /*
7721341Sstevel * set up the overtemp condition variable before
7731341Sstevel * starting the thread.
7741341Sstevel */
7751341Sstevel cv_init(&overtemp_cv, NULL, CV_DRIVER, NULL);
7761341Sstevel
7771341Sstevel /*
7781341Sstevel * start up the overtemp polling thread
7791341Sstevel */
7801341Sstevel (void) thread_create(NULL, 0, (void (*)())sysctrl_overtemp_poll,
7811341Sstevel NULL, 0, &p0, TS_RUN, minclsyspri);
7821341Sstevel sysctrl_overtemp_thread_started++;
7831341Sstevel }
7841341Sstevel
7851341Sstevel if (sysctrl_keyswitch_thread_started == 0) {
7861341Sstevel extern void (*abort_seq_handler)();
7871341Sstevel
7881341Sstevel /*
7891341Sstevel * interpose sysctrl's abort sequence handler
7901341Sstevel */
7911341Sstevel abort_seq_handler = sysctrl_abort_seq_handler;
7921341Sstevel
7931341Sstevel /*
7941341Sstevel * set up the key switch condition variable before
7951341Sstevel * starting the thread
7961341Sstevel */
7971341Sstevel cv_init(&keyswitch_cv, NULL, CV_DRIVER, NULL);
7981341Sstevel
7991341Sstevel /*
8001341Sstevel * start up the key switch polling thread
8011341Sstevel */
8021341Sstevel (void) thread_create(NULL, 0,
8031341Sstevel (void (*)())sysctrl_keyswitch_poll, NULL, 0, &p0,
8041341Sstevel TS_RUN, minclsyspri);
8051341Sstevel sysctrl_keyswitch_thread_started++;
8061341Sstevel }
8071341Sstevel
8081341Sstevel /*
8091341Sstevel * perform initialization to allow setting of powerfail-time
8101341Sstevel */
8111341Sstevel if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL)
8121341Sstevel softsp->options_nodeid = (pnode_t)NULL;
8131341Sstevel else
8141341Sstevel softsp->options_nodeid = (pnode_t)ddi_get_nodeid(dip);
8151341Sstevel
8161341Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG,
8177656SSherry.Moore@Sun.COM ("sysctrl: Creating devices start:%d, limit:%d, incr:%d\n",
8187656SSherry.Moore@Sun.COM start, limit, incr));
8191341Sstevel
8201341Sstevel /*
8211341Sstevel * Create minor node for each system attachment points
8221341Sstevel */
8231341Sstevel for (slot_num = start; slot_num < limit; slot_num = slot_num + incr) {
8241341Sstevel char name[30];
8251341Sstevel (void) sprintf(name, "slot%d", slot_num);
8261341Sstevel if (ddi_create_minor_node(devi, name, S_IFCHR,
8271341Sstevel (PUTINSTANCE(instance) | slot_num),
8281341Sstevel DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
8291341Sstevel cmn_err(CE_WARN, "sysctrl%d: \"%s\" "
8307656SSherry.Moore@Sun.COM "ddi_create_minor_node failed",
8317656SSherry.Moore@Sun.COM instance, name);
8321341Sstevel goto bad16;
8331341Sstevel }
8341341Sstevel }
8351341Sstevel
8361341Sstevel ddi_report_dev(devi);
8371341Sstevel
8381341Sstevel /*
8391341Sstevel * Remote console is inherited from POST
8401341Sstevel */
8411341Sstevel if ((*(softsp->clk_freq2) & RCONS_UART_EN) == 0) {
8421341Sstevel softsp->enable_rcons_atboot = FALSE;
8431341Sstevel cmn_err(CE_WARN, "Remote console not active");
8441341Sstevel } else
8451341Sstevel softsp->enable_rcons_atboot = TRUE;
8461341Sstevel
8471341Sstevel return (DDI_SUCCESS);
8481341Sstevel
8491341Sstevel bad16:
8501341Sstevel cv_destroy(&keyswitch_cv);
8511341Sstevel cv_destroy(&overtemp_cv);
8521341Sstevel mutex_destroy(&sslist_mutex);
8531341Sstevel mutex_destroy(&softsp->sys_led_lock);
8541341Sstevel ddi_remove_softintr(softsp->blink_led_id);
8551341Sstevel bad15:
8561341Sstevel ddi_remove_softintr(softsp->sbrd_gone_id);
8571341Sstevel bad14:
8581341Sstevel ddi_remove_softintr(softsp->sbrd_pres_id);
8591341Sstevel bad13:
8601341Sstevel ddi_remove_softintr(softsp->pps_fan_high_id);
8611341Sstevel bad12:
8621341Sstevel ddi_remove_softintr(softsp->pps_fan_id);
8631341Sstevel bad11:
8641341Sstevel ddi_remove_softintr(softsp->ps_fail_poll_id);
8651341Sstevel bad10:
8661341Sstevel mutex_destroy(&softsp->ps_fail_lock);
8671341Sstevel ddi_remove_softintr(softsp->ps_fail_int_id);
8681341Sstevel bad9:
8691341Sstevel ddi_remove_softintr(softsp->ac_fail_high_id);
8701341Sstevel bad8:
8711341Sstevel ddi_remove_softintr(softsp->ac_fail_id);
8721341Sstevel bad7:
8731341Sstevel ddi_remove_softintr(softsp->spur_long_to_id);
8741341Sstevel bad6:
8751341Sstevel ddi_remove_softintr(softsp->spur_high_id);
8761341Sstevel bad5:
8771341Sstevel mutex_destroy(&softsp->spur_int_lock);
8781341Sstevel ddi_remove_softintr(softsp->spur_id);
8791341Sstevel bad4:
8801341Sstevel ddi_remove_intr(devi, 0, softsp->iblock);
8811341Sstevel bad3:
8821341Sstevel mutex_destroy(&softsp->csr_mutex);
8831341Sstevel bad2:
8841341Sstevel ddi_unmap_regs(softsp->dip, 1, (caddr_t *)&softsp->csr, 0, 0);
8851341Sstevel if (softsp->clk_ver != NULL)
8861341Sstevel ddi_unmap_regs(softsp->dip, 2, (caddr_t *)&softsp->clk_ver,
8871341Sstevel 0, 0);
8881341Sstevel bad1:
8891341Sstevel ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->clk_freq1, 0, 0);
8901341Sstevel
8911341Sstevel bad0:
8921341Sstevel ddi_soft_state_free(sysctrlp, instance);
8931341Sstevel ddi_remove_minor_node(dip, NULL);
8941341Sstevel cmn_err(CE_WARN,
8951341Sstevel "sysctrl%d: Initialization failure. Some system level events,"
8961341Sstevel " {AC Fail, Fan Failure, PS Failure} not detected", instance);
8971341Sstevel return (DDI_FAILURE);
8981341Sstevel }
8991341Sstevel
9001341Sstevel struct sysc_hold {
9011341Sstevel int start;
9021341Sstevel int limit;
9031341Sstevel int incr;
9041341Sstevel int hold;
9051341Sstevel };
9061341Sstevel
9071341Sstevel static int
sysctrl_hold_rele_branches(dev_info_t * dip,void * arg)9081341Sstevel sysctrl_hold_rele_branches(dev_info_t *dip, void *arg)
9091341Sstevel {
9101341Sstevel int *rp, len, slot, i;
9111341Sstevel struct sysc_hold *ap = (struct sysc_hold *)arg;
9121341Sstevel
9131341Sstevel /*
9141341Sstevel * For Sunfire, top nodes on board are always children of root dip
9151341Sstevel */
9161341Sstevel ASSERT(ddi_get_parent(dip) == ddi_root_node());
9171341Sstevel
9181341Sstevel /*
9191341Sstevel * Skip non-PROM and "central" nodes
9201341Sstevel */
9211341Sstevel if (!ndi_dev_is_prom_node(dip) ||
9221341Sstevel strcmp(ddi_node_name(dip), "central") == 0)
9231341Sstevel return (DDI_WALK_PRUNECHILD);
9241341Sstevel
9251341Sstevel /*
9261341Sstevel * Extract board # from reg property.
9271341Sstevel */
9281341Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
9291341Sstevel DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", (caddr_t)&rp, &len)
9301341Sstevel != DDI_SUCCESS) {
9311341Sstevel DPRINTF(SYSC_DEBUG, ("devinfo node %s(%p) has no reg"
9321341Sstevel " property\n", ddi_node_name(dip), (void *)dip));
9331341Sstevel return (DDI_WALK_PRUNECHILD);
9341341Sstevel }
9351341Sstevel
9361341Sstevel slot = (*rp - 0x1c0) >> 2;
9371341Sstevel kmem_free(rp, len);
9381341Sstevel
9391341Sstevel ASSERT(ap->start >= 0 && ap->start < ap->limit);
9401341Sstevel
9411341Sstevel for (i = ap->start; i < ap->limit; i = i + ap->incr) {
9421341Sstevel if (i == slot)
9431341Sstevel break;
9441341Sstevel }
9451341Sstevel
9461341Sstevel if (i >= ap->limit) {
9471341Sstevel DPRINTF(SYSC_DEBUG, ("sysctrl_hold_rele: Invalid board # (%d)"
9481341Sstevel " for node %s(%p)\n", slot, ddi_node_name(dip),
9491341Sstevel (void *)dip));
9501341Sstevel return (DDI_WALK_PRUNECHILD);
9511341Sstevel }
9521341Sstevel
9531341Sstevel if (ap->hold) {
9541341Sstevel ASSERT(!e_ddi_branch_held(dip));
9551341Sstevel e_ddi_branch_hold(dip);
9561341Sstevel } else {
9571341Sstevel ASSERT(e_ddi_branch_held(dip));
9581341Sstevel e_ddi_branch_rele(dip);
9591341Sstevel }
9601341Sstevel
9611341Sstevel return (DDI_WALK_PRUNECHILD);
9621341Sstevel }
9631341Sstevel
9641341Sstevel /* ARGSUSED */
9651341Sstevel static int
sysctrl_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)9661341Sstevel sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
9671341Sstevel {
9681341Sstevel #ifdef SYSCTRL_SUPPORTS_DETACH
9691341Sstevel dev_info_t *rdip;
9701341Sstevel struct sysc_hold arg = {0};
9711341Sstevel struct sysctrl_soft_state *softsp;
9721341Sstevel #endif /* SYSCTRL_SUPPORTS_DETACH */
9731341Sstevel
9741341Sstevel if (sysctrl_enable_detach_suspend == FALSE)
9751341Sstevel return (DDI_FAILURE);
9761341Sstevel
9771341Sstevel switch (cmd) {
9781341Sstevel case DDI_SUSPEND:
9791341Sstevel /*
9801341Sstevel * XXX we don't presently save the state of the remote
9811341Sstevel * console because it is a constant function of POST.
9821341Sstevel * XXX we don't deal with the hardware watchdog here
9831341Sstevel * either. It should be handled in hardclk.
9841341Sstevel */
9851341Sstevel return (DDI_SUCCESS);
9861341Sstevel
9871341Sstevel case DDI_DETACH:
9881341Sstevel break;
9891341Sstevel default:
9901341Sstevel return (DDI_FAILURE);
9911341Sstevel }
9921341Sstevel
9931341Sstevel #ifdef SYSCTRL_SUPPORTS_DETACH
9941341Sstevel
9951341Sstevel /*
9961341Sstevel * XXX If sysctrl ever supports detach, this code should be enabled
9971341Sstevel * This is only the portion of the detach code dealing with
9981341Sstevel * the DDI branch routines. Other parts of detach will need
9991341Sstevel * to be added.
10001341Sstevel */
10011341Sstevel
10021341Sstevel /*
10031341Sstevel * Walk immediate children of root devinfo node, releasing holds
10041341Sstevel * on branches acquired in first sysctrl_open().
10051341Sstevel */
10061341Sstevel
10071341Sstevel instance = ddi_get_instance(dip);
10081341Sstevel softsp = GETSOFTC(instance);
10091341Sstevel
10101341Sstevel if (softsp == NULL) {
10111341Sstevel cmn_err(CE_WARN, "sysctrl%d device not attached", instance);
10121341Sstevel return (DDI_FAILURE);
10131341Sstevel }
10141341Sstevel
10151341Sstevel sysc_slot_info(softsp->nslots, &arg.start, &arg.limit, &arg.incr);
10161341Sstevel
10171341Sstevel arg.hold = 0;
10181341Sstevel
10191341Sstevel rdip = ddi_root_node();
10201341Sstevel
10211341Sstevel ndi_devi_enter(rdip, &circ);
10221341Sstevel ddi_walk_devs(ddi_get_child(rdip), sysctrl_hold_rele_branches, &arg);
10231341Sstevel ndi_devi_exit(rdip, circ);
10241341Sstevel
10251341Sstevel sysctrl_ddi_branch_init = 0;
10261341Sstevel
10271341Sstevel return (DDI_SUCCESS);
10281341Sstevel #endif /* SYSCTRL_SUPPORTS_DETACH */
10291341Sstevel
10301341Sstevel return (DDI_FAILURE);
10311341Sstevel }
10321341Sstevel
10331341Sstevel /* ARGSUSED */
10341341Sstevel static int
sysctrl_open(dev_t * devp,int flag,int otyp,cred_t * credp)10351341Sstevel sysctrl_open(dev_t *devp, int flag, int otyp, cred_t *credp)
10361341Sstevel {
10371341Sstevel int instance;
10381341Sstevel int slot;
10391341Sstevel dev_t dev;
10401341Sstevel int circ;
10411341Sstevel dev_info_t *rdip;
10421341Sstevel struct sysc_hold arg = {0};
10431341Sstevel struct sysctrl_soft_state *softsp;
10441341Sstevel
10451341Sstevel dev = *devp;
10461341Sstevel
10471341Sstevel /*
10481341Sstevel * We checked against the instance softstate structure since there
10491341Sstevel * will only be one instance of sysctrl (clock board) in UEXX00
10501341Sstevel *
10511341Sstevel * Since we only create minor devices for existing slots on a
10521341Sstevel * particular system, we don't need to worry about non-exist slot.
10531341Sstevel */
10541341Sstevel
10551341Sstevel instance = GETINSTANCE(dev);
10561341Sstevel slot = GETSLOT(dev);
10571341Sstevel
10581341Sstevel /* Is the instance attached? */
10591341Sstevel if ((softsp = GETSOFTC(instance)) == NULL) {
10601341Sstevel cmn_err(CE_WARN, "sysctrl%d device not attached", instance);
10611341Sstevel return (ENXIO);
10621341Sstevel }
10631341Sstevel
10641341Sstevel /* verify that otyp is appropriate */
10651341Sstevel if (otyp != OTYP_CHR) {
10661341Sstevel return (EINVAL);
10671341Sstevel }
10681341Sstevel
10691341Sstevel if (!fhc_bd_valid(slot))
10701341Sstevel return (ENXIO);
10711341Sstevel
10721341Sstevel /*
10731341Sstevel * On first open of a sysctrl minor walk immediate children of the
10741341Sstevel * devinfo root node and hold all branches of interest.
10751341Sstevel */
10761341Sstevel mutex_enter(&sysctrl_branch_mutex);
10771341Sstevel if (!sysctrl_ddi_branch_init) {
10781341Sstevel
10791341Sstevel sysctrl_ddi_branch_init = 1;
10801341Sstevel
10811341Sstevel sysc_slot_info(softsp->nslots, &arg.start, &arg.limit,
10821341Sstevel &arg.incr);
10831341Sstevel arg.hold = 1;
10841341Sstevel
10851341Sstevel rdip = ddi_root_node();
10861341Sstevel
10871341Sstevel ndi_devi_enter(rdip, &circ);
10881341Sstevel ddi_walk_devs(ddi_get_child(rdip), sysctrl_hold_rele_branches,
10891341Sstevel &arg);
10901341Sstevel ndi_devi_exit(rdip, circ);
10911341Sstevel }
10921341Sstevel mutex_exit(&sysctrl_branch_mutex);
10931341Sstevel
10941341Sstevel return (DDI_SUCCESS);
10951341Sstevel }
10961341Sstevel
10971341Sstevel /* ARGSUSED */
10981341Sstevel static int
sysctrl_close(dev_t devp,int flag,int otyp,cred_t * credp)10991341Sstevel sysctrl_close(dev_t devp, int flag, int otyp, cred_t *credp)
11001341Sstevel {
11011341Sstevel return (DDI_SUCCESS);
11021341Sstevel }
11031341Sstevel
11041341Sstevel /*
11051341Sstevel * This function will acquire the lock and set the in_transition
11061341Sstevel * bit for the specified slot. If the slot is being used,
11071341Sstevel * we return FALSE; else set in_transition and return TRUE.
11081341Sstevel */
11091341Sstevel static int
sysc_enter_transition(int slot)11101341Sstevel sysc_enter_transition(int slot)
11111341Sstevel {
11121341Sstevel fhc_bd_t *list;
11131341Sstevel sysc_cfga_stat_t *sysc_stat_lk;
11141341Sstevel fhc_bd_t *glist;
11151341Sstevel sysc_cfga_stat_t *sysc_stat_gk;
11161341Sstevel
11171341Sstevel /* mutex lock the structure */
11181341Sstevel list = fhc_bdlist_lock(slot);
11191341Sstevel if ((slot != -1) && (list == NULL)) {
11201341Sstevel fhc_bdlist_unlock();
11211341Sstevel return (FALSE);
11221341Sstevel }
11231341Sstevel
11241341Sstevel glist = fhc_bd_clock();
11251341Sstevel if (slot == -1)
11261341Sstevel list = glist;
11271341Sstevel
11281341Sstevel /* change the in_transition bit */
11291341Sstevel sysc_stat_lk = &list->sc;
11301341Sstevel sysc_stat_gk = &glist->sc;
11311341Sstevel if ((sysc_stat_lk->in_transition == TRUE) ||
11321341Sstevel (sysc_stat_gk->in_transition == TRUE)) {
11331341Sstevel fhc_bdlist_unlock();
11341341Sstevel return (FALSE);
11351341Sstevel } else {
11361341Sstevel sysc_stat_lk->in_transition = TRUE;
11371341Sstevel return (TRUE);
11381341Sstevel }
11391341Sstevel }
11401341Sstevel
11411341Sstevel /*
11421341Sstevel * This function will release the lock and clear the in_transition
11431341Sstevel * bit for the specified slot.
11441341Sstevel */
11451341Sstevel static void
sysc_exit_transition(int slot)11461341Sstevel sysc_exit_transition(int slot)
11471341Sstevel {
11481341Sstevel fhc_bd_t *list;
11491341Sstevel sysc_cfga_stat_t *sysc_stat_lk;
11501341Sstevel
11511341Sstevel ASSERT(fhc_bdlist_locked());
11521341Sstevel
11531341Sstevel if (slot == -1)
11541341Sstevel list = fhc_bd_clock();
11551341Sstevel else
11561341Sstevel list = fhc_bd(slot);
11571341Sstevel sysc_stat_lk = &list->sc;
11581341Sstevel ASSERT(sysc_stat_lk->in_transition == TRUE);
11591341Sstevel sysc_stat_lk->in_transition = FALSE;
11601341Sstevel fhc_bdlist_unlock();
11611341Sstevel }
11621341Sstevel
11631341Sstevel static int
sysc_pkt_init(sysc_cfga_pkt_t * pkt,intptr_t arg,int flag)11641341Sstevel sysc_pkt_init(sysc_cfga_pkt_t *pkt, intptr_t arg, int flag)
11651341Sstevel {
11661341Sstevel #ifdef _MULTI_DATAMODEL
11671341Sstevel if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
11681341Sstevel sysc_cfga_cmd32_t sysc_cmd32;
11691341Sstevel
11701341Sstevel if (ddi_copyin((void *)arg, &sysc_cmd32,
11717656SSherry.Moore@Sun.COM sizeof (sysc_cfga_cmd32_t), flag) != 0) {
11721341Sstevel return (EFAULT);
11731341Sstevel }
11741341Sstevel pkt->cmd_cfga.force = sysc_cmd32.force;
11751341Sstevel pkt->cmd_cfga.test = sysc_cmd32.test;
11761341Sstevel pkt->cmd_cfga.arg = sysc_cmd32.arg;
11771341Sstevel pkt->cmd_cfga.errtype = sysc_cmd32.errtype;
11781341Sstevel pkt->cmd_cfga.outputstr =
11797656SSherry.Moore@Sun.COM (char *)(uintptr_t)sysc_cmd32.outputstr;
11801341Sstevel } else
11811341Sstevel #endif /* _MULTI_DATAMODEL */
11821341Sstevel if (ddi_copyin((void *)arg, &(pkt->cmd_cfga),
11837656SSherry.Moore@Sun.COM sizeof (sysc_cfga_cmd_t), flag) != 0) {
11841341Sstevel return (EFAULT);
11851341Sstevel }
11861341Sstevel pkt->errbuf = kmem_zalloc(SYSC_OUTPUT_LEN, KM_SLEEP);
11871341Sstevel return (0);
11881341Sstevel }
11891341Sstevel
11901341Sstevel static int
sysc_pkt_fini(sysc_cfga_pkt_t * pkt,intptr_t arg,int flag)11911341Sstevel sysc_pkt_fini(sysc_cfga_pkt_t *pkt, intptr_t arg, int flag)
11921341Sstevel {
11931341Sstevel int ret = TRUE;
11941341Sstevel
11951341Sstevel #ifdef _MULTI_DATAMODEL
11961341Sstevel if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
11971341Sstevel
11981341Sstevel if (ddi_copyout(&(pkt->cmd_cfga.errtype),
11997656SSherry.Moore@Sun.COM (void *)&(((sysc_cfga_cmd32_t *)arg)->errtype),
12007656SSherry.Moore@Sun.COM sizeof (sysc_err_t), flag) != 0) {
12011341Sstevel ret = FALSE;
12021341Sstevel }
12031341Sstevel } else
12041341Sstevel #endif
12051341Sstevel if (ddi_copyout(&(pkt->cmd_cfga.errtype),
12067656SSherry.Moore@Sun.COM (void *)&(((sysc_cfga_cmd_t *)arg)->errtype),
12077656SSherry.Moore@Sun.COM sizeof (sysc_err_t), flag) != 0) {
12081341Sstevel ret = FALSE;
12091341Sstevel }
12101341Sstevel
12111341Sstevel if ((ret != FALSE) && ((pkt->cmd_cfga.outputstr != NULL) &&
12127656SSherry.Moore@Sun.COM (ddi_copyout(pkt->errbuf, pkt->cmd_cfga.outputstr,
12137656SSherry.Moore@Sun.COM SYSC_OUTPUT_LEN, flag) != 0))) {
12141341Sstevel ret = FALSE;
12151341Sstevel }
12161341Sstevel
12171341Sstevel kmem_free(pkt->errbuf, SYSC_OUTPUT_LEN);
12181341Sstevel return (ret);
12191341Sstevel }
12201341Sstevel
12211341Sstevel /* ARGSUSED */
12221341Sstevel static int
sysctrl_ioctl(dev_t devt,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rval_p)12231341Sstevel sysctrl_ioctl(dev_t devt, int cmd, intptr_t arg, int flag, cred_t *cred_p,
12241341Sstevel int *rval_p)
12251341Sstevel {
12261341Sstevel struct sysctrl_soft_state *softsp;
12271341Sstevel sysc_cfga_pkt_t sysc_pkt;
12281341Sstevel fhc_bd_t *fhc_list = NULL;
12291341Sstevel sysc_cfga_stat_t *sc_list = NULL;
12301341Sstevel fhc_bd_t *bdp;
12311341Sstevel sysc_cfga_stat_t *sc = NULL;
12321341Sstevel int instance;
12331341Sstevel int slot;
12341341Sstevel int retval = 0;
12351341Sstevel int i;
12361341Sstevel
12371341Sstevel instance = GETINSTANCE(devt);
12381341Sstevel softsp = GETSOFTC(instance);
12391341Sstevel if (softsp == NULL) {
12401341Sstevel cmn_err(CE_CONT,
12417656SSherry.Moore@Sun.COM "sysctrl_ioctl(%d): NULL softstate ptr!\n",
12427656SSherry.Moore@Sun.COM (int)GETSLOT(devt));
12431341Sstevel return (ENXIO);
12441341Sstevel }
12451341Sstevel
12461341Sstevel slot = GETSLOT(devt);
12471341Sstevel
12481341Sstevel /*
12491341Sstevel * First switch is to do correct locking and do ddi_copyin()
12501341Sstevel */
12511341Sstevel switch (cmd) {
12521341Sstevel case SYSC_CFGA_CMD_GETSTATUS:
12531341Sstevel /* mutex lock the whole list */
12541341Sstevel if (sysc_enter_transition(-1) != TRUE) {
12551341Sstevel retval = EBUSY;
12561341Sstevel goto cleanup_exit;
12571341Sstevel }
12581341Sstevel
12591341Sstevel /* allocate the memory before acquiring mutex */
12601341Sstevel fhc_list = kmem_zalloc(sizeof (fhc_bd_t) * fhc_max_boards(),
12611341Sstevel KM_SLEEP);
12621341Sstevel
12631341Sstevel sc_list = kmem_zalloc(sizeof (sysc_cfga_stat_t) *
12641341Sstevel fhc_max_boards(), KM_SLEEP);
12651341Sstevel
12661341Sstevel break;
12671341Sstevel
12681341Sstevel case SYSC_CFGA_CMD_EJECT:
12691341Sstevel case SYSC_CFGA_CMD_INSERT:
12701341Sstevel retval = ENOTSUP;
12711341Sstevel goto cleanup_exit;
12721341Sstevel
12731341Sstevel case SYSC_CFGA_CMD_CONNECT:
12741341Sstevel case SYSC_CFGA_CMD_DISCONNECT:
12751341Sstevel case SYSC_CFGA_CMD_UNCONFIGURE:
12761341Sstevel case SYSC_CFGA_CMD_CONFIGURE:
12771341Sstevel case SYSC_CFGA_CMD_TEST:
12781341Sstevel case SYSC_CFGA_CMD_TEST_SET_COND:
12791341Sstevel case SYSC_CFGA_CMD_QUIESCE_TEST:
12801341Sstevel
12811341Sstevel /* ioctls allowed if caller has write permission */
12821341Sstevel if (!(flag & FWRITE)) {
12831341Sstevel retval = EPERM;
12841341Sstevel goto cleanup_exit;
12851341Sstevel }
12861341Sstevel
12871341Sstevel retval = sysc_pkt_init(&sysc_pkt, arg, flag);
12881341Sstevel if (retval != 0)
12891341Sstevel goto cleanup_exit;
12901341Sstevel
12911341Sstevel /* grasp lock and set in_transition bit */
12921341Sstevel if (sysc_enter_transition(cmd == SYSC_CFGA_CMD_QUIESCE_TEST
12937656SSherry.Moore@Sun.COM ? -1 : slot) != TRUE) {
12941341Sstevel retval = EBUSY;
12951341Sstevel SYSC_ERR_SET(&sysc_pkt, SYSC_ERR_INTRANS);
12961341Sstevel goto cleanup_copyout;
12971341Sstevel }
12981341Sstevel
12991341Sstevel /* get the status structure for the slot */
13001341Sstevel bdp = fhc_bd(slot);
13011341Sstevel sc = &bdp->sc;
13021341Sstevel break;
13031341Sstevel
13041341Sstevel /* POSIX definition: return ENOTTY if unsupported command */
13051341Sstevel default:
13061341Sstevel retval = ENOTTY;
13071341Sstevel goto cleanup_exit;
13081341Sstevel }
13091341Sstevel
13101341Sstevel /*
13111341Sstevel * Second switch is to call the underlayer workhorse.
13121341Sstevel */
13131341Sstevel switch (cmd) {
13141341Sstevel case SYSC_CFGA_CMD_GETSTATUS:
13151341Sstevel for (i = 0; i < fhc_max_boards(); i++) {
13161341Sstevel if (fhc_bd_valid(i)) {
13171341Sstevel bdp = fhc_bd(i);
13181341Sstevel if (fhc_bd_is_jtag_master(i))
13191341Sstevel bdp->sc.no_detach = 1;
13201341Sstevel else
13211341Sstevel bdp->sc.no_detach = 0;
13221341Sstevel bcopy((caddr_t)&bdp->sc,
13237656SSherry.Moore@Sun.COM &sc_list[i], sizeof (sysc_cfga_stat_t));
13241341Sstevel } else {
13251341Sstevel sc_list[i].board = -1;
13261341Sstevel sc_list[i].rstate = SYSC_CFGA_RSTATE_EMPTY;
13271341Sstevel }
13281341Sstevel }
13291341Sstevel
13301341Sstevel sysc_exit_transition(-1);
13311341Sstevel
13321341Sstevel break;
13331341Sstevel
13341341Sstevel case SYSC_CFGA_CMD_EJECT:
13351341Sstevel case SYSC_CFGA_CMD_INSERT:
13361341Sstevel retval = ENOTSUP;
13371341Sstevel goto cleanup_exit;
13381341Sstevel
13391341Sstevel case SYSC_CFGA_CMD_CONNECT:
13401341Sstevel retval = sysc_policy_connect(softsp, &sysc_pkt, sc);
13411341Sstevel sysc_exit_transition(slot);
13421341Sstevel break;
13431341Sstevel
13441341Sstevel case SYSC_CFGA_CMD_DISCONNECT:
13451341Sstevel retval = sysc_policy_disconnect(softsp, &sysc_pkt, sc);
13461341Sstevel sysc_exit_transition(slot);
13471341Sstevel break;
13481341Sstevel
13491341Sstevel case SYSC_CFGA_CMD_UNCONFIGURE:
13501341Sstevel retval = sysc_policy_unconfigure(softsp, &sysc_pkt, sc);
13511341Sstevel sysc_exit_transition(slot);
13521341Sstevel break;
13531341Sstevel
13541341Sstevel case SYSC_CFGA_CMD_CONFIGURE:
13551341Sstevel retval = sysc_policy_configure(softsp, &sysc_pkt, sc);
13561341Sstevel sysc_exit_transition(slot);
13571341Sstevel break;
13581341Sstevel
13591341Sstevel case SYSC_CFGA_CMD_TEST:
13601341Sstevel retval = fhc_bd_test(slot, &sysc_pkt);
13611341Sstevel sysc_exit_transition(slot);
13621341Sstevel break;
13631341Sstevel
13641341Sstevel case SYSC_CFGA_CMD_TEST_SET_COND:
13651341Sstevel retval = fhc_bd_test_set_cond(slot, &sysc_pkt);
13661341Sstevel sysc_exit_transition(slot);
13671341Sstevel break;
13681341Sstevel
13691341Sstevel case SYSC_CFGA_CMD_QUIESCE_TEST:
13701341Sstevel sysctrl_suspend_prepare();
13711341Sstevel fhc_bdlist_unlock();
13721341Sstevel
13731341Sstevel if (sysctrl_suspend(&sysc_pkt) == DDI_SUCCESS) {
13741341Sstevel sysctrl_resume(&sysc_pkt);
13751341Sstevel } else {
13761341Sstevel retval = EBUSY;
13771341Sstevel }
13781341Sstevel
13791341Sstevel (void) fhc_bdlist_lock(-1);
13801341Sstevel sysc_exit_transition(-1);
13811341Sstevel break;
13821341Sstevel
13831341Sstevel default:
13841341Sstevel retval = ENOTTY;
13851341Sstevel goto cleanup_exit;
13861341Sstevel }
13871341Sstevel
13881341Sstevel cleanup_copyout:
13891341Sstevel /*
13901341Sstevel * 3rd switch is to do appropriate copyout and reset locks
13911341Sstevel */
13921341Sstevel switch (cmd) {
13931341Sstevel case SYSC_CFGA_CMD_GETSTATUS:
13941341Sstevel if (ddi_copyout(sc_list, (void *)arg,
13957656SSherry.Moore@Sun.COM sizeof (sysc_cfga_stat_t) * fhc_max_boards(),
13967656SSherry.Moore@Sun.COM flag) != 0) {
13971341Sstevel retval = EFAULT;
13981341Sstevel }
13991341Sstevel
14001341Sstevel /* cleanup memory */
14011341Sstevel kmem_free(fhc_list, sizeof (fhc_bd_t) * fhc_max_boards());
14021341Sstevel kmem_free(sc_list, sizeof (sysc_cfga_stat_t) *
14031341Sstevel fhc_max_boards());
14041341Sstevel break;
14051341Sstevel
14061341Sstevel case SYSC_CFGA_CMD_EJECT:
14071341Sstevel case SYSC_CFGA_CMD_INSERT:
14081341Sstevel retval = ENOTSUP;
14091341Sstevel break;
14101341Sstevel
14111341Sstevel case SYSC_CFGA_CMD_CONNECT:
14121341Sstevel case SYSC_CFGA_CMD_DISCONNECT:
14131341Sstevel case SYSC_CFGA_CMD_UNCONFIGURE:
14141341Sstevel case SYSC_CFGA_CMD_CONFIGURE:
14151341Sstevel case SYSC_CFGA_CMD_TEST:
14161341Sstevel case SYSC_CFGA_CMD_TEST_SET_COND:
14171341Sstevel case SYSC_CFGA_CMD_QUIESCE_TEST:
14181341Sstevel if (sysc_pkt_fini(&sysc_pkt, arg, flag) != TRUE)
14191341Sstevel return (EFAULT);
14201341Sstevel break;
14211341Sstevel
14221341Sstevel default:
14231341Sstevel retval = ENOTTY;
14241341Sstevel break;
14251341Sstevel }
14261341Sstevel
14271341Sstevel cleanup_exit:
14281341Sstevel return (retval);
14291341Sstevel }
14301341Sstevel
14311341Sstevel /*
14321341Sstevel * system_high_handler()
14331341Sstevel * This routine handles system interrupts.
14341341Sstevel *
14351341Sstevel * This routine goes through all the interrupt sources and masks
14361341Sstevel * off the enable bit if interrupting. Because of the special
14371341Sstevel * nature of the pps fan source bits, we also cache the state
14381341Sstevel * of the fan bits for that special case.
14391341Sstevel *
14401341Sstevel * The rest of the work is done in the low level handlers
14411341Sstevel */
14421341Sstevel static uint_t
system_high_handler(caddr_t arg)14431341Sstevel system_high_handler(caddr_t arg)
14441341Sstevel {
14451341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
14461341Sstevel uchar_t csr;
14471341Sstevel uchar_t status2;
14481341Sstevel uchar_t tmp_reg;
14491341Sstevel int serviced = 0;
14501341Sstevel
14511341Sstevel ASSERT(softsp);
14521341Sstevel
14531341Sstevel mutex_enter(&softsp->csr_mutex);
14541341Sstevel
14551341Sstevel /* read in the hardware registers */
14561341Sstevel csr = *(softsp->csr);
14571341Sstevel status2 = *(softsp->status2);
14581341Sstevel
14591341Sstevel if (csr & SYS_AC_PWR_FAIL_EN) {
14601341Sstevel if (status2 & SYS_AC_FAIL) {
14611341Sstevel
14621341Sstevel /* save the powerfail state in nvram */
14631341Sstevel nvram_update_powerfail(softsp);
14641341Sstevel
14651341Sstevel /* disable this interrupt source */
14661341Sstevel csr &= ~SYS_AC_PWR_FAIL_EN;
14671341Sstevel
14681341Sstevel ddi_trigger_softintr(softsp->ac_fail_id);
14691341Sstevel serviced++;
14701341Sstevel }
14711341Sstevel }
14721341Sstevel
14731341Sstevel if (csr & SYS_PS_FAIL_EN) {
14741341Sstevel if ((*(softsp->ps_stat) != 0xff) ||
14751341Sstevel ((~status2) & (SYS_PPS0_OK | SYS_CLK_33_OK |
14767656SSherry.Moore@Sun.COM SYS_CLK_50_OK)) ||
14771341Sstevel (~(*(softsp->pppsr)) & SYS_PPPSR_BITS)) {
14781341Sstevel
14791341Sstevel /* disable this interrupt source */
14801341Sstevel csr &= ~SYS_PS_FAIL_EN;
14811341Sstevel
14821341Sstevel ddi_trigger_softintr(softsp->ps_fail_int_id);
14831341Sstevel serviced++;
14841341Sstevel }
14851341Sstevel }
14861341Sstevel
14871341Sstevel if (csr & SYS_PPS_FAN_FAIL_EN) {
14881341Sstevel if (status2 & SYS_RACK_FANFAIL ||
14891341Sstevel !(status2 & SYS_AC_FAN_OK) ||
14901341Sstevel !(status2 & SYS_KEYSW_FAN_OK)) {
14911341Sstevel
14921341Sstevel /*
14931341Sstevel * we must cache the fan status because it goes
14941341Sstevel * away when we disable interrupts !?!?!
14951341Sstevel */
14961341Sstevel softsp->pps_fan_saved = status2;
14971341Sstevel
14981341Sstevel /* disable this interrupt source */
14991341Sstevel csr &= ~SYS_PPS_FAN_FAIL_EN;
15001341Sstevel
15011341Sstevel ddi_trigger_softintr(softsp->pps_fan_id);
15021341Sstevel serviced++;
15031341Sstevel }
15041341Sstevel }
15051341Sstevel
15061341Sstevel if (csr & SYS_SBRD_PRES_EN) {
15071341Sstevel if (!(*(softsp->status1) & SYS_NOT_BRD_PRES)) {
15081341Sstevel
15091341Sstevel /* disable this interrupt source */
15101341Sstevel csr &= ~SYS_SBRD_PRES_EN;
15111341Sstevel
15121341Sstevel ddi_trigger_softintr(softsp->sbrd_pres_id);
15131341Sstevel serviced++;
15141341Sstevel }
15151341Sstevel }
15161341Sstevel
15171341Sstevel if (!serviced) {
15181341Sstevel
15191341Sstevel /*
15201341Sstevel * if we get here than it is likely that contact bounce
15211341Sstevel * is messing with us. so, we need to shut this interrupt
15221341Sstevel * up for a while to let the contacts settle down.
15231341Sstevel * Then we will re-enable the interrupts that are enabled
15241341Sstevel * right now. The trick is to disable the appropriate
15251341Sstevel * interrupts and then to re-enable them correctly, even
15261341Sstevel * though intervening handlers might have been working.
15271341Sstevel */
15281341Sstevel
15291341Sstevel /* remember all interrupts that could have caused it */
15301341Sstevel softsp->saved_en_state |= csr &
15311341Sstevel (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
15321341Sstevel SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
15331341Sstevel
15341341Sstevel /* and then turn them off */
15351341Sstevel csr &= ~(SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
15367656SSherry.Moore@Sun.COM SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
15371341Sstevel
15381341Sstevel /* and then bump the counter */
15391341Sstevel softsp->spur_count++;
15401341Sstevel
15411341Sstevel /* and kick off the timeout */
15421341Sstevel ddi_trigger_softintr(softsp->spur_id);
15431341Sstevel }
15441341Sstevel
15451341Sstevel /* update the real csr */
15461341Sstevel *(softsp->csr) = csr;
15471341Sstevel tmp_reg = *(softsp->csr);
15481341Sstevel #ifdef lint
15491341Sstevel tmp_reg = tmp_reg;
15501341Sstevel #endif
15511341Sstevel mutex_exit(&softsp->csr_mutex);
15521341Sstevel
15531341Sstevel return (DDI_INTR_CLAIMED);
15541341Sstevel }
15551341Sstevel
15561341Sstevel /*
15571341Sstevel * we've detected a spurious interrupt.
15581341Sstevel * determine if we should log a message and if we need another timeout
15591341Sstevel */
15601341Sstevel static uint_t
spur_delay(caddr_t arg)15611341Sstevel spur_delay(caddr_t arg)
15621341Sstevel {
15631341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
15641341Sstevel
15651341Sstevel ASSERT(softsp);
15661341Sstevel
15671341Sstevel /* do we need to complain? */
15681341Sstevel mutex_enter(&softsp->csr_mutex);
15691341Sstevel
15701341Sstevel /* NOTE: this is == because we want one message per long timeout */
15711341Sstevel if (softsp->spur_count == MAX_SPUR_COUNT) {
15721341Sstevel char buf[128];
15731341Sstevel
15741341Sstevel /* print out the candidates known at this time */
15751341Sstevel /* XXX not perfect because of re-entrant nature but close */
15761341Sstevel buf[0] = '\0';
15771341Sstevel if (softsp->saved_en_state & SYS_AC_PWR_FAIL_EN)
15781341Sstevel (void) strcat(buf, "AC FAIL");
15791341Sstevel if (softsp->saved_en_state & SYS_PPS_FAN_FAIL_EN)
15801341Sstevel (void) strcat(buf, buf[0] ? "|PPS FANS" : "PPS FANS");
15811341Sstevel if (softsp->saved_en_state & SYS_PS_FAIL_EN)
15821341Sstevel (void) strcat(buf, buf[0] ? "|PS FAIL" : "PS FAIL");
15831341Sstevel if (softsp->saved_en_state & SYS_SBRD_PRES_EN)
15841341Sstevel (void) strcat(buf,
15857656SSherry.Moore@Sun.COM buf[0] ? "|BOARD INSERT" : "BOARD INSERT");
15861341Sstevel
15871341Sstevel /*
15881341Sstevel * This is a high level mutex, therefore it needs to be
15891341Sstevel * dropped before calling cmn_err.
15901341Sstevel */
15911341Sstevel mutex_exit(&softsp->csr_mutex);
15921341Sstevel
15931341Sstevel cmn_err(CE_WARN, "sysctrl%d: unserviced interrupt."
15947656SSherry.Moore@Sun.COM " possible sources [%s].",
15957656SSherry.Moore@Sun.COM ddi_get_instance(softsp->dip), buf);
15961341Sstevel } else
15971341Sstevel mutex_exit(&softsp->csr_mutex);
15981341Sstevel
15991341Sstevel mutex_enter(&softsp->spur_int_lock);
16001341Sstevel
16011341Sstevel /* do we need to start the short timeout? */
16021341Sstevel if (softsp->spur_timeout_id == 0) {
16031341Sstevel softsp->spur_timeout_id = timeout(spur_retry, softsp,
16041341Sstevel spur_timeout_hz);
16051341Sstevel }
16061341Sstevel
16071341Sstevel /* do we need to start the long timeout? */
16081341Sstevel if (softsp->spur_long_timeout_id == 0) {
16091341Sstevel softsp->spur_long_timeout_id = timeout(spur_long_timeout,
16101341Sstevel softsp, spur_long_timeout_hz);
16111341Sstevel }
16121341Sstevel
16131341Sstevel mutex_exit(&softsp->spur_int_lock);
16141341Sstevel
16151341Sstevel return (DDI_INTR_CLAIMED);
16161341Sstevel }
16171341Sstevel
16181341Sstevel /*
16191341Sstevel * spur_retry
16201341Sstevel *
16211341Sstevel * this routine simply triggers the interrupt which will re-enable
16221341Sstevel * the interrupts disabled by the spurious int detection.
16231341Sstevel */
16241341Sstevel static void
spur_retry(void * arg)16251341Sstevel spur_retry(void *arg)
16261341Sstevel {
16271341Sstevel struct sysctrl_soft_state *softsp = arg;
16281341Sstevel
16291341Sstevel ASSERT(softsp);
16301341Sstevel
16311341Sstevel ddi_trigger_softintr(softsp->spur_high_id);
16321341Sstevel
16331341Sstevel mutex_enter(&softsp->spur_int_lock);
16341341Sstevel softsp->spur_timeout_id = 0;
16351341Sstevel mutex_exit(&softsp->spur_int_lock);
16361341Sstevel }
16371341Sstevel
16381341Sstevel /*
16391341Sstevel * spur_reenable
16401341Sstevel *
16411341Sstevel * OK, we've been slient for a while. Go ahead and re-enable the
16421341Sstevel * interrupts that were enabled at the time of the spurious detection.
16431341Sstevel */
16441341Sstevel static uint_t
spur_reenable(caddr_t arg)16451341Sstevel spur_reenable(caddr_t arg)
16461341Sstevel {
16471341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
16481341Sstevel uchar_t tmp_reg;
16491341Sstevel
16501341Sstevel ASSERT(softsp);
16511341Sstevel
16521341Sstevel mutex_enter(&softsp->csr_mutex);
16531341Sstevel
16541341Sstevel /* reenable those who were spurious candidates */
16551341Sstevel *(softsp->csr) |= softsp->saved_en_state &
16567656SSherry.Moore@Sun.COM (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
16577656SSherry.Moore@Sun.COM SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
16581341Sstevel tmp_reg = *(softsp->csr);
16591341Sstevel #ifdef lint
16601341Sstevel tmp_reg = tmp_reg;
16611341Sstevel #endif
16621341Sstevel
16631341Sstevel /* clear out the saved state */
16641341Sstevel softsp->saved_en_state = 0;
16651341Sstevel
16661341Sstevel mutex_exit(&softsp->csr_mutex);
16671341Sstevel
16681341Sstevel return (DDI_INTR_CLAIMED);
16691341Sstevel }
16701341Sstevel
16711341Sstevel /*
16721341Sstevel * spur_long_timeout
16731341Sstevel *
16741341Sstevel * this routine merely resets the spurious interrupt counter thus ending
16751341Sstevel * the interval of interest. of course this is done by triggering a
16761341Sstevel * softint because the counter is protected by an interrupt mutex.
16771341Sstevel */
16781341Sstevel static void
spur_long_timeout(void * arg)16791341Sstevel spur_long_timeout(void *arg)
16801341Sstevel {
16811341Sstevel struct sysctrl_soft_state *softsp = arg;
16821341Sstevel
16831341Sstevel ASSERT(softsp);
16841341Sstevel
16851341Sstevel ddi_trigger_softintr(softsp->spur_long_to_id);
16861341Sstevel
16871341Sstevel mutex_enter(&softsp->spur_int_lock);
16881341Sstevel softsp->spur_long_timeout_id = 0;
16891341Sstevel mutex_exit(&softsp->spur_int_lock);
16901341Sstevel }
16911341Sstevel
16921341Sstevel /*
16931341Sstevel * spur_clear_count
16941341Sstevel *
16951341Sstevel * simply clear out the spurious interrupt counter.
16961341Sstevel *
16971341Sstevel * softint level only
16981341Sstevel */
16991341Sstevel static uint_t
spur_clear_count(caddr_t arg)17001341Sstevel spur_clear_count(caddr_t arg)
17011341Sstevel {
17021341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
17031341Sstevel
17041341Sstevel ASSERT(softsp);
17051341Sstevel
17061341Sstevel mutex_enter(&softsp->csr_mutex);
17071341Sstevel softsp->spur_count = 0;
17081341Sstevel mutex_exit(&softsp->csr_mutex);
17091341Sstevel
17101341Sstevel return (DDI_INTR_CLAIMED);
17111341Sstevel }
17121341Sstevel
17131341Sstevel /*
17141341Sstevel * ac_fail_handler
17151341Sstevel *
17161341Sstevel * This routine polls the AC power failure bit in the system status2
17171341Sstevel * register. If we get to this routine, then we sensed an ac fail
17181341Sstevel * condition. Note the fact and check again in a few.
17191341Sstevel *
17201341Sstevel * Called as softint from high interrupt.
17211341Sstevel */
17221341Sstevel static uint_t
ac_fail_handler(caddr_t arg)17231341Sstevel ac_fail_handler(caddr_t arg)
17241341Sstevel {
17251341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
17261341Sstevel
17271341Sstevel ASSERT(softsp);
17281341Sstevel
17291341Sstevel cmn_err(CE_WARN, "%s failure detected", ft_str_table[FT_AC_PWR]);
17301341Sstevel reg_fault(0, FT_AC_PWR, FT_SYSTEM);
17311341Sstevel (void) timeout(ac_fail_retry, softsp, ac_timeout_hz);
17321341Sstevel
17331341Sstevel return (DDI_INTR_CLAIMED);
17341341Sstevel }
17351341Sstevel
17361341Sstevel /*
17371341Sstevel * The timeout from ac_fail_handler() that checks to see if the
17381341Sstevel * condition persists.
17391341Sstevel */
17401341Sstevel static void
ac_fail_retry(void * arg)17411341Sstevel ac_fail_retry(void *arg)
17421341Sstevel {
17431341Sstevel struct sysctrl_soft_state *softsp = arg;
17441341Sstevel
17451341Sstevel ASSERT(softsp);
17461341Sstevel
17471341Sstevel if (*softsp->status2 & SYS_AC_FAIL) { /* still bad? */
17481341Sstevel (void) timeout(ac_fail_retry, softsp, ac_timeout_hz);
17491341Sstevel } else {
17501341Sstevel cmn_err(CE_NOTE, "%s failure no longer detected",
17517656SSherry.Moore@Sun.COM ft_str_table[FT_AC_PWR]);
17521341Sstevel clear_fault(0, FT_AC_PWR, FT_SYSTEM);
17531341Sstevel ddi_trigger_softintr(softsp->ac_fail_high_id);
17541341Sstevel }
17551341Sstevel }
17561341Sstevel
17571341Sstevel /*
17581341Sstevel * The interrupt routine that we use to re-enable the interrupt.
17591341Sstevel * Called from ddi_trigger_softint() in the ac_fail_retry() when
17601341Sstevel * the AC is better.
17611341Sstevel */
17621341Sstevel static uint_t
ac_fail_reenable(caddr_t arg)17631341Sstevel ac_fail_reenable(caddr_t arg)
17641341Sstevel {
17651341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
17661341Sstevel uchar_t tmp_reg;
17671341Sstevel
17681341Sstevel ASSERT(softsp);
17691341Sstevel
17701341Sstevel mutex_enter(&softsp->csr_mutex);
17711341Sstevel *(softsp->csr) |= SYS_AC_PWR_FAIL_EN;
17721341Sstevel tmp_reg = *(softsp->csr);
17731341Sstevel #ifdef lint
17741341Sstevel tmp_reg = tmp_reg;
17751341Sstevel #endif
17761341Sstevel mutex_exit(&softsp->csr_mutex);
17771341Sstevel
17781341Sstevel return (DDI_INTR_CLAIMED);
17791341Sstevel }
17801341Sstevel
17811341Sstevel /*
17821341Sstevel * ps_fail_int_handler
17831341Sstevel *
17841341Sstevel * Handle power supply failure interrupt.
17851341Sstevel *
17861341Sstevel * This wrapper is called as softint from hardware interrupt routine.
17871341Sstevel */
17881341Sstevel static uint_t
ps_fail_int_handler(caddr_t arg)17891341Sstevel ps_fail_int_handler(caddr_t arg)
17901341Sstevel {
17911341Sstevel return (ps_fail_handler((struct sysctrl_soft_state *)arg, 1));
17921341Sstevel }
17931341Sstevel
17941341Sstevel /*
17951341Sstevel * ps_fail_poll_handler
17961341Sstevel *
17971341Sstevel * Handle power supply failure interrupt.
17981341Sstevel *
17991341Sstevel * This wrapper is called as softint from power supply poll routine.
18001341Sstevel */
18011341Sstevel static uint_t
ps_fail_poll_handler(caddr_t arg)18021341Sstevel ps_fail_poll_handler(caddr_t arg)
18031341Sstevel {
18041341Sstevel return (ps_fail_handler((struct sysctrl_soft_state *)arg, 0));
18051341Sstevel }
18061341Sstevel
18071341Sstevel /*
18081341Sstevel * ps_fail_handler
18091341Sstevel *
18101341Sstevel * This routine checks all eight of the board power supplies that are
18111341Sstevel * installed plus the Peripheral power supply and the two DC OK. Since the
18121341Sstevel * hardware bits are not enough to indicate Power Supply failure
18131341Sstevel * vs. being turned off via software, the driver must maintain a
18141341Sstevel * shadow state for the Power Supply status and monitor all changes.
18151341Sstevel *
18161341Sstevel * Called as a softint only.
18171341Sstevel */
18181341Sstevel static uint_t
ps_fail_handler(struct sysctrl_soft_state * softsp,int fromint)18191341Sstevel ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint)
18201341Sstevel {
18211341Sstevel int i;
18221341Sstevel struct ps_state *pstatp;
18231341Sstevel int poll_needed = 0;
18241341Sstevel uchar_t ps_stat, ps_pres, status1, status2, pppsr;
18251341Sstevel uchar_t tmp_reg;
18261341Sstevel enum power_state current_power_state;
18271341Sstevel
18281341Sstevel ASSERT(softsp);
18291341Sstevel
18301341Sstevel /* pre-read the hardware state */
18311341Sstevel ps_stat = *softsp->ps_stat;
18321341Sstevel ps_pres = *softsp->ps_pres;
18331341Sstevel status1 = *softsp->status1;
18341341Sstevel status2 = *softsp->status2;
18351341Sstevel pppsr = *softsp->pppsr;
18361341Sstevel
18371341Sstevel (void) fhc_bdlist_lock(-1);
18381341Sstevel
18391341Sstevel mutex_enter(&softsp->ps_fail_lock);
18401341Sstevel
18411341Sstevel for (i = 0, pstatp = &softsp->ps_stats[0]; i < SYS_PS_COUNT;
18421341Sstevel i++, pstatp++) {
18431341Sstevel int temp_psok;
18441341Sstevel int temp_pres;
18451341Sstevel int is_precharge = FALSE;
18461341Sstevel int is_fan_assy = FALSE;
18471341Sstevel
18481341Sstevel /*
18491341Sstevel * pre-compute the presence and ok bits for this
18501341Sstevel * power supply from the hardware registers.
18511341Sstevel * NOTE: 4-slot pps1 is the same as core ps 7...
18521341Sstevel */
18531341Sstevel switch (i) {
18541341Sstevel /* the core power supplies */
18551341Sstevel case 0: case 1: case 2: case 3:
18561341Sstevel case 4: case 5: case 6: case 7:
18571341Sstevel temp_pres = !((ps_pres >> i) & 0x1);
18581341Sstevel temp_psok = (ps_stat >> i) & 0x1;
18591341Sstevel break;
18601341Sstevel
18611341Sstevel /* the first peripheral power supply */
18621341Sstevel case SYS_PPS0_INDEX:
18631341Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
18641341Sstevel temp_psok = status2 & SYS_PPS0_OK;
18651341Sstevel break;
18661341Sstevel
18671341Sstevel /* shared 3.3v clock power */
18681341Sstevel case SYS_CLK_33_INDEX:
18691341Sstevel temp_pres = TRUE;
18701341Sstevel temp_psok = status2 & SYS_CLK_33_OK;
18711341Sstevel break;
18721341Sstevel
18731341Sstevel /* shared 5.0v clock power */
18741341Sstevel case SYS_CLK_50_INDEX:
18751341Sstevel temp_pres = TRUE;
18761341Sstevel temp_psok = status2 & SYS_CLK_50_OK;
18771341Sstevel break;
18781341Sstevel
18791341Sstevel /* peripheral 5v */
18801341Sstevel case SYS_V5_P_INDEX:
18811341Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES) ||
18827656SSherry.Moore@Sun.COM ((IS4SLOT(softsp->nslots) ||
18837656SSherry.Moore@Sun.COM IS5SLOT(softsp->nslots)) &&
18847656SSherry.Moore@Sun.COM !(ps_pres & SYS_NOT_PPS1_PRES));
18851341Sstevel temp_psok = pppsr & SYS_V5_P_OK;
18861341Sstevel break;
18871341Sstevel
18881341Sstevel /* peripheral 12v */
18891341Sstevel case SYS_V12_P_INDEX:
18901341Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES) ||
18917656SSherry.Moore@Sun.COM ((IS4SLOT(softsp->nslots) ||
18927656SSherry.Moore@Sun.COM IS5SLOT(softsp->nslots)) &&
18937656SSherry.Moore@Sun.COM !(ps_pres & SYS_NOT_PPS1_PRES));
18941341Sstevel temp_psok = pppsr & SYS_V12_P_OK;
18951341Sstevel break;
18961341Sstevel
18971341Sstevel /* aux 5v */
18981341Sstevel case SYS_V5_AUX_INDEX:
18991341Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
19001341Sstevel temp_psok = pppsr & SYS_V5_AUX_OK;
19011341Sstevel break;
19021341Sstevel
19031341Sstevel /* peripheral 5v precharge */
19041341Sstevel case SYS_V5_P_PCH_INDEX:
19051341Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
19061341Sstevel temp_psok = pppsr & SYS_V5_P_PCH_OK;
19071341Sstevel is_precharge = TRUE;
19081341Sstevel break;
19091341Sstevel
19101341Sstevel /* peripheral 12v precharge */
19111341Sstevel case SYS_V12_P_PCH_INDEX:
19121341Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
19131341Sstevel temp_psok = pppsr & SYS_V12_P_PCH_OK;
19141341Sstevel is_precharge = TRUE;
19151341Sstevel break;
19161341Sstevel
19171341Sstevel /* 3.3v precharge */
19181341Sstevel case SYS_V3_PCH_INDEX:
19191341Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
19201341Sstevel temp_psok = pppsr & SYS_V3_PCH_OK;
19211341Sstevel is_precharge = TRUE;
19221341Sstevel break;
19231341Sstevel
19241341Sstevel /* 5v precharge */
19251341Sstevel case SYS_V5_PCH_INDEX:
19261341Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
19271341Sstevel temp_psok = pppsr & SYS_V5_PCH_OK;
19281341Sstevel is_precharge = TRUE;
19291341Sstevel break;
19301341Sstevel
19311341Sstevel /* peripheral fan assy */
19321341Sstevel case SYS_P_FAN_INDEX:
19331341Sstevel temp_pres = (IS4SLOT(softsp->nslots) ||
19347656SSherry.Moore@Sun.COM IS5SLOT(softsp->nslots)) &&
19357656SSherry.Moore@Sun.COM !(status1 & SYS_NOT_P_FAN_PRES);
19361341Sstevel temp_psok = softsp->pps_fan_saved &
19377656SSherry.Moore@Sun.COM SYS_AC_FAN_OK;
19381341Sstevel is_fan_assy = TRUE;
19391341Sstevel break;
19401341Sstevel }
19411341Sstevel
19421341Sstevel /* *** Phase 1 -- power supply presence tests *** */
19431341Sstevel
19441341Sstevel /* do we know the presence status for this power supply? */
19451341Sstevel if (pstatp->pshadow == PRES_UNKNOWN) {
19461341Sstevel pstatp->pshadow = temp_pres ? PRES_IN : PRES_OUT;
19471341Sstevel pstatp->dcshadow = temp_pres ? PS_BOOT : PS_OUT;
19481341Sstevel } else {
19491341Sstevel /* has the ps presence state changed? */
19501341Sstevel if (!temp_pres ^ (pstatp->pshadow == PRES_IN)) {
19511341Sstevel pstatp->pctr = 0;
19521341Sstevel } else {
19531341Sstevel /* a change! are we counting? */
19541341Sstevel if (pstatp->pctr == 0) {
19551341Sstevel pstatp->pctr = PS_PRES_CHANGE_TICKS;
19561341Sstevel } else if (--pstatp->pctr == 0) {
19571341Sstevel pstatp->pshadow = temp_pres ?
19587656SSherry.Moore@Sun.COM PRES_IN : PRES_OUT;
19591341Sstevel pstatp->dcshadow = temp_pres ?
19607656SSherry.Moore@Sun.COM PS_UNKNOWN : PS_OUT;
19611341Sstevel
19621341Sstevel /*
19631341Sstevel * Now we know the state has
19641341Sstevel * changed, so we should log it.
19651341Sstevel */
19661341Sstevel ps_log_pres_change(softsp,
19677656SSherry.Moore@Sun.COM i, temp_pres);
19681341Sstevel }
19691341Sstevel }
19701341Sstevel }
19711341Sstevel
19721341Sstevel /* *** Phase 2 -- power supply status tests *** */
19731341Sstevel
19741341Sstevel /* check if the Power Supply is removed or same as before */
19751341Sstevel if ((pstatp->dcshadow == PS_OUT) ||
19761341Sstevel ((pstatp->dcshadow == PS_OK) && temp_psok) ||
19771341Sstevel ((pstatp->dcshadow == PS_FAIL) && !temp_psok)) {
19781341Sstevel pstatp->dcctr = 0;
19791341Sstevel } else {
19801341Sstevel
19811341Sstevel /* OK, a change, do we start the timer? */
19821341Sstevel if (pstatp->dcctr == 0) {
19831341Sstevel switch (pstatp->dcshadow) {
19841341Sstevel case PS_BOOT:
19851341Sstevel pstatp->dcctr = PS_FROM_BOOT_TICKS;
19861341Sstevel break;
19871341Sstevel
19881341Sstevel case PS_UNKNOWN:
19891341Sstevel pstatp->dcctr = is_fan_assy ?
19907656SSherry.Moore@Sun.COM PS_P_FAN_FROM_UNKNOWN_TICKS :
19917656SSherry.Moore@Sun.COM PS_FROM_UNKNOWN_TICKS;
19921341Sstevel break;
19931341Sstevel
19941341Sstevel case PS_OK:
19951341Sstevel pstatp->dcctr = is_precharge ?
19967656SSherry.Moore@Sun.COM PS_PCH_FROM_OK_TICKS :
19977656SSherry.Moore@Sun.COM PS_FROM_OK_TICKS;
19981341Sstevel break;
19991341Sstevel
20001341Sstevel case PS_FAIL:
20011341Sstevel pstatp->dcctr = PS_FROM_FAIL_TICKS;
20021341Sstevel break;
20031341Sstevel
20041341Sstevel default:
20051341Sstevel panic("sysctrl%d: Unknown Power "
20061341Sstevel "Supply State %d", pstatp->dcshadow,
20071341Sstevel ddi_get_instance(softsp->dip));
20081341Sstevel }
20091341Sstevel }
20101341Sstevel
20111341Sstevel /* has the ticker expired? */
20121341Sstevel if (--pstatp->dcctr == 0) {
20131341Sstevel
20141341Sstevel /* we'll skip OK messages during boot */
20151341Sstevel if (!((pstatp->dcshadow == PS_BOOT) &&
20161341Sstevel temp_psok)) {
20171341Sstevel ps_log_state_change(softsp,
20187656SSherry.Moore@Sun.COM i, temp_psok);
20191341Sstevel }
20201341Sstevel
20211341Sstevel /*
20221341Sstevel * remote console interface has to be
20231341Sstevel * reinitialized on the rising edge V5_AUX
20241341Sstevel * when it is NOT boot. At the boot time an
20251341Sstevel * an error condition exists if it was not
20261341Sstevel * enabled before.
20271341Sstevel */
20281341Sstevel if ((i == SYS_V5_AUX_INDEX) &&
20291341Sstevel (pstatp->dcshadow != PS_BOOT) &&
20301341Sstevel (softsp->enable_rcons_atboot)) {
20311341Sstevel if (temp_psok)
20321341Sstevel rcons_reinit(softsp);
20331341Sstevel else
20341341Sstevel /* disable rconsole */
20351341Sstevel *(softsp->clk_freq2) &=
20361341Sstevel ~RCONS_UART_EN;
20371341Sstevel tmp_reg = *(softsp->csr);
20381341Sstevel #ifdef lint
20391341Sstevel tmp_reg = tmp_reg;
20401341Sstevel #endif
20411341Sstevel
20421341Sstevel }
20431341Sstevel
20441341Sstevel /* regardless, update the shadow state */
20451341Sstevel pstatp->dcshadow = temp_psok ? PS_OK : PS_FAIL;
20461341Sstevel
20471341Sstevel /* always update board condition */
20481341Sstevel sysc_policy_update(softsp, NULL,
20497656SSherry.Moore@Sun.COM SYSC_EVT_BD_PS_CHANGE);
20501341Sstevel
20511341Sstevel }
20521341Sstevel }
20531341Sstevel
20541341Sstevel /*
20551341Sstevel * We will need to continue polling for three reasons:
20561341Sstevel * - a failing power supply is detected and we haven't yet
20571341Sstevel * determined the power supplies existence.
20581341Sstevel * - the power supply is just installed and we're waiting
20591341Sstevel * to give it a change to power up,
20601341Sstevel * - a failed power supply state is recognized
20611341Sstevel *
20621341Sstevel * NOTE: PS_FAIL shadow state is not the same as !temp_psok
20631341Sstevel * because of the persistence of PS_FAIL->PS_OK.
20641341Sstevel */
20651341Sstevel if (!temp_psok ||
20661341Sstevel (pstatp->dcshadow == PS_UNKNOWN) ||
20671341Sstevel (pstatp->dcshadow == PS_FAIL)) {
20681341Sstevel poll_needed++;
20691341Sstevel }
20701341Sstevel }
20711341Sstevel
20721341Sstevel /*
20731341Sstevel * Now, get the current power state for this instance.
20741341Sstevel * If the current state is different than what was known, complain.
20751341Sstevel */
20761341Sstevel current_power_state = compute_power_state(softsp, 0);
20771341Sstevel
20781341Sstevel if (softsp->power_state != current_power_state) {
20791341Sstevel switch (current_power_state) {
20801341Sstevel case BELOW_MINIMUM:
20811341Sstevel cmn_err(CE_WARN,
20827656SSherry.Moore@Sun.COM "Insufficient power available to system");
20831341Sstevel if (!disable_insufficient_power_reboot) {
20841341Sstevel cmn_err(CE_WARN, "System reboot in %d seconds",
20857656SSherry.Moore@Sun.COM PS_INSUFFICIENT_COUNTDOWN_SEC);
20861341Sstevel }
20871341Sstevel reg_fault(1, FT_INSUFFICIENT_POWER, FT_SYSTEM);
20881341Sstevel softsp->power_countdown = PS_POWER_COUNTDOWN_TICKS;
20891341Sstevel break;
20901341Sstevel
20911341Sstevel case MINIMUM:
20921341Sstevel /* If we came from REDUNDANT, complain */
20931341Sstevel if (softsp->power_state == REDUNDANT) {
20941341Sstevel cmn_err(CE_WARN, "Redundant power lost");
20951341Sstevel /* If we came from BELOW_MINIMUM, hurrah! */
20961341Sstevel } else if (softsp->power_state == BELOW_MINIMUM) {
20971341Sstevel cmn_err(CE_NOTE, "Minimum power available");
20981341Sstevel clear_fault(1, FT_INSUFFICIENT_POWER,
20997656SSherry.Moore@Sun.COM FT_SYSTEM);
21001341Sstevel }
21011341Sstevel break;
21021341Sstevel
21031341Sstevel case REDUNDANT:
21041341Sstevel /* If we aren't from boot, spread the good news */
21051341Sstevel if (softsp->power_state != BOOT) {
21061341Sstevel cmn_err(CE_NOTE, "Redundant power available");
21071341Sstevel clear_fault(1, FT_INSUFFICIENT_POWER,
21087656SSherry.Moore@Sun.COM FT_SYSTEM);
21091341Sstevel }
21101341Sstevel break;
21111341Sstevel
21121341Sstevel default:
21131341Sstevel break;
21141341Sstevel }
21151341Sstevel softsp->power_state = current_power_state;
21161341Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
21171341Sstevel }
21181341Sstevel
21191341Sstevel mutex_exit(&softsp->ps_fail_lock);
21201341Sstevel
21211341Sstevel fhc_bdlist_unlock();
21221341Sstevel
21231341Sstevel /*
21241341Sstevel * Are we in insufficient powerstate?
21251341Sstevel * If so, is it time to take action?
21261341Sstevel */
21271341Sstevel if (softsp->power_state == BELOW_MINIMUM &&
21281341Sstevel softsp->power_countdown > 0 && --(softsp->power_countdown) == 0 &&
21291341Sstevel !disable_insufficient_power_reboot) {
21301341Sstevel cmn_err(CE_WARN,
21311341Sstevel "Insufficient power. System Reboot Started...");
21321341Sstevel
21331341Sstevel fhc_reboot();
21341341Sstevel }
21351341Sstevel
21361341Sstevel /*
21371341Sstevel * If we don't have ps problems that need to be polled for, then
21381341Sstevel * enable interrupts.
21391341Sstevel */
21401341Sstevel if (!poll_needed) {
21411341Sstevel mutex_enter(&softsp->csr_mutex);
21421341Sstevel *(softsp->csr) |= SYS_PS_FAIL_EN;
21431341Sstevel tmp_reg = *(softsp->csr);
21441341Sstevel #ifdef lint
21451341Sstevel tmp_reg = tmp_reg;
21461341Sstevel #endif
21471341Sstevel mutex_exit(&softsp->csr_mutex);
21481341Sstevel }
21491341Sstevel
21501341Sstevel /*
21511341Sstevel * Only the polling loop re-triggers the polling loop timeout
21521341Sstevel */
21531341Sstevel if (!fromint) {
21541341Sstevel (void) timeout(ps_fail_retry, softsp, ps_fail_timeout_hz);
21551341Sstevel }
21561341Sstevel
21571341Sstevel return (DDI_INTR_CLAIMED);
21581341Sstevel }
21591341Sstevel
21601341Sstevel /*
21611341Sstevel * Compute the current power configuration for this system.
21621341Sstevel * Disk boards and Clock boards are not counted.
21631341Sstevel *
21641341Sstevel * This function must be called with the ps_fail_lock held.
21651341Sstevel */
21661341Sstevel enum power_state
compute_power_state(struct sysctrl_soft_state * softsp,int plus_load)21671341Sstevel compute_power_state(struct sysctrl_soft_state *softsp, int plus_load)
21681341Sstevel {
21691341Sstevel int i;
21701341Sstevel int ok_supply_count = 0;
21711341Sstevel int load_count = 0;
21721341Sstevel int minimum_power_count;
21731341Sstevel int pps_ok;
21741341Sstevel fhc_bd_t *list;
21751341Sstevel
21761341Sstevel ASSERT(mutex_owned(&softsp->ps_fail_lock));
21771341Sstevel
21781341Sstevel /*
21791341Sstevel * Walk down the interesting power supplies and
21801341Sstevel * count the operational power units
21811341Sstevel */
21821341Sstevel for (i = 0; i < 8; i++) {
21831341Sstevel /*
21841341Sstevel * power supply id 7 on a 4 or 5 slot system is PPS1.
21851341Sstevel * don't include it in the redundant core power calculation.
21861341Sstevel */
21871341Sstevel if (i == 7 &&
21881341Sstevel (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)))
21891341Sstevel continue;
21901341Sstevel
21911341Sstevel if (softsp->ps_stats[i].dcshadow == PS_OK)
21921341Sstevel ok_supply_count++;
21931341Sstevel }
21941341Sstevel
21951341Sstevel /* Note the state of the PPS... */
21961341Sstevel pps_ok = (softsp->ps_stats[SYS_PPS0_INDEX].dcshadow == PS_OK);
21971341Sstevel
21981341Sstevel /*
21991341Sstevel * Dynamically compute the load count in the system.
22001341Sstevel * Don't count disk boards or boards in low power state.
22011341Sstevel */
22021341Sstevel for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) {
22031341Sstevel ASSERT(list->sc.type != CLOCK_BOARD);
22041341Sstevel if (list->sc.rstate == SYSC_CFGA_RSTATE_CONNECTED) {
22051341Sstevel load_count++;
22061341Sstevel }
22071341Sstevel }
22081341Sstevel
22091341Sstevel load_count += plus_load;
22101341Sstevel /*
22111341Sstevel * If we are 8 slot and we have 7 or 8 boards, then the PPS
22121341Sstevel * can count as a power supply...
22131341Sstevel */
22141341Sstevel if (IS8SLOT(softsp->nslots) && load_count >= 7 && pps_ok)
22151341Sstevel ok_supply_count++;
22161341Sstevel
22171341Sstevel /*
22181341Sstevel * This is to cover the corner case of a UE3500 having 5
22191341Sstevel * boards installed and still giving it N+1 power status.
22201341Sstevel */
22211341Sstevel if (IS5SLOT(softsp->nslots) && (load_count >= 5))
22221341Sstevel ok_supply_count++;
22231341Sstevel
22241341Sstevel /*
22251341Sstevel * Determine our power situation. This is a simple step
22261341Sstevel * function right now:
22271341Sstevel *
22281341Sstevel * minimum power count = min(7, floor((board count + 1) / 2))
22291341Sstevel */
22301341Sstevel minimum_power_count = (load_count + 1) / 2;
22311341Sstevel if (minimum_power_count > 7)
22321341Sstevel minimum_power_count = 7;
22331341Sstevel
22341341Sstevel if (ok_supply_count > minimum_power_count)
22351341Sstevel return (REDUNDANT);
22361341Sstevel else if (ok_supply_count == minimum_power_count)
22371341Sstevel return (MINIMUM);
22381341Sstevel else
22391341Sstevel return (BELOW_MINIMUM);
22401341Sstevel }
22411341Sstevel
22421341Sstevel /*
22431341Sstevel * log the change of power supply presence
22441341Sstevel */
22451341Sstevel static void
ps_log_pres_change(struct sysctrl_soft_state * softsp,int index,int present)22461341Sstevel ps_log_pres_change(struct sysctrl_soft_state *softsp, int index, int present)
22471341Sstevel {
22481341Sstevel char *trans = present ? "Installed" : "Removed";
22491341Sstevel
22501341Sstevel switch (index) {
22511341Sstevel /* the core power supplies (except for 7) */
22521341Sstevel case 0: case 1: case 2: case 3:
22531341Sstevel case 4: case 5: case 6:
22541341Sstevel cmn_err(CE_NOTE, "%s %d %s", ft_str_table[FT_CORE_PS], index,
22551341Sstevel trans);
22561341Sstevel if (!present) {
22577656SSherry.Moore@Sun.COM clear_fault(index, FT_CORE_PS, FT_SYSTEM);
22587656SSherry.Moore@Sun.COM sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
22591341Sstevel }
22601341Sstevel break;
22611341Sstevel
22621341Sstevel /* power supply 7 / pps 1 */
22631341Sstevel case 7:
22641341Sstevel if (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)) {
22657656SSherry.Moore@Sun.COM cmn_err(CE_NOTE, "%s 1 %s", ft_str_table[FT_PPS],
22667656SSherry.Moore@Sun.COM trans);
22677656SSherry.Moore@Sun.COM if (!present) {
22681341Sstevel clear_fault(1, FT_PPS, FT_SYSTEM);
22697656SSherry.Moore@Sun.COM }
22701341Sstevel } else {
22717656SSherry.Moore@Sun.COM cmn_err(CE_NOTE, "%s %d %s", ft_str_table[FT_CORE_PS],
22727656SSherry.Moore@Sun.COM index, trans);
22737656SSherry.Moore@Sun.COM if (!present) {
22741341Sstevel clear_fault(7, FT_CORE_PS, FT_SYSTEM);
22751341Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
22767656SSherry.Moore@Sun.COM }
22771341Sstevel }
22781341Sstevel break;
22791341Sstevel
22801341Sstevel /* the peripheral power supply 0 */
22811341Sstevel case SYS_PPS0_INDEX:
22821341Sstevel cmn_err(CE_NOTE, "%s 0 %s", ft_str_table[FT_PPS], trans);
22831341Sstevel if (!present) {
22841341Sstevel clear_fault(0, FT_PPS, FT_SYSTEM);
22851341Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
22861341Sstevel }
22871341Sstevel break;
22881341Sstevel
22891341Sstevel /* the peripheral rack fan assy */
22901341Sstevel case SYS_P_FAN_INDEX:
22911341Sstevel cmn_err(CE_NOTE, "%s %s", ft_str_table[FT_PPS_FAN], trans);
22921341Sstevel if (!present) {
22931341Sstevel clear_fault(0, FT_PPS_FAN, FT_SYSTEM);
22941341Sstevel }
22951341Sstevel break;
22961341Sstevel
22971341Sstevel /* we don't mention a change of presence state for any other power */
22981341Sstevel }
22991341Sstevel }
23001341Sstevel
23011341Sstevel /*
23021341Sstevel * log the change of power supply status
23031341Sstevel */
23041341Sstevel static void
ps_log_state_change(struct sysctrl_soft_state * softsp,int index,int ps_ok)23051341Sstevel ps_log_state_change(struct sysctrl_soft_state *softsp, int index, int ps_ok)
23061341Sstevel {
23071341Sstevel int level = ps_ok ? CE_NOTE : CE_WARN;
23081341Sstevel char *s = ps_ok ? "OK" : "Failing";
23091341Sstevel
23101341Sstevel switch (index) {
23111341Sstevel /* the core power supplies (except 7) */
23121341Sstevel case 0: case 1: case 2: case 3:
23131341Sstevel case 4: case 5: case 6:
23141341Sstevel cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS], index, s);
23151341Sstevel if (ps_ok) {
23161341Sstevel clear_fault(index, FT_CORE_PS, FT_SYSTEM);
23171341Sstevel } else {
23181341Sstevel reg_fault(index, FT_CORE_PS, FT_SYSTEM);
23191341Sstevel }
23201341Sstevel break;
23211341Sstevel
23221341Sstevel /* power supply 7 / pps 1 */
23231341Sstevel case 7:
23241341Sstevel if (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)) {
23251341Sstevel cmn_err(level, "%s 1 %s", ft_str_table[FT_PPS], s);
23261341Sstevel if (ps_ok) {
23271341Sstevel clear_fault(1, FT_PPS, FT_SYSTEM);
23281341Sstevel } else {
23291341Sstevel reg_fault(1, FT_PPS, FT_SYSTEM);
23301341Sstevel }
23311341Sstevel } else {
23321341Sstevel cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS],
23337656SSherry.Moore@Sun.COM index, s);
23341341Sstevel if (ps_ok) {
23351341Sstevel clear_fault(index, FT_CORE_PS, FT_SYSTEM);
23361341Sstevel } else {
23371341Sstevel reg_fault(index, FT_CORE_PS, FT_SYSTEM);
23381341Sstevel }
23391341Sstevel }
23401341Sstevel break;
23411341Sstevel
23421341Sstevel /* the peripheral power supply */
23431341Sstevel case SYS_PPS0_INDEX:
23441341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_PPS], s);
23451341Sstevel if (ps_ok) {
23461341Sstevel clear_fault(0, FT_PPS, FT_SYSTEM);
23471341Sstevel } else {
23481341Sstevel reg_fault(0, FT_PPS, FT_SYSTEM);
23491341Sstevel }
23501341Sstevel break;
23511341Sstevel
23521341Sstevel /* shared 3.3v clock power */
23531341Sstevel case SYS_CLK_33_INDEX:
23541341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_CLK_33], s);
23551341Sstevel if (ps_ok) {
23561341Sstevel clear_fault(0, FT_CLK_33, FT_SYSTEM);
23571341Sstevel } else {
23581341Sstevel reg_fault(0, FT_CLK_33, FT_SYSTEM);
23591341Sstevel }
23601341Sstevel break;
23611341Sstevel
23621341Sstevel /* shared 5.0v clock power */
23631341Sstevel case SYS_CLK_50_INDEX:
23641341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_CLK_50], s);
23651341Sstevel if (ps_ok) {
23661341Sstevel clear_fault(0, FT_CLK_50, FT_SYSTEM);
23671341Sstevel } else {
23681341Sstevel reg_fault(0, FT_CLK_50, FT_SYSTEM);
23691341Sstevel }
23701341Sstevel break;
23711341Sstevel
23721341Sstevel /* peripheral 5v */
23731341Sstevel case SYS_V5_P_INDEX:
23741341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_P], s);
23751341Sstevel if (ps_ok) {
23761341Sstevel clear_fault(0, FT_V5_P, FT_SYSTEM);
23771341Sstevel } else {
23781341Sstevel reg_fault(0, FT_V5_P, FT_SYSTEM);
23791341Sstevel }
23801341Sstevel break;
23811341Sstevel
23821341Sstevel /* peripheral 12v */
23831341Sstevel case SYS_V12_P_INDEX:
23841341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V12_P], s);
23851341Sstevel if (ps_ok) {
23861341Sstevel clear_fault(0, FT_V12_P, FT_SYSTEM);
23871341Sstevel } else {
23881341Sstevel reg_fault(0, FT_V12_P, FT_SYSTEM);
23891341Sstevel }
23901341Sstevel break;
23911341Sstevel
23921341Sstevel /* aux 5v */
23931341Sstevel case SYS_V5_AUX_INDEX:
23941341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_AUX], s);
23951341Sstevel if (ps_ok) {
23961341Sstevel clear_fault(0, FT_V5_AUX, FT_SYSTEM);
23971341Sstevel } else {
23981341Sstevel reg_fault(0, FT_V5_AUX, FT_SYSTEM);
23991341Sstevel }
24001341Sstevel break;
24011341Sstevel
24021341Sstevel /* peripheral 5v precharge */
24031341Sstevel case SYS_V5_P_PCH_INDEX:
24041341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_P_PCH], s);
24051341Sstevel if (ps_ok) {
24061341Sstevel clear_fault(0, FT_V5_P_PCH, FT_SYSTEM);
24071341Sstevel } else {
24081341Sstevel reg_fault(0, FT_V5_P_PCH, FT_SYSTEM);
24091341Sstevel }
24101341Sstevel break;
24111341Sstevel
24121341Sstevel /* peripheral 12v precharge */
24131341Sstevel case SYS_V12_P_PCH_INDEX:
24141341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V12_P_PCH], s);
24151341Sstevel if (ps_ok) {
24161341Sstevel clear_fault(0, FT_V12_P_PCH, FT_SYSTEM);
24171341Sstevel } else {
24181341Sstevel reg_fault(0, FT_V12_P_PCH, FT_SYSTEM);
24191341Sstevel }
24201341Sstevel break;
24211341Sstevel
24221341Sstevel /* 3.3v precharge */
24231341Sstevel case SYS_V3_PCH_INDEX:
24241341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V3_PCH], s);
24251341Sstevel if (ps_ok) {
24261341Sstevel clear_fault(0, FT_V3_PCH, FT_SYSTEM);
24271341Sstevel } else {
24281341Sstevel reg_fault(0, FT_V3_PCH, FT_SYSTEM);
24291341Sstevel }
24301341Sstevel break;
24311341Sstevel
24321341Sstevel /* 5v precharge */
24331341Sstevel case SYS_V5_PCH_INDEX:
24341341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_PCH], s);
24351341Sstevel if (ps_ok) {
24361341Sstevel clear_fault(0, FT_V5_PCH, FT_SYSTEM);
24371341Sstevel } else {
24381341Sstevel reg_fault(0, FT_V5_PCH, FT_SYSTEM);
24391341Sstevel }
24401341Sstevel break;
24411341Sstevel
24421341Sstevel /* peripheral power supply fans */
24431341Sstevel case SYS_P_FAN_INDEX:
24441341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_PPS_FAN], s);
24451341Sstevel if (ps_ok) {
24461341Sstevel clear_fault(0, FT_PPS_FAN, FT_SYSTEM);
24471341Sstevel } else {
24481341Sstevel reg_fault(0, FT_PPS_FAN, FT_SYSTEM);
24491341Sstevel }
24501341Sstevel break;
24511341Sstevel }
24521341Sstevel }
24531341Sstevel
24541341Sstevel /*
24551341Sstevel * The timeout from ps_fail_handler() that simply re-triggers a check
24561341Sstevel * of the ps condition.
24571341Sstevel */
24581341Sstevel static void
ps_fail_retry(void * arg)24591341Sstevel ps_fail_retry(void *arg)
24601341Sstevel {
24611341Sstevel struct sysctrl_soft_state *softsp = arg;
24621341Sstevel
24631341Sstevel ASSERT(softsp);
24641341Sstevel
24651341Sstevel ddi_trigger_softintr(softsp->ps_fail_poll_id);
24661341Sstevel }
24671341Sstevel
24681341Sstevel /*
24691341Sstevel * pps_fanfail_handler
24701341Sstevel *
24711341Sstevel * This routine is called from the high level handler.
24721341Sstevel */
24731341Sstevel static uint_t
pps_fanfail_handler(caddr_t arg)24741341Sstevel pps_fanfail_handler(caddr_t arg)
24751341Sstevel {
24761341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
24771341Sstevel
24781341Sstevel ASSERT(softsp);
24791341Sstevel
24801341Sstevel /* always check again in a bit by re-enabling the fan interrupt */
24811341Sstevel (void) timeout(pps_fanfail_retry, softsp, pps_fan_timeout_hz);
24821341Sstevel
24831341Sstevel return (DDI_INTR_CLAIMED);
24841341Sstevel }
24851341Sstevel
24861341Sstevel /*
24871341Sstevel * After a bit of waiting, we simply re-enable the interrupt to
24881341Sstevel * see if we get another one. The softintr triggered routine does
24891341Sstevel * the dirty work for us since it runs in the interrupt context.
24901341Sstevel */
24911341Sstevel static void
pps_fanfail_retry(void * arg)24921341Sstevel pps_fanfail_retry(void *arg)
24931341Sstevel {
24941341Sstevel struct sysctrl_soft_state *softsp = arg;
24951341Sstevel
24961341Sstevel ASSERT(softsp);
24971341Sstevel
24981341Sstevel ddi_trigger_softintr(softsp->pps_fan_high_id);
24991341Sstevel }
25001341Sstevel
25011341Sstevel /*
25021341Sstevel * The other half of the retry handler run from the interrupt context
25031341Sstevel */
25041341Sstevel static uint_t
pps_fanfail_reenable(caddr_t arg)25051341Sstevel pps_fanfail_reenable(caddr_t arg)
25061341Sstevel {
25071341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
25081341Sstevel uchar_t tmp_reg;
25091341Sstevel
25101341Sstevel ASSERT(softsp);
25111341Sstevel
25121341Sstevel mutex_enter(&softsp->csr_mutex);
25131341Sstevel
25141341Sstevel /*
25151341Sstevel * re-initialize the bit field for all pps fans to assumed good.
25161341Sstevel * If the fans are still bad, we're going to get an immediate system
25171341Sstevel * interrupt which will put the correct state back anyway.
25181341Sstevel *
25191341Sstevel * NOTE: the polling routines that use this state understand the
25201341Sstevel * pulse resulting from above...
25211341Sstevel */
25221341Sstevel softsp->pps_fan_saved = SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK;
25231341Sstevel
25241341Sstevel *(softsp->csr) |= SYS_PPS_FAN_FAIL_EN;
25251341Sstevel tmp_reg = *(softsp->csr);
25261341Sstevel #ifdef lint
25271341Sstevel tmp_reg = tmp_reg;
25281341Sstevel #endif
25291341Sstevel mutex_exit(&softsp->csr_mutex);
25301341Sstevel
25311341Sstevel return (DDI_INTR_CLAIMED);
25321341Sstevel }
25331341Sstevel
25341341Sstevel /*
25351341Sstevel *
25361341Sstevel * Poll the hardware shadow state to determine the pps fan status.
25371341Sstevel * The shadow state is maintained by the system_high handler and its
25381341Sstevel * associated pps_* functions (above).
25391341Sstevel *
25401341Sstevel * There is a short time interval where the shadow state is pulsed to
25411341Sstevel * the OK state even when the fans are bad. However, this polling
25421341Sstevel * routine has some built in hysteresis to filter out those _normal_
25431341Sstevel * events.
25441341Sstevel */
25451341Sstevel static void
pps_fan_poll(void * arg)25461341Sstevel pps_fan_poll(void *arg)
25471341Sstevel {
25481341Sstevel struct sysctrl_soft_state *softsp = arg;
25491341Sstevel int i;
25501341Sstevel
25511341Sstevel ASSERT(softsp);
25521341Sstevel
25531341Sstevel for (i = 0; i < SYS_PPS_FAN_COUNT; i++) {
25541341Sstevel int fanfail = FALSE;
25551341Sstevel
25561341Sstevel /* determine fan status */
25571341Sstevel switch (i) {
25581341Sstevel case RACK:
25591341Sstevel fanfail = softsp->pps_fan_saved & SYS_RACK_FANFAIL;
25601341Sstevel break;
25611341Sstevel
25621341Sstevel case AC:
25631341Sstevel /*
25641341Sstevel * Don't bother polling the AC fan on 4 and 5 slot
25651341Sstevel * systems.
25661341Sstevel * Rather, it is handled by the power supply loop.
25671341Sstevel */
25681341Sstevel fanfail = !(IS4SLOT(softsp->nslots) ||
25697656SSherry.Moore@Sun.COM IS5SLOT(softsp->nslots)) &&
25707656SSherry.Moore@Sun.COM !(softsp->pps_fan_saved & SYS_AC_FAN_OK);
25711341Sstevel break;
25721341Sstevel
25731341Sstevel case KEYSW:
25741341Sstevel /*
25751341Sstevel * This signal is not usable if aux5v is missing
25761341Sstevel * so we will synthesize a failed fan when aux5v
25771341Sstevel * fails or when pps0 is out.
25781341Sstevel * The 4 and 5 slot systems behave the same.
25791341Sstevel */
25801341Sstevel fanfail = (!(IS4SLOT(softsp->nslots) ||
25817656SSherry.Moore@Sun.COM IS5SLOT(softsp->nslots)) &&
25821341Sstevel (softsp->ps_stats[SYS_V5_AUX_INDEX].dcshadow !=
25837656SSherry.Moore@Sun.COM PS_OK)) ||
25841341Sstevel !(softsp->pps_fan_saved & SYS_KEYSW_FAN_OK);
25851341Sstevel break;
25861341Sstevel
25871341Sstevel }
25881341Sstevel
25891341Sstevel /* is the fan bad? */
25901341Sstevel if (fanfail) {
25911341Sstevel
25921341Sstevel /* is this condition different than we know? */
25931341Sstevel if (softsp->pps_fan_state_count[i] == 0) {
25941341Sstevel
25951341Sstevel /* log the change to failed */
25961341Sstevel pps_fan_state_change(softsp, i, FALSE);
25971341Sstevel }
25981341Sstevel
25991341Sstevel /* always restart the fan OK counter */
26001341Sstevel softsp->pps_fan_state_count[i] = PPS_FROM_FAIL_TICKS;
26011341Sstevel } else {
26021341Sstevel
26031341Sstevel /* do we currently know the fan is bad? */
26041341Sstevel if (softsp->pps_fan_state_count[i]) {
26051341Sstevel
26061341Sstevel /* yes, but has it been stable? */
26071341Sstevel if (--softsp->pps_fan_state_count[i] == 0) {
26081341Sstevel
26091341Sstevel /* log the change to OK */
26101341Sstevel pps_fan_state_change(softsp, i, TRUE);
26111341Sstevel }
26121341Sstevel }
26131341Sstevel }
26141341Sstevel }
26151341Sstevel
26161341Sstevel /* always check again in a bit by re-enabling the fan interrupt */
26171341Sstevel (void) timeout(pps_fan_poll, softsp, pps_fan_timeout_hz);
26181341Sstevel }
26191341Sstevel
26201341Sstevel /*
26211341Sstevel * pps_fan_state_change()
26221341Sstevel *
26231341Sstevel * Log the changed fan condition and update the external status.
26241341Sstevel */
26251341Sstevel static void
pps_fan_state_change(struct sysctrl_soft_state * softsp,int index,int fan_ok)26261341Sstevel pps_fan_state_change(struct sysctrl_soft_state *softsp, int index, int fan_ok)
26271341Sstevel {
26281341Sstevel char *fan_type;
26291341Sstevel char *state = fan_ok ? "fans OK" : "fan failure detected";
26301341Sstevel
26311341Sstevel switch (index) {
26321341Sstevel case RACK:
26331341Sstevel /* 4 and 5 slot systems behave the same */
26341341Sstevel fan_type = (IS4SLOT(softsp->nslots) ||
26357656SSherry.Moore@Sun.COM IS5SLOT(softsp->nslots)) ?
26367656SSherry.Moore@Sun.COM "Disk Drive" : "Rack Exhaust";
26371341Sstevel if (fan_ok) {
26381341Sstevel softsp->pps_fan_external_state &= ~SYS_RACK_FANFAIL;
26391341Sstevel clear_fault(0, (IS4SLOT(softsp->nslots) ||
26407656SSherry.Moore@Sun.COM IS5SLOT(softsp->nslots)) ? FT_DSK_FAN :
26417656SSherry.Moore@Sun.COM FT_RACK_EXH, FT_SYSTEM);
26421341Sstevel } else {
26431341Sstevel softsp->pps_fan_external_state |= SYS_RACK_FANFAIL;
26441341Sstevel reg_fault(0, (IS4SLOT(softsp->nslots) ||
26457656SSherry.Moore@Sun.COM IS5SLOT(softsp->nslots)) ? FT_DSK_FAN :
26467656SSherry.Moore@Sun.COM FT_RACK_EXH, FT_SYSTEM);
26471341Sstevel }
26481341Sstevel break;
26491341Sstevel
26501341Sstevel case AC:
26511341Sstevel fan_type = "AC Box";
26521341Sstevel if (fan_ok) {
26531341Sstevel softsp->pps_fan_external_state |= SYS_AC_FAN_OK;
26541341Sstevel clear_fault(0, FT_AC_FAN, FT_SYSTEM);
26551341Sstevel } else {
26561341Sstevel softsp->pps_fan_external_state &= ~SYS_AC_FAN_OK;
26571341Sstevel reg_fault(0, FT_AC_FAN, FT_SYSTEM);
26581341Sstevel }
26591341Sstevel break;
26601341Sstevel
26611341Sstevel case KEYSW:
26621341Sstevel fan_type = "Keyswitch";
26631341Sstevel if (fan_ok) {
26641341Sstevel softsp->pps_fan_external_state |= SYS_KEYSW_FAN_OK;
26651341Sstevel clear_fault(0, FT_KEYSW_FAN, FT_SYSTEM);
26661341Sstevel } else {
26671341Sstevel softsp->pps_fan_external_state &= ~SYS_KEYSW_FAN_OK;
26681341Sstevel reg_fault(0, FT_KEYSW_FAN, FT_SYSTEM);
26691341Sstevel }
26701341Sstevel break;
26711341Sstevel default:
26721341Sstevel fan_type = "[invalid fan id]";
26731341Sstevel break;
26741341Sstevel }
26751341Sstevel
26761341Sstevel /* now log the state change */
26771341Sstevel cmn_err(fan_ok ? CE_NOTE : CE_WARN, "%s %s", fan_type, state);
26781341Sstevel }
26791341Sstevel
26801341Sstevel static uint_t
bd_insert_handler(caddr_t arg)26811341Sstevel bd_insert_handler(caddr_t arg)
26821341Sstevel {
26831341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
26841341Sstevel
26851341Sstevel ASSERT(softsp);
26861341Sstevel
26871341Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, ("bd_insert_handler()"));
26881341Sstevel
26891341Sstevel (void) timeout(bd_insert_timeout, softsp, bd_insert_delay_hz);
26901341Sstevel
26911341Sstevel return (DDI_INTR_CLAIMED);
26921341Sstevel }
26931341Sstevel
26941341Sstevel void
bd_remove_poll(struct sysctrl_soft_state * softsp)26951341Sstevel bd_remove_poll(struct sysctrl_soft_state *softsp)
26961341Sstevel {
26971341Sstevel ASSERT(fhc_bdlist_locked());
26981341Sstevel
26991341Sstevel if (!bd_remove_to_id) {
27001341Sstevel bd_remove_to_id = timeout(bd_remove_timeout, softsp,
27017656SSherry.Moore@Sun.COM bd_remove_timeout_hz);
27021341Sstevel } else {
27031341Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG,
27047656SSherry.Moore@Sun.COM ("bd_remove_poll ignoring start request"));
27051341Sstevel }
27061341Sstevel }
27071341Sstevel
27081341Sstevel /*
27091341Sstevel * bd_insert_timeout()
27101341Sstevel *
27111341Sstevel * This routine handles the board insert interrupt. It is called from a
27121341Sstevel * timeout so that it does not run at interrupt level. The main job
27131341Sstevel * of this routine is to find hotplugged boards and de-assert the
27141341Sstevel * board insert interrupt coming from the board. For hotplug phase I,
27151341Sstevel * the routine also powers down the board.
27161341Sstevel * JTAG scan is used to find boards which have been inserted.
27171341Sstevel * All other control of the boards is also done by JTAG scan.
27181341Sstevel */
27191341Sstevel static void
bd_insert_timeout(void * arg)27201341Sstevel bd_insert_timeout(void *arg)
27211341Sstevel {
27221341Sstevel struct sysctrl_soft_state *softsp = arg;
27231341Sstevel int found;
27241341Sstevel
27251341Sstevel ASSERT(softsp);
27261341Sstevel
27271341Sstevel if (sysctrl_hotplug_disabled) {
27281341Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_HP_DISABLED);
27291341Sstevel } else {
27301341Sstevel /*
27311341Sstevel * Lock the board list mutex. Keep it locked until all work
27321341Sstevel * is done.
27331341Sstevel */
27341341Sstevel (void) fhc_bdlist_lock(-1);
27351341Sstevel
27361341Sstevel found = fhc_bd_insert_scan();
27371341Sstevel
27381341Sstevel if (found) {
27391341Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG,
27401341Sstevel ("bd_insert_timeout starting bd_remove_poll()"));
27411341Sstevel bd_remove_poll(softsp);
27421341Sstevel }
27431341Sstevel
27441341Sstevel fhc_bdlist_unlock();
27451341Sstevel }
27461341Sstevel
27471341Sstevel /*
27481341Sstevel * Enable interrupts.
27491341Sstevel */
27501341Sstevel ddi_trigger_softintr(softsp->sbrd_gone_id);
27511341Sstevel }
27521341Sstevel
27531341Sstevel static void
bd_remove_timeout(void * arg)27541341Sstevel bd_remove_timeout(void *arg)
27551341Sstevel {
27561341Sstevel struct sysctrl_soft_state *softsp = arg;
27571341Sstevel int keep_polling;
27581341Sstevel
27591341Sstevel ASSERT(softsp);
27601341Sstevel
27611341Sstevel /*
27621341Sstevel * Lock the board list mutex. Keep it locked until all work
27631341Sstevel * is done.
27641341Sstevel */
27651341Sstevel (void) fhc_bdlist_lock(-1);
27661341Sstevel
27671341Sstevel bd_remove_to_id = 0; /* delete our timeout ID */
27681341Sstevel
27691341Sstevel keep_polling = fhc_bd_remove_scan();
27701341Sstevel
27711341Sstevel if (keep_polling) {
27721341Sstevel bd_remove_poll(softsp);
27731341Sstevel } else {
27741341Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, ("exiting bd_remove_poll."));
27751341Sstevel }
27761341Sstevel
27771341Sstevel fhc_bdlist_unlock();
27781341Sstevel }
27791341Sstevel
27801341Sstevel static uint_t
bd_insert_normal(caddr_t arg)27811341Sstevel bd_insert_normal(caddr_t arg)
27821341Sstevel {
27831341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
27841341Sstevel uchar_t tmp_reg;
27851341Sstevel
27861341Sstevel ASSERT(softsp);
27871341Sstevel
27881341Sstevel /* has the condition been removed? */
27891341Sstevel /* XXX add deglitch state machine here */
27901341Sstevel if (!(*(softsp->status1) & SYS_NOT_BRD_PRES)) {
27911341Sstevel /* check again in a few */
27921341Sstevel (void) timeout(bd_insert_timeout, softsp, bd_insert_retry_hz);
27931341Sstevel } else {
27941341Sstevel /* Turn on the enable bit for this interrupt */
27951341Sstevel mutex_enter(&softsp->csr_mutex);
27961341Sstevel *(softsp->csr) |= SYS_SBRD_PRES_EN;
27971341Sstevel /* flush the hardware store buffer */
27981341Sstevel tmp_reg = *(softsp->csr);
27991341Sstevel #ifdef lint
28001341Sstevel tmp_reg = tmp_reg;
28011341Sstevel #endif
28021341Sstevel mutex_exit(&softsp->csr_mutex);
28031341Sstevel }
28041341Sstevel
28051341Sstevel return (DDI_INTR_CLAIMED);
28061341Sstevel }
28071341Sstevel
28081341Sstevel /*
28091341Sstevel * blink LED handler.
28101341Sstevel *
28111341Sstevel * The actual bit manipulation needs to occur at interrupt level
28121341Sstevel * because we need access to the CSR with its CSR mutex
28131341Sstevel */
28141341Sstevel static uint_t
blink_led_handler(caddr_t arg)28151341Sstevel blink_led_handler(caddr_t arg)
28161341Sstevel {
28171341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
28181341Sstevel uchar_t tmp_reg;
28191341Sstevel
28201341Sstevel ASSERT(softsp);
28211341Sstevel
28221341Sstevel mutex_enter(&softsp->csr_mutex);
28231341Sstevel
28241341Sstevel /*
28251341Sstevel * XXX - The lock for the sys_led is not held here. If more
28261341Sstevel * complicated tasks are done with the System LED, then
28271341Sstevel * locking should be done here.
28281341Sstevel */
28291341Sstevel
28301341Sstevel /* read the hardware register. */
28311341Sstevel tmp_reg = *(softsp->csr);
28321341Sstevel
28331341Sstevel /* Only turn on the OS System LED bit if the softsp state is on. */
28341341Sstevel if (softsp->sys_led) {
28351341Sstevel tmp_reg |= SYS_LED_RIGHT;
28361341Sstevel } else {
28371341Sstevel tmp_reg &= ~SYS_LED_RIGHT;
28381341Sstevel }
28391341Sstevel
28401341Sstevel /* Turn on the yellow LED if system fault status is set. */
28411341Sstevel if (softsp->sys_fault) {
28421341Sstevel tmp_reg |= SYS_LED_MID;
28431341Sstevel } else {
28441341Sstevel tmp_reg &= ~SYS_LED_MID;
28451341Sstevel }
28461341Sstevel
28471341Sstevel /* write to the hardware register */
28481341Sstevel *(softsp->csr) = tmp_reg;
28491341Sstevel
28501341Sstevel /* flush the hardware store buffer */
28511341Sstevel tmp_reg = *(softsp->csr);
28521341Sstevel #ifdef lint
28531341Sstevel tmp_reg = tmp_reg;
28541341Sstevel #endif
28551341Sstevel mutex_exit(&softsp->csr_mutex);
28561341Sstevel
28571341Sstevel (void) timeout(blink_led_timeout, softsp, blink_led_timeout_hz);
28581341Sstevel
28591341Sstevel return (DDI_INTR_CLAIMED);
28601341Sstevel }
28611341Sstevel
28621341Sstevel /*
28631341Sstevel * simply re-trigger the interrupt handler on led timeout
28641341Sstevel */
28651341Sstevel static void
blink_led_timeout(void * arg)28661341Sstevel blink_led_timeout(void *arg)
28671341Sstevel {
28681341Sstevel struct sysctrl_soft_state *softsp = arg;
28691341Sstevel int led_state;
28701341Sstevel
28711341Sstevel ASSERT(softsp);
28721341Sstevel
28731341Sstevel /*
28741341Sstevel * Process the system fault list here. This is where the driver
28751341Sstevel * must decide what yellow LEDs to turn on if any. The fault
28761341Sstevel * list is walked and each fhc_list entry is updated with it's
28771341Sstevel * yellow LED status. This info is used later by the routine
28781341Sstevel * toggle_board_green_leds().
28791341Sstevel *
28801341Sstevel * The variable system_fault is non-zero if any non-
28811341Sstevel * suppressed faults are found in the system.
28821341Sstevel */
28831341Sstevel softsp->sys_fault = process_fault_list();
28841341Sstevel
28851341Sstevel /* blink the system board OS LED */
28861341Sstevel mutex_enter(&softsp->sys_led_lock);
28871341Sstevel softsp->sys_led = !softsp->sys_led;
28881341Sstevel led_state = softsp->sys_led;
28891341Sstevel mutex_exit(&softsp->sys_led_lock);
28901341Sstevel
28911341Sstevel toggle_board_green_leds(led_state);
28921341Sstevel
28931341Sstevel ddi_trigger_softintr(softsp->blink_led_id);
28941341Sstevel }
28951341Sstevel
28961341Sstevel void
toggle_board_green_leds(int led_state)28971341Sstevel toggle_board_green_leds(int led_state)
28981341Sstevel {
28991341Sstevel fhc_bd_t *list;
29001341Sstevel
29011341Sstevel (void) fhc_bdlist_lock(-1);
29021341Sstevel for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) {
29031341Sstevel uint_t value = 0;
29041341Sstevel
29051341Sstevel if (list->sc.in_transition ||
29061341Sstevel (list->sc.rstate != SYSC_CFGA_RSTATE_CONNECTED))
29071341Sstevel continue;
29081341Sstevel
29091341Sstevel ASSERT(list->sc.type != CLOCK_BOARD);
29101341Sstevel ASSERT(list->sc.type != DISK_BOARD);
29111341Sstevel ASSERT(list->softsp);
29121341Sstevel
29131341Sstevel if ((list->sc.ostate == SYSC_CFGA_OSTATE_CONFIGURED) &&
29141341Sstevel led_state)
29151341Sstevel value |= FHC_LED_RIGHT;
29161341Sstevel
29171341Sstevel if (list->fault)
29181341Sstevel value |= FHC_LED_MID;
29191341Sstevel else
29201341Sstevel value &= ~FHC_LED_MID;
29211341Sstevel
29221341Sstevel update_board_leds(list, FHC_LED_RIGHT|FHC_LED_MID, value);
29231341Sstevel }
29241341Sstevel fhc_bdlist_unlock();
29251341Sstevel }
29261341Sstevel
29271341Sstevel /*
29281341Sstevel * timestamp an AC power failure in nvram
29291341Sstevel */
29301341Sstevel static void
nvram_update_powerfail(struct sysctrl_soft_state * softsp)29311341Sstevel nvram_update_powerfail(struct sysctrl_soft_state *softsp)
29321341Sstevel {
29331341Sstevel char buf[80];
29341341Sstevel int len = 0;
29351341Sstevel
29361341Sstevel numtos(gethrestime_sec(), buf);
29371341Sstevel
29381341Sstevel if (softsp->options_nodeid) {
29391341Sstevel len = prom_setprop(softsp->options_nodeid, "powerfail-time",
29407656SSherry.Moore@Sun.COM buf, strlen(buf)+1);
29411341Sstevel }
29421341Sstevel
29431341Sstevel if (len <= 0) {
29441341Sstevel cmn_err(CE_WARN, "sysctrl%d: failed to set powerfail-time "
29457656SSherry.Moore@Sun.COM "to %s\n", ddi_get_instance(softsp->dip), buf);
29461341Sstevel }
29471341Sstevel }
29481341Sstevel
29491341Sstevel void
sysctrl_add_kstats(struct sysctrl_soft_state * softsp)29501341Sstevel sysctrl_add_kstats(struct sysctrl_soft_state *softsp)
29511341Sstevel {
29521341Sstevel struct kstat *ksp; /* Generic sysctrl kstats */
29531341Sstevel struct kstat *pksp; /* Power Supply kstat */
29541341Sstevel struct kstat *tksp; /* Sysctrl temperatrure kstat */
29551341Sstevel struct kstat *ttsp; /* Sysctrl temperature test kstat */
29561341Sstevel
29571341Sstevel if ((ksp = kstat_create("unix", ddi_get_instance(softsp->dip),
29581341Sstevel SYSCTRL_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED,
29591341Sstevel sizeof (struct sysctrl_kstat) / sizeof (kstat_named_t),
29601341Sstevel KSTAT_FLAG_PERSISTENT)) == NULL) {
29611341Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
29627656SSherry.Moore@Sun.COM ddi_get_instance(softsp->dip));
29631341Sstevel } else {
29641341Sstevel struct sysctrl_kstat *sysksp;
29651341Sstevel
29661341Sstevel sysksp = (struct sysctrl_kstat *)(ksp->ks_data);
29671341Sstevel
29681341Sstevel /* now init the named kstats */
29691341Sstevel kstat_named_init(&sysksp->csr, CSR_KSTAT_NAMED,
29707656SSherry.Moore@Sun.COM KSTAT_DATA_CHAR);
29711341Sstevel
29721341Sstevel kstat_named_init(&sysksp->status1, STAT1_KSTAT_NAMED,
29737656SSherry.Moore@Sun.COM KSTAT_DATA_CHAR);
29741341Sstevel
29751341Sstevel kstat_named_init(&sysksp->status2, STAT2_KSTAT_NAMED,
29767656SSherry.Moore@Sun.COM KSTAT_DATA_CHAR);
29771341Sstevel
29781341Sstevel kstat_named_init(&sysksp->clk_freq2, CLK_FREQ2_KSTAT_NAMED,
29797656SSherry.Moore@Sun.COM KSTAT_DATA_CHAR);
29801341Sstevel
29811341Sstevel kstat_named_init(&sysksp->fan_status, FAN_KSTAT_NAMED,
29827656SSherry.Moore@Sun.COM KSTAT_DATA_CHAR);
29831341Sstevel
29841341Sstevel kstat_named_init(&sysksp->key_status, KEY_KSTAT_NAMED,
29857656SSherry.Moore@Sun.COM KSTAT_DATA_CHAR);
29861341Sstevel
29871341Sstevel kstat_named_init(&sysksp->power_state, POWER_KSTAT_NAMED,
29887656SSherry.Moore@Sun.COM KSTAT_DATA_INT32);
29891341Sstevel
29901341Sstevel kstat_named_init(&sysksp->clk_ver, CLK_VER_KSTAT_NAME,
29917656SSherry.Moore@Sun.COM KSTAT_DATA_CHAR);
29921341Sstevel
29931341Sstevel ksp->ks_update = sysctrl_kstat_update;
29941341Sstevel ksp->ks_private = (void *)softsp;
29951341Sstevel kstat_install(ksp);
29961341Sstevel }
29971341Sstevel
29981341Sstevel if ((tksp = kstat_create("unix", CLOCK_BOARD_INDEX,
29991341Sstevel OVERTEMP_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
30001341Sstevel sizeof (struct temp_stats), KSTAT_FLAG_PERSISTENT)) == NULL) {
30011341Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
30021341Sstevel ddi_get_instance(softsp->dip));
30031341Sstevel } else {
30041341Sstevel tksp->ks_update = overtemp_kstat_update;
30051341Sstevel tksp->ks_private = (void *)&softsp->tempstat;
30061341Sstevel kstat_install(tksp);
30071341Sstevel }
30081341Sstevel
30091341Sstevel if ((ttsp = kstat_create("unix", CLOCK_BOARD_INDEX,
30101341Sstevel TEMP_OVERRIDE_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, sizeof (short),
30117656SSherry.Moore@Sun.COM KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
30121341Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
30137656SSherry.Moore@Sun.COM ddi_get_instance(softsp->dip));
30141341Sstevel } else {
30151341Sstevel ttsp->ks_update = temp_override_kstat_update;
30161341Sstevel ttsp->ks_private = (void *)&softsp->tempstat.override;
30171341Sstevel kstat_install(ttsp);
30181341Sstevel }
30191341Sstevel
30201341Sstevel if ((pksp = kstat_create("unix", ddi_get_instance(softsp->dip),
30211341Sstevel PSSHAD_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
30221341Sstevel SYS_PS_COUNT, KSTAT_FLAG_PERSISTENT)) == NULL) {
30231341Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
30247656SSherry.Moore@Sun.COM ddi_get_instance(softsp->dip));
30251341Sstevel } else {
30261341Sstevel pksp->ks_update = psstat_kstat_update;
30271341Sstevel pksp->ks_private = (void *)softsp;
30281341Sstevel kstat_install(pksp);
30291341Sstevel }
30301341Sstevel }
30311341Sstevel
30321341Sstevel static int
sysctrl_kstat_update(kstat_t * ksp,int rw)30331341Sstevel sysctrl_kstat_update(kstat_t *ksp, int rw)
30341341Sstevel {
30351341Sstevel struct sysctrl_kstat *sysksp;
30361341Sstevel struct sysctrl_soft_state *softsp;
30371341Sstevel
30381341Sstevel sysksp = (struct sysctrl_kstat *)(ksp->ks_data);
30391341Sstevel softsp = (struct sysctrl_soft_state *)(ksp->ks_private);
30401341Sstevel
30411341Sstevel /* this is a read-only kstat. Exit on a write */
30421341Sstevel
30431341Sstevel if (rw == KSTAT_WRITE) {
30441341Sstevel return (EACCES);
30451341Sstevel } else {
30461341Sstevel /*
30471341Sstevel * copy the current state of the hardware into the
30481341Sstevel * kstat structure.
30491341Sstevel */
30501341Sstevel sysksp->csr.value.c[0] = *(softsp->csr);
30511341Sstevel sysksp->status1.value.c[0] = *(softsp->status1);
30521341Sstevel sysksp->status2.value.c[0] = *(softsp->status2);
30531341Sstevel sysksp->clk_freq2.value.c[0] = *(softsp->clk_freq2);
30541341Sstevel
30551341Sstevel sysksp->fan_status.value.c[0] = softsp->pps_fan_external_state;
30561341Sstevel sysksp->key_status.value.c[0] = softsp->key_shadow;
30571341Sstevel sysksp->power_state.value.i32 = softsp->power_state;
30581341Sstevel
30591341Sstevel /*
30601341Sstevel * non-existence of the clock version register returns the
30611341Sstevel * value 0xff when the hardware register location is read
30621341Sstevel */
30631341Sstevel if (softsp->clk_ver != NULL)
30641341Sstevel sysksp->clk_ver.value.c[0] = *(softsp->clk_ver);
30651341Sstevel else
30661341Sstevel sysksp->clk_ver.value.c[0] = (char)0xff;
30671341Sstevel }
30681341Sstevel return (0);
30691341Sstevel }
30701341Sstevel
30711341Sstevel static int
psstat_kstat_update(kstat_t * ksp,int rw)30721341Sstevel psstat_kstat_update(kstat_t *ksp, int rw)
30731341Sstevel {
30741341Sstevel struct sysctrl_soft_state *softsp;
30751341Sstevel uchar_t *ptr = (uchar_t *)(ksp->ks_data);
30761341Sstevel int ps;
30771341Sstevel
30781341Sstevel softsp = (struct sysctrl_soft_state *)(ksp->ks_private);
30791341Sstevel
30801341Sstevel if (rw == KSTAT_WRITE) {
30811341Sstevel return (EACCES);
30821341Sstevel } else {
30831341Sstevel for (ps = 0; ps < SYS_PS_COUNT; ps++) {
30841341Sstevel *ptr++ = softsp->ps_stats[ps].dcshadow;
30851341Sstevel }
30861341Sstevel }
30871341Sstevel return (0);
30881341Sstevel }
30891341Sstevel
30901341Sstevel static void
sysctrl_thread_wakeup(void * arg)30911341Sstevel sysctrl_thread_wakeup(void *arg)
30921341Sstevel {
30931341Sstevel int type = (int)(uintptr_t)arg;
30941341Sstevel
30951341Sstevel /*
30961341Sstevel * grab mutex to guarantee that our wakeup call
30971341Sstevel * arrives after we go to sleep -- so we can't sleep forever.
30981341Sstevel */
30991341Sstevel mutex_enter(&sslist_mutex);
31001341Sstevel switch (type) {
31011341Sstevel case OVERTEMP_POLL:
31021341Sstevel cv_signal(&overtemp_cv);
31031341Sstevel break;
31041341Sstevel case KEYSWITCH_POLL:
31051341Sstevel cv_signal(&keyswitch_cv);
31061341Sstevel break;
31071341Sstevel default:
31081341Sstevel cmn_err(CE_WARN, "sysctrl: invalid type %d to wakeup\n", type);
31091341Sstevel break;
31101341Sstevel }
31111341Sstevel mutex_exit(&sslist_mutex);
31121341Sstevel }
31131341Sstevel
31141341Sstevel static void
sysctrl_overtemp_poll(void)31151341Sstevel sysctrl_overtemp_poll(void)
31161341Sstevel {
31171341Sstevel struct sysctrl_soft_state *list;
31181341Sstevel callb_cpr_t cprinfo;
31191341Sstevel
31201341Sstevel CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "overtemp");
31211341Sstevel
31221341Sstevel /* The overtemp data structures are protected by a mutex. */
31231341Sstevel mutex_enter(&sslist_mutex);
31241341Sstevel
31251341Sstevel while (sysctrl_do_overtemp_thread) {
31261341Sstevel
31271341Sstevel for (list = sys_list; list != NULL; list = list->next) {
31281341Sstevel if (list->temp_reg != NULL) {
31291341Sstevel update_temp(list->pdip, &list->tempstat,
31307656SSherry.Moore@Sun.COM *(list->temp_reg));
31311341Sstevel }
31321341Sstevel }
31331341Sstevel
31341341Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo);
31351341Sstevel
31361341Sstevel /* now have this thread sleep for a while */
31371341Sstevel (void) timeout(sysctrl_thread_wakeup, (void *)OVERTEMP_POLL,
31387656SSherry.Moore@Sun.COM overtemp_timeout_hz);
31391341Sstevel
31401341Sstevel cv_wait(&overtemp_cv, &sslist_mutex);
31411341Sstevel
31421341Sstevel CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex);
31431341Sstevel }
31441341Sstevel CALLB_CPR_EXIT(&cprinfo);
31451341Sstevel thread_exit();
31461341Sstevel /* NOTREACHED */
31471341Sstevel }
31481341Sstevel
31491341Sstevel static void
sysctrl_keyswitch_poll(void)31501341Sstevel sysctrl_keyswitch_poll(void)
31511341Sstevel {
31521341Sstevel struct sysctrl_soft_state *list;
31531341Sstevel callb_cpr_t cprinfo;
31541341Sstevel
31551341Sstevel CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "keyswitch");
31561341Sstevel
31571341Sstevel /* The keyswitch data strcutures are protected by a mutex. */
31581341Sstevel mutex_enter(&sslist_mutex);
31591341Sstevel
31601341Sstevel while (sysctrl_do_keyswitch_thread) {
31611341Sstevel
31621341Sstevel for (list = sys_list; list != NULL; list = list->next) {
31631341Sstevel if (list->status1 != NULL)
31641341Sstevel update_key_state(list);
31651341Sstevel }
31661341Sstevel
31671341Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo);
31681341Sstevel
31691341Sstevel /* now have this thread sleep for a while */
31701341Sstevel (void) timeout(sysctrl_thread_wakeup, (void *)KEYSWITCH_POLL,
31717656SSherry.Moore@Sun.COM keyswitch_timeout_hz);
31721341Sstevel
31731341Sstevel cv_wait(&keyswitch_cv, &sslist_mutex);
31741341Sstevel
31751341Sstevel CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex);
31761341Sstevel }
31771341Sstevel CALLB_CPR_EXIT(&cprinfo);
31781341Sstevel thread_exit();
31791341Sstevel /* NOTREACHED */
31801341Sstevel }
31811341Sstevel
31821341Sstevel /*
31831341Sstevel * check the key switch position for state changes
31841341Sstevel */
31851341Sstevel static void
update_key_state(struct sysctrl_soft_state * list)31861341Sstevel update_key_state(struct sysctrl_soft_state *list)
31871341Sstevel {
31881341Sstevel enum keyswitch_state key;
31891341Sstevel
31901341Sstevel /*
31911341Sstevel * snapshot current hardware key position
31921341Sstevel */
31931341Sstevel if (*(list->status1) & SYS_NOT_SECURE)
31941341Sstevel key = KEY_NOT_SECURE;
31951341Sstevel else
31961341Sstevel key = KEY_SECURE;
31971341Sstevel
31981341Sstevel /*
31991341Sstevel * check for state transition
32001341Sstevel */
32011341Sstevel if (key != list->key_shadow) {
32021341Sstevel
32031341Sstevel /*
32041341Sstevel * handle state transition
32051341Sstevel */
32061341Sstevel switch (list->key_shadow) {
32071341Sstevel case KEY_BOOT:
32081341Sstevel cmn_err(CE_CONT, "?sysctrl%d: Key switch is%sin the "
32091341Sstevel "secure position\n", ddi_get_instance(list->dip),
32101341Sstevel (key == KEY_SECURE) ? " " : " not ");
32111341Sstevel list->key_shadow = key;
32121341Sstevel break;
32131341Sstevel case KEY_SECURE:
32141341Sstevel case KEY_NOT_SECURE:
32151341Sstevel cmn_err(CE_NOTE, "sysctrl%d: Key switch has changed"
32161341Sstevel " to the %s position",
32171341Sstevel ddi_get_instance(list->dip),
32181341Sstevel (key == KEY_SECURE) ? "secure" : "not-secure");
32191341Sstevel list->key_shadow = key;
32201341Sstevel break;
32211341Sstevel default:
32221341Sstevel cmn_err(CE_CONT,
32231341Sstevel "?sysctrl%d: Key switch is in an unknown position,"
32241341Sstevel "treated as being in the %s position\n",
32251341Sstevel ddi_get_instance(list->dip),
32261341Sstevel (list->key_shadow == KEY_SECURE) ?
32271341Sstevel "secure" : "not-secure");
32281341Sstevel break;
32291341Sstevel }
32301341Sstevel }
32311341Sstevel }
32321341Sstevel
32331341Sstevel /*
32341341Sstevel * consider key switch position when handling an abort sequence
32351341Sstevel */
32361341Sstevel static void
sysctrl_abort_seq_handler(char * msg)32371341Sstevel sysctrl_abort_seq_handler(char *msg)
32381341Sstevel {
32391341Sstevel struct sysctrl_soft_state *list;
32401341Sstevel uint_t secure = 0;
32411341Sstevel char buf[64], inst[4];
32421341Sstevel
32431341Sstevel
32441341Sstevel /*
32451341Sstevel * if any of the key switch positions are secure,
32461341Sstevel * then disallow entry to the prom/debugger
32471341Sstevel */
32481341Sstevel mutex_enter(&sslist_mutex);
32491341Sstevel buf[0] = (char)0;
32501341Sstevel for (list = sys_list; list != NULL; list = list->next) {
32511341Sstevel if (!(*(list->status1) & SYS_NOT_SECURE)) {
32521341Sstevel if (secure++)
32531341Sstevel (void) strcat(buf, ",");
32541341Sstevel /*
32551341Sstevel * XXX: later, replace instance number with nodeid
32561341Sstevel */
32571341Sstevel (void) sprintf(inst, "%d", ddi_get_instance(list->dip));
32581341Sstevel (void) strcat(buf, inst);
32591341Sstevel }
32601341Sstevel }
32611341Sstevel mutex_exit(&sslist_mutex);
32621341Sstevel
32631341Sstevel if (secure) {
32641341Sstevel cmn_err(CE_CONT,
32657656SSherry.Moore@Sun.COM "!sysctrl(%s): ignoring debug enter sequence\n", buf);
32661341Sstevel } else {
32671341Sstevel cmn_err(CE_CONT, "!sysctrl: allowing debug enter\n");
32681341Sstevel debug_enter(msg);
32691341Sstevel }
32701341Sstevel }
32711341Sstevel
32721341Sstevel #define TABLE_END 0xFF
32731341Sstevel
32741341Sstevel struct uart_cmd {
32751341Sstevel uchar_t reg;
32761341Sstevel uchar_t data;
32771341Sstevel };
32781341Sstevel
32791341Sstevel /*
32801341Sstevel * Time constant defined by this formula:
32811341Sstevel * ((4915200/32)/(baud) -2)
32821341Sstevel */
32831341Sstevel
32841341Sstevel struct uart_cmd uart_table[] = {
32851341Sstevel { 0x09, 0xc0 }, /* Force hardware reset */
32861341Sstevel { 0x04, 0x46 }, /* X16 clock mode, 1 stop bit/char, no parity */
32871341Sstevel { 0x03, 0xc0 }, /* Rx is 8 bits/char */
32881341Sstevel { 0x05, 0xe2 }, /* DTR, Tx is 8 bits/char, RTS */
32891341Sstevel { 0x09, 0x02 }, /* No vector returned on interrupt */
32901341Sstevel { 0x0b, 0x55 }, /* Rx Clock = Tx Clock = BR generator = ~TRxC OUT */
32911341Sstevel { 0x0c, 0x0e }, /* Time Constant = 0x000e for 9600 baud */
32921341Sstevel { 0x0d, 0x00 }, /* High byte of time constant */
32931341Sstevel { 0x0e, 0x02 }, /* BR generator comes from Z-SCC's PCLK input */
32941341Sstevel { 0x03, 0xc1 }, /* Rx is 8 bits/char, Rx is enabled */
32951341Sstevel { 0x05, 0xea }, /* DTR, Tx is 8 bits/char, Tx is enabled, RTS */
32961341Sstevel { 0x0e, 0x03 }, /* BR comes from PCLK, BR generator is enabled */
32971341Sstevel { 0x00, 0x30 }, /* Error reset */
32981341Sstevel { 0x00, 0x30 }, /* Error reset */
32991341Sstevel { 0x00, 0x10 }, /* external status reset */
33001341Sstevel { 0x03, 0xc1 }, /* Rx is 8 bits/char, Rx is enabled */
33011341Sstevel { TABLE_END, 0x0 }
33021341Sstevel };
33031341Sstevel
33041341Sstevel static void
init_remote_console_uart(struct sysctrl_soft_state * softsp)33051341Sstevel init_remote_console_uart(struct sysctrl_soft_state *softsp)
33061341Sstevel {
33071341Sstevel int i = 0;
33081341Sstevel
33091341Sstevel /*
33101341Sstevel * Serial chip expects software to write to the control
33111341Sstevel * register first with the desired register number. Then
33121341Sstevel * write to the control register with the desired data.
33131341Sstevel * So walk thru table writing the register/data pairs to
33141341Sstevel * the serial port chip.
33151341Sstevel */
33161341Sstevel while (uart_table[i].reg != TABLE_END) {
33171341Sstevel *(softsp->rcons_ctl) = uart_table[i].reg;
33181341Sstevel *(softsp->rcons_ctl) = uart_table[i].data;
33191341Sstevel i++;
33201341Sstevel }
33211341Sstevel }
33221341Sstevel
33231341Sstevel /*
33241341Sstevel * return the slot information of the system
33251341Sstevel *
33261341Sstevel * function take a sysctrl_soft_state, so it's ready for sunfire+
33271341Sstevel * change which requires 2 registers to decide the system type.
33281341Sstevel */
33291341Sstevel static void
sysc_slot_info(int nslots,int * start,int * limit,int * incr)33301341Sstevel sysc_slot_info(int nslots, int *start, int *limit, int *incr)
33311341Sstevel {
33321341Sstevel switch (nslots) {
33331341Sstevel case 8:
33341341Sstevel *start = 0;
33351341Sstevel *limit = 8;
33361341Sstevel *incr = 1;
33371341Sstevel break;
33381341Sstevel case 5:
33391341Sstevel *start = 1;
33401341Sstevel *limit = 10;
33411341Sstevel *incr = 2;
33421341Sstevel break;
33431341Sstevel case 4:
33441341Sstevel *start = 1;
33451341Sstevel *limit = 8;
33461341Sstevel *incr = 2;
33471341Sstevel break;
33481341Sstevel case 0:
33491341Sstevel case 16:
33501341Sstevel default:
33511341Sstevel *start = 0;
33521341Sstevel *limit = 16;
33531341Sstevel *incr = 1;
33541341Sstevel break;
33551341Sstevel }
33561341Sstevel }
33571341Sstevel
33581341Sstevel /*
33591341Sstevel * reinitialize the Remote Console on the clock board
33601341Sstevel *
33611341Sstevel * with V5_AUX power outage the Remote Console ends up in
33621341Sstevel * unknown state and has to be reinitilized if it was enabled
33631341Sstevel * initially.
33641341Sstevel */
33651341Sstevel static void
rcons_reinit(struct sysctrl_soft_state * softsp)33661341Sstevel rcons_reinit(struct sysctrl_soft_state *softsp)
33671341Sstevel {
33681341Sstevel uchar_t tmp_reg;
33691341Sstevel
33701341Sstevel if (!(softsp->rcons_ctl))
33711341Sstevel /*
33721341Sstevel * There is no OBP register set for the remote console UART,
33731341Sstevel * so offset from the last register set, the misc register
33741341Sstevel * set, in order to map in the remote console UART.
33751341Sstevel */
33761341Sstevel if (ddi_map_regs(softsp->dip, 1, (caddr_t *)&softsp->rcons_ctl,
33771341Sstevel RMT_CONS_OFFSET, RMT_CONS_LEN)) {
33781341Sstevel cmn_err(CE_WARN, "Unable to reinitialize "
33797656SSherry.Moore@Sun.COM "remote console.");
33801341Sstevel return;
33811341Sstevel }
33821341Sstevel
33831341Sstevel
33841341Sstevel /* Disable the remote console reset control bits. */
33851341Sstevel *(softsp->clk_freq2) &= ~RCONS_UART_EN;
33861341Sstevel
33871341Sstevel /* flush the hardware buffers */
33881341Sstevel tmp_reg = *(softsp->csr);
33891341Sstevel
33901341Sstevel /*
33911341Sstevel * Program the UART to watch ttya console.
33921341Sstevel */
33931341Sstevel init_remote_console_uart(softsp);
33941341Sstevel
33951341Sstevel /* Now enable the remote console reset control bits. */
33961341Sstevel *(softsp->clk_freq2) |= RCONS_UART_EN;
33971341Sstevel
33981341Sstevel /* flush the hardware buffers */
33991341Sstevel tmp_reg = *(softsp->csr);
34001341Sstevel
34011341Sstevel /* print some info for user to watch */
34021341Sstevel cmn_err(CE_NOTE, "Remote console reinitialized");
34031341Sstevel #ifdef lint
34041341Sstevel tmp_reg = tmp_reg;
34051341Sstevel #endif
34061341Sstevel }
3407