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*1366Spetede * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241341Sstevel * Use is subject to license terms. 251341Sstevel */ 261341Sstevel 271341Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 281341Sstevel 291341Sstevel #include <sys/types.h> 301341Sstevel #include <sys/conf.h> 311341Sstevel #include <sys/ddi.h> 321341Sstevel #include <sys/sunddi.h> 331341Sstevel #include <sys/ddi_impldefs.h> 341341Sstevel #include <sys/sunndi.h> 351341Sstevel #include <sys/ndi_impldefs.h> 361341Sstevel #include <sys/obpdefs.h> 371341Sstevel #include <sys/cmn_err.h> 381341Sstevel #include <sys/errno.h> 391341Sstevel #include <sys/kmem.h> 401341Sstevel #include <sys/debug.h> 411341Sstevel #include <sys/sysmacros.h> 421341Sstevel #include <sys/ivintr.h> 431341Sstevel #include <sys/autoconf.h> 441341Sstevel #include <sys/intreg.h> 451341Sstevel #include <sys/proc.h> 461341Sstevel #include <sys/modctl.h> 471341Sstevel #include <sys/callb.h> 481341Sstevel #include <sys/file.h> 491341Sstevel #include <sys/open.h> 501341Sstevel #include <sys/stat.h> 511341Sstevel #include <sys/fhc.h> 521341Sstevel #include <sys/sysctrl.h> 531341Sstevel #include <sys/jtag.h> 541341Sstevel #include <sys/ac.h> 551341Sstevel #include <sys/simmstat.h> 561341Sstevel #include <sys/clock.h> 571341Sstevel #include <sys/promif.h> 581341Sstevel #include <sys/promimpl.h> 591341Sstevel #include <sys/sunndi.h> 601341Sstevel #include <sys/machsystm.h> 611341Sstevel 621341Sstevel /* Useful debugging Stuff */ 631341Sstevel #ifdef DEBUG 641341Sstevel int sysc_debug_info = 1; 651341Sstevel int sysc_debug_print_level = 0; 661341Sstevel #endif 671341Sstevel 681341Sstevel /* 691341Sstevel * Function prototypes 701341Sstevel */ 711341Sstevel static int sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 721341Sstevel void **result); 731341Sstevel 741341Sstevel static int sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 751341Sstevel 761341Sstevel static int sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 771341Sstevel 781341Sstevel static int sysctrl_open(dev_t *, int, int, cred_t *); 791341Sstevel 801341Sstevel static int sysctrl_close(dev_t, int, int, cred_t *); 811341Sstevel 821341Sstevel static int sysctrl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 831341Sstevel 841341Sstevel static uint_t system_high_handler(caddr_t arg); 851341Sstevel 861341Sstevel static uint_t spur_delay(caddr_t arg); 871341Sstevel 881341Sstevel static void spur_retry(void *); 891341Sstevel 901341Sstevel static uint_t spur_reenable(caddr_t arg); 911341Sstevel 921341Sstevel static void spur_long_timeout(void *); 931341Sstevel 941341Sstevel static uint_t spur_clear_count(caddr_t arg); 951341Sstevel 961341Sstevel static uint_t ac_fail_handler(caddr_t arg); 971341Sstevel 981341Sstevel static void ac_fail_retry(void *); 991341Sstevel 1001341Sstevel static uint_t ac_fail_reenable(caddr_t arg); 1011341Sstevel 1021341Sstevel static uint_t ps_fail_int_handler(caddr_t arg); 1031341Sstevel 1041341Sstevel static uint_t ps_fail_poll_handler(caddr_t arg); 1051341Sstevel 1061341Sstevel static uint_t ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint); 1071341Sstevel 1081341Sstevel enum power_state compute_power_state(struct sysctrl_soft_state *softsp, 1091341Sstevel int plus_load); 1101341Sstevel 1111341Sstevel static void ps_log_state_change(struct sysctrl_soft_state *softsp, 1121341Sstevel int index, int present); 1131341Sstevel 1141341Sstevel static void ps_log_pres_change(struct sysctrl_soft_state *softsp, 1151341Sstevel int index, int present); 1161341Sstevel 1171341Sstevel static void ps_fail_retry(void *); 1181341Sstevel 1191341Sstevel static uint_t pps_fanfail_handler(caddr_t arg); 1201341Sstevel 1211341Sstevel static void pps_fanfail_retry(void *); 1221341Sstevel 1231341Sstevel static uint_t pps_fanfail_reenable(caddr_t arg); 1241341Sstevel 1251341Sstevel static void pps_fan_poll(void *); 1261341Sstevel 1271341Sstevel static void pps_fan_state_change(struct sysctrl_soft_state *softsp, 1281341Sstevel int index, int fan_ok); 1291341Sstevel 1301341Sstevel static uint_t bd_insert_handler(caddr_t arg); 1311341Sstevel 1321341Sstevel static void bd_insert_timeout(void *); 1331341Sstevel 1341341Sstevel static void bd_remove_timeout(void *); 1351341Sstevel 1361341Sstevel static uint_t bd_insert_normal(caddr_t arg); 1371341Sstevel 1381341Sstevel static void sysctrl_add_kstats(struct sysctrl_soft_state *softsp); 1391341Sstevel 1401341Sstevel static int sysctrl_kstat_update(kstat_t *ksp, int rw); 1411341Sstevel 1421341Sstevel static int psstat_kstat_update(kstat_t *, int); 1431341Sstevel 1441341Sstevel static void init_remote_console_uart(struct sysctrl_soft_state *); 1451341Sstevel 1461341Sstevel static void blink_led_timeout(void *); 1471341Sstevel 1481341Sstevel static uint_t blink_led_handler(caddr_t arg); 1491341Sstevel 1501341Sstevel static void sysctrl_thread_wakeup(void *type); 1511341Sstevel 1521341Sstevel static void sysctrl_overtemp_poll(void); 1531341Sstevel 1541341Sstevel static void sysctrl_keyswitch_poll(void); 1551341Sstevel 1561341Sstevel static void update_key_state(struct sysctrl_soft_state *); 1571341Sstevel 1581341Sstevel static void sysctrl_abort_seq_handler(char *msg); 1591341Sstevel 1601341Sstevel static void nvram_update_powerfail(struct sysctrl_soft_state *softsp); 1611341Sstevel 1621341Sstevel static void toggle_board_green_leds(int); 1631341Sstevel 1641341Sstevel void bd_remove_poll(struct sysctrl_soft_state *); 1651341Sstevel 1661341Sstevel static void sysc_slot_info(int nslots, int *start, int *limit, int *incr); 1671341Sstevel 1681341Sstevel extern void sysc_board_connect_supported_init(void); 1691341Sstevel 1701341Sstevel static void rcons_reinit(struct sysctrl_soft_state *softsp); 1711341Sstevel 1721341Sstevel /* 1731341Sstevel * Configuration data structures 1741341Sstevel */ 1751341Sstevel static struct cb_ops sysctrl_cb_ops = { 1761341Sstevel sysctrl_open, /* open */ 1771341Sstevel sysctrl_close, /* close */ 1781341Sstevel nulldev, /* strategy */ 1791341Sstevel nulldev, /* print */ 1801341Sstevel nulldev, /* dump */ 1811341Sstevel nulldev, /* read */ 1821341Sstevel nulldev, /* write */ 1831341Sstevel sysctrl_ioctl, /* ioctl */ 1841341Sstevel nodev, /* devmap */ 1851341Sstevel nodev, /* mmap */ 1861341Sstevel nodev, /* segmap */ 1871341Sstevel nochpoll, /* poll */ 1881341Sstevel ddi_prop_op, /* cb_prop_op */ 1891341Sstevel 0, /* streamtab */ 1901341Sstevel D_MP|D_NEW, /* Driver compatibility flag */ 1911341Sstevel CB_REV, /* rev */ 1921341Sstevel nodev, /* cb_aread */ 1931341Sstevel nodev /* cb_awrite */ 1941341Sstevel }; 1951341Sstevel 1961341Sstevel static struct dev_ops sysctrl_ops = { 1971341Sstevel DEVO_REV, /* devo_rev */ 1981341Sstevel 0, /* refcnt */ 1991341Sstevel sysctrl_info, /* getinfo */ 2001341Sstevel nulldev, /* identify */ 2011341Sstevel nulldev, /* probe */ 2021341Sstevel sysctrl_attach, /* attach */ 2031341Sstevel sysctrl_detach, /* detach */ 2041341Sstevel nulldev, /* reset */ 2051341Sstevel &sysctrl_cb_ops, /* cb_ops */ 2061341Sstevel (struct bus_ops *)0, /* bus_ops */ 2071341Sstevel nulldev /* power */ 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 */ 3191341Sstevel "Clock Board %I%", /* 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 330*1366Spetede char _depends_on[] = "drv/fhc"; 3311341Sstevel #endif /* lint */ 3321341Sstevel 3331341Sstevel /* 3341341Sstevel * These are the module initialization routines. 3351341Sstevel */ 3361341Sstevel 3371341Sstevel int 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 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 3731341Sstevel _info(struct modinfo *modinfop) 3741341Sstevel { 3751341Sstevel return (mod_info(&modlinkage, modinfop)); 3761341Sstevel } 3771341Sstevel 3781341Sstevel /* ARGSUSED */ 3791341Sstevel static int 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 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", 4361341Sstevel devi, 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 " 4641341Sstevel "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" 4711341Sstevel "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 + 4891341Sstevel SYS_OFF_CLK_FREQ2); 4901341Sstevel 4911341Sstevel softsp->status1 = (uchar_t *)((caddr_t)softsp->csr + 4921341Sstevel SYS_OFF_STAT1); 4931341Sstevel 4941341Sstevel softsp->status2 = (uchar_t *)((caddr_t)softsp->csr + 4951341Sstevel SYS_OFF_STAT2); 4961341Sstevel 4971341Sstevel softsp->ps_stat = (uchar_t *)((caddr_t)softsp->csr + 4981341Sstevel SYS_OFF_PSSTAT); 4991341Sstevel 5001341Sstevel softsp->ps_pres = (uchar_t *)((caddr_t)softsp->csr + 5011341Sstevel SYS_OFF_PSPRES); 5021341Sstevel 5031341Sstevel softsp->pppsr = (uchar_t *)((caddr_t)softsp->csr + 5041341Sstevel SYS_OFF_PPPSR); 5051341Sstevel 5061341Sstevel softsp->temp_reg = (uchar_t *)((caddr_t)softsp->csr + 5071341Sstevel 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 | 5701341Sstevel 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, 6001341Sstevel (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, 6321341Sstevel (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, 6941341Sstevel ("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, 7181341Sstevel (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 = 7221341Sstevel 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 & 7361341Sstevel (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN | 7371341Sstevel 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, 8171341Sstevel ("sysctrl: Creating devices start:%d, limit:%d, incr:%d\n", 8181341Sstevel 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\" " 8301341Sstevel "ddi_create_minor_node failed", 8311341Sstevel 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 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 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 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 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 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 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 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, 11711341Sstevel 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 = 11791341Sstevel (char *)(uintptr_t)sysc_cmd32.outputstr; 11801341Sstevel } else 11811341Sstevel #endif /* _MULTI_DATAMODEL */ 11821341Sstevel if (ddi_copyin((void *)arg, &(pkt->cmd_cfga), 11831341Sstevel 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 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), 11991341Sstevel (void *)&(((sysc_cfga_cmd32_t *)arg)->errtype), 12001341Sstevel sizeof (sysc_err_t), flag) != 0) { 12011341Sstevel ret = FALSE; 12021341Sstevel } 12031341Sstevel } else 12041341Sstevel #endif 12051341Sstevel if (ddi_copyout(&(pkt->cmd_cfga.errtype), 12061341Sstevel (void *)&(((sysc_cfga_cmd_t *)arg)->errtype), 12071341Sstevel sizeof (sysc_err_t), flag) != 0) { 12081341Sstevel ret = FALSE; 12091341Sstevel } 12101341Sstevel 12111341Sstevel if ((ret != FALSE) && ((pkt->cmd_cfga.outputstr != NULL) && 12121341Sstevel (ddi_copyout(pkt->errbuf, pkt->cmd_cfga.outputstr, 12131341Sstevel 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 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, 12411341Sstevel "sysctrl_ioctl(%d): NULL softstate ptr!\n", 12421341Sstevel (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 12931341Sstevel ? -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, 13231341Sstevel &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, 13951341Sstevel sizeof (sysc_cfga_stat_t) * fhc_max_boards(), 13961341Sstevel 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 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 | 14761341Sstevel 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 | 15361341Sstevel 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 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, 15851341Sstevel 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." 15941341Sstevel " possible sources [%s].", 15951341Sstevel 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 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 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 & 16561341Sstevel (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN | 16571341Sstevel 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 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 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 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 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", 17511341Sstevel 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 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 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 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 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) || 18821341Sstevel ((IS4SLOT(softsp->nslots) || 18831341Sstevel IS5SLOT(softsp->nslots)) && 18841341Sstevel !(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) || 18911341Sstevel ((IS4SLOT(softsp->nslots) || 18921341Sstevel IS5SLOT(softsp->nslots)) && 18931341Sstevel !(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) || 19341341Sstevel IS5SLOT(softsp->nslots)) && 19351341Sstevel !(status1 & SYS_NOT_P_FAN_PRES); 19361341Sstevel temp_psok = softsp->pps_fan_saved & 19371341Sstevel 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 ? 19581341Sstevel PRES_IN : PRES_OUT; 19591341Sstevel pstatp->dcshadow = temp_pres ? 19601341Sstevel 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, 19671341Sstevel 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 ? 19901341Sstevel PS_P_FAN_FROM_UNKNOWN_TICKS : 19911341Sstevel PS_FROM_UNKNOWN_TICKS; 19921341Sstevel break; 19931341Sstevel 19941341Sstevel case PS_OK: 19951341Sstevel pstatp->dcctr = is_precharge ? 19961341Sstevel PS_PCH_FROM_OK_TICKS : 19971341Sstevel 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, 20181341Sstevel 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, 20491341Sstevel 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, 20821341Sstevel "Insufficient power available to system"); 20831341Sstevel if (!disable_insufficient_power_reboot) { 20841341Sstevel cmn_err(CE_WARN, "System reboot in %d seconds", 20851341Sstevel 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, 20991341Sstevel 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, 21081341Sstevel 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 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 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) { 22571341Sstevel clear_fault(index, FT_CORE_PS, FT_SYSTEM); 22581341Sstevel 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)) { 22651341Sstevel cmn_err(CE_NOTE, "%s 1 %s", ft_str_table[FT_PPS], trans); 22661341Sstevel if (!present) { 22671341Sstevel clear_fault(1, FT_PPS, FT_SYSTEM); 22681341Sstevel } 22691341Sstevel } else { 22701341Sstevel cmn_err(CE_NOTE, "%s %d %s", ft_str_table[FT_CORE_PS], 22711341Sstevel index, trans); 22721341Sstevel if (!present) { 22731341Sstevel clear_fault(7, FT_CORE_PS, FT_SYSTEM); 22741341Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE); 22751341Sstevel } 22761341Sstevel } 22771341Sstevel break; 22781341Sstevel 22791341Sstevel /* the peripheral power supply 0 */ 22801341Sstevel case SYS_PPS0_INDEX: 22811341Sstevel cmn_err(CE_NOTE, "%s 0 %s", ft_str_table[FT_PPS], trans); 22821341Sstevel if (!present) { 22831341Sstevel clear_fault(0, FT_PPS, FT_SYSTEM); 22841341Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE); 22851341Sstevel } 22861341Sstevel break; 22871341Sstevel 22881341Sstevel /* the peripheral rack fan assy */ 22891341Sstevel case SYS_P_FAN_INDEX: 22901341Sstevel cmn_err(CE_NOTE, "%s %s", ft_str_table[FT_PPS_FAN], trans); 22911341Sstevel if (!present) { 22921341Sstevel clear_fault(0, FT_PPS_FAN, FT_SYSTEM); 22931341Sstevel } 22941341Sstevel break; 22951341Sstevel 22961341Sstevel /* we don't mention a change of presence state for any other power */ 22971341Sstevel } 22981341Sstevel } 22991341Sstevel 23001341Sstevel /* 23011341Sstevel * log the change of power supply status 23021341Sstevel */ 23031341Sstevel static void 23041341Sstevel ps_log_state_change(struct sysctrl_soft_state *softsp, int index, int ps_ok) 23051341Sstevel { 23061341Sstevel int level = ps_ok ? CE_NOTE : CE_WARN; 23071341Sstevel char *s = ps_ok ? "OK" : "Failing"; 23081341Sstevel 23091341Sstevel switch (index) { 23101341Sstevel /* the core power supplies (except 7) */ 23111341Sstevel case 0: case 1: case 2: case 3: 23121341Sstevel case 4: case 5: case 6: 23131341Sstevel cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS], index, s); 23141341Sstevel if (ps_ok) { 23151341Sstevel clear_fault(index, FT_CORE_PS, FT_SYSTEM); 23161341Sstevel } else { 23171341Sstevel reg_fault(index, FT_CORE_PS, FT_SYSTEM); 23181341Sstevel } 23191341Sstevel break; 23201341Sstevel 23211341Sstevel /* power supply 7 / pps 1 */ 23221341Sstevel case 7: 23231341Sstevel if (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)) { 23241341Sstevel cmn_err(level, "%s 1 %s", ft_str_table[FT_PPS], s); 23251341Sstevel if (ps_ok) { 23261341Sstevel clear_fault(1, FT_PPS, FT_SYSTEM); 23271341Sstevel } else { 23281341Sstevel reg_fault(1, FT_PPS, FT_SYSTEM); 23291341Sstevel } 23301341Sstevel } else { 23311341Sstevel cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS], 23321341Sstevel index, s); 23331341Sstevel if (ps_ok) { 23341341Sstevel clear_fault(index, FT_CORE_PS, FT_SYSTEM); 23351341Sstevel } else { 23361341Sstevel reg_fault(index, FT_CORE_PS, FT_SYSTEM); 23371341Sstevel } 23381341Sstevel } 23391341Sstevel break; 23401341Sstevel 23411341Sstevel /* the peripheral power supply */ 23421341Sstevel case SYS_PPS0_INDEX: 23431341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_PPS], s); 23441341Sstevel if (ps_ok) { 23451341Sstevel clear_fault(0, FT_PPS, FT_SYSTEM); 23461341Sstevel } else { 23471341Sstevel reg_fault(0, FT_PPS, FT_SYSTEM); 23481341Sstevel } 23491341Sstevel break; 23501341Sstevel 23511341Sstevel /* shared 3.3v clock power */ 23521341Sstevel case SYS_CLK_33_INDEX: 23531341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_CLK_33], s); 23541341Sstevel if (ps_ok) { 23551341Sstevel clear_fault(0, FT_CLK_33, FT_SYSTEM); 23561341Sstevel } else { 23571341Sstevel reg_fault(0, FT_CLK_33, FT_SYSTEM); 23581341Sstevel } 23591341Sstevel break; 23601341Sstevel 23611341Sstevel /* shared 5.0v clock power */ 23621341Sstevel case SYS_CLK_50_INDEX: 23631341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_CLK_50], s); 23641341Sstevel if (ps_ok) { 23651341Sstevel clear_fault(0, FT_CLK_50, FT_SYSTEM); 23661341Sstevel } else { 23671341Sstevel reg_fault(0, FT_CLK_50, FT_SYSTEM); 23681341Sstevel } 23691341Sstevel break; 23701341Sstevel 23711341Sstevel /* peripheral 5v */ 23721341Sstevel case SYS_V5_P_INDEX: 23731341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_P], s); 23741341Sstevel if (ps_ok) { 23751341Sstevel clear_fault(0, FT_V5_P, FT_SYSTEM); 23761341Sstevel } else { 23771341Sstevel reg_fault(0, FT_V5_P, FT_SYSTEM); 23781341Sstevel } 23791341Sstevel break; 23801341Sstevel 23811341Sstevel /* peripheral 12v */ 23821341Sstevel case SYS_V12_P_INDEX: 23831341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V12_P], s); 23841341Sstevel if (ps_ok) { 23851341Sstevel clear_fault(0, FT_V12_P, FT_SYSTEM); 23861341Sstevel } else { 23871341Sstevel reg_fault(0, FT_V12_P, FT_SYSTEM); 23881341Sstevel } 23891341Sstevel break; 23901341Sstevel 23911341Sstevel /* aux 5v */ 23921341Sstevel case SYS_V5_AUX_INDEX: 23931341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_AUX], s); 23941341Sstevel if (ps_ok) { 23951341Sstevel clear_fault(0, FT_V5_AUX, FT_SYSTEM); 23961341Sstevel } else { 23971341Sstevel reg_fault(0, FT_V5_AUX, FT_SYSTEM); 23981341Sstevel } 23991341Sstevel break; 24001341Sstevel 24011341Sstevel /* peripheral 5v precharge */ 24021341Sstevel case SYS_V5_P_PCH_INDEX: 24031341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_P_PCH], s); 24041341Sstevel if (ps_ok) { 24051341Sstevel clear_fault(0, FT_V5_P_PCH, FT_SYSTEM); 24061341Sstevel } else { 24071341Sstevel reg_fault(0, FT_V5_P_PCH, FT_SYSTEM); 24081341Sstevel } 24091341Sstevel break; 24101341Sstevel 24111341Sstevel /* peripheral 12v precharge */ 24121341Sstevel case SYS_V12_P_PCH_INDEX: 24131341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V12_P_PCH], s); 24141341Sstevel if (ps_ok) { 24151341Sstevel clear_fault(0, FT_V12_P_PCH, FT_SYSTEM); 24161341Sstevel } else { 24171341Sstevel reg_fault(0, FT_V12_P_PCH, FT_SYSTEM); 24181341Sstevel } 24191341Sstevel break; 24201341Sstevel 24211341Sstevel /* 3.3v precharge */ 24221341Sstevel case SYS_V3_PCH_INDEX: 24231341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V3_PCH], s); 24241341Sstevel if (ps_ok) { 24251341Sstevel clear_fault(0, FT_V3_PCH, FT_SYSTEM); 24261341Sstevel } else { 24271341Sstevel reg_fault(0, FT_V3_PCH, FT_SYSTEM); 24281341Sstevel } 24291341Sstevel break; 24301341Sstevel 24311341Sstevel /* 5v precharge */ 24321341Sstevel case SYS_V5_PCH_INDEX: 24331341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_PCH], s); 24341341Sstevel if (ps_ok) { 24351341Sstevel clear_fault(0, FT_V5_PCH, FT_SYSTEM); 24361341Sstevel } else { 24371341Sstevel reg_fault(0, FT_V5_PCH, FT_SYSTEM); 24381341Sstevel } 24391341Sstevel break; 24401341Sstevel 24411341Sstevel /* peripheral power supply fans */ 24421341Sstevel case SYS_P_FAN_INDEX: 24431341Sstevel cmn_err(level, "%s %s", ft_str_table[FT_PPS_FAN], s); 24441341Sstevel if (ps_ok) { 24451341Sstevel clear_fault(0, FT_PPS_FAN, FT_SYSTEM); 24461341Sstevel } else { 24471341Sstevel reg_fault(0, FT_PPS_FAN, FT_SYSTEM); 24481341Sstevel } 24491341Sstevel break; 24501341Sstevel } 24511341Sstevel } 24521341Sstevel 24531341Sstevel /* 24541341Sstevel * The timeout from ps_fail_handler() that simply re-triggers a check 24551341Sstevel * of the ps condition. 24561341Sstevel */ 24571341Sstevel static void 24581341Sstevel ps_fail_retry(void *arg) 24591341Sstevel { 24601341Sstevel struct sysctrl_soft_state *softsp = arg; 24611341Sstevel 24621341Sstevel ASSERT(softsp); 24631341Sstevel 24641341Sstevel ddi_trigger_softintr(softsp->ps_fail_poll_id); 24651341Sstevel } 24661341Sstevel 24671341Sstevel /* 24681341Sstevel * pps_fanfail_handler 24691341Sstevel * 24701341Sstevel * This routine is called from the high level handler. 24711341Sstevel */ 24721341Sstevel static uint_t 24731341Sstevel pps_fanfail_handler(caddr_t arg) 24741341Sstevel { 24751341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 24761341Sstevel 24771341Sstevel ASSERT(softsp); 24781341Sstevel 24791341Sstevel /* always check again in a bit by re-enabling the fan interrupt */ 24801341Sstevel (void) timeout(pps_fanfail_retry, softsp, pps_fan_timeout_hz); 24811341Sstevel 24821341Sstevel return (DDI_INTR_CLAIMED); 24831341Sstevel } 24841341Sstevel 24851341Sstevel /* 24861341Sstevel * After a bit of waiting, we simply re-enable the interrupt to 24871341Sstevel * see if we get another one. The softintr triggered routine does 24881341Sstevel * the dirty work for us since it runs in the interrupt context. 24891341Sstevel */ 24901341Sstevel static void 24911341Sstevel pps_fanfail_retry(void *arg) 24921341Sstevel { 24931341Sstevel struct sysctrl_soft_state *softsp = arg; 24941341Sstevel 24951341Sstevel ASSERT(softsp); 24961341Sstevel 24971341Sstevel ddi_trigger_softintr(softsp->pps_fan_high_id); 24981341Sstevel } 24991341Sstevel 25001341Sstevel /* 25011341Sstevel * The other half of the retry handler run from the interrupt context 25021341Sstevel */ 25031341Sstevel static uint_t 25041341Sstevel pps_fanfail_reenable(caddr_t arg) 25051341Sstevel { 25061341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 25071341Sstevel uchar_t tmp_reg; 25081341Sstevel 25091341Sstevel ASSERT(softsp); 25101341Sstevel 25111341Sstevel mutex_enter(&softsp->csr_mutex); 25121341Sstevel 25131341Sstevel /* 25141341Sstevel * re-initialize the bit field for all pps fans to assumed good. 25151341Sstevel * If the fans are still bad, we're going to get an immediate system 25161341Sstevel * interrupt which will put the correct state back anyway. 25171341Sstevel * 25181341Sstevel * NOTE: the polling routines that use this state understand the 25191341Sstevel * pulse resulting from above... 25201341Sstevel */ 25211341Sstevel softsp->pps_fan_saved = SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK; 25221341Sstevel 25231341Sstevel *(softsp->csr) |= SYS_PPS_FAN_FAIL_EN; 25241341Sstevel tmp_reg = *(softsp->csr); 25251341Sstevel #ifdef lint 25261341Sstevel tmp_reg = tmp_reg; 25271341Sstevel #endif 25281341Sstevel mutex_exit(&softsp->csr_mutex); 25291341Sstevel 25301341Sstevel return (DDI_INTR_CLAIMED); 25311341Sstevel } 25321341Sstevel 25331341Sstevel /* 25341341Sstevel * 25351341Sstevel * Poll the hardware shadow state to determine the pps fan status. 25361341Sstevel * The shadow state is maintained by the system_high handler and its 25371341Sstevel * associated pps_* functions (above). 25381341Sstevel * 25391341Sstevel * There is a short time interval where the shadow state is pulsed to 25401341Sstevel * the OK state even when the fans are bad. However, this polling 25411341Sstevel * routine has some built in hysteresis to filter out those _normal_ 25421341Sstevel * events. 25431341Sstevel */ 25441341Sstevel static void 25451341Sstevel pps_fan_poll(void *arg) 25461341Sstevel { 25471341Sstevel struct sysctrl_soft_state *softsp = arg; 25481341Sstevel int i; 25491341Sstevel 25501341Sstevel ASSERT(softsp); 25511341Sstevel 25521341Sstevel for (i = 0; i < SYS_PPS_FAN_COUNT; i++) { 25531341Sstevel int fanfail = FALSE; 25541341Sstevel 25551341Sstevel /* determine fan status */ 25561341Sstevel switch (i) { 25571341Sstevel case RACK: 25581341Sstevel fanfail = softsp->pps_fan_saved & SYS_RACK_FANFAIL; 25591341Sstevel break; 25601341Sstevel 25611341Sstevel case AC: 25621341Sstevel /* 25631341Sstevel * Don't bother polling the AC fan on 4 and 5 slot 25641341Sstevel * systems. 25651341Sstevel * Rather, it is handled by the power supply loop. 25661341Sstevel */ 25671341Sstevel fanfail = !(IS4SLOT(softsp->nslots) || 25681341Sstevel IS5SLOT(softsp->nslots)) && 25691341Sstevel !(softsp->pps_fan_saved & SYS_AC_FAN_OK); 25701341Sstevel break; 25711341Sstevel 25721341Sstevel case KEYSW: 25731341Sstevel /* 25741341Sstevel * This signal is not usable if aux5v is missing 25751341Sstevel * so we will synthesize a failed fan when aux5v 25761341Sstevel * fails or when pps0 is out. 25771341Sstevel * The 4 and 5 slot systems behave the same. 25781341Sstevel */ 25791341Sstevel fanfail = (!(IS4SLOT(softsp->nslots) || 25801341Sstevel IS5SLOT(softsp->nslots)) && 25811341Sstevel (softsp->ps_stats[SYS_V5_AUX_INDEX].dcshadow != 25821341Sstevel PS_OK)) || 25831341Sstevel !(softsp->pps_fan_saved & SYS_KEYSW_FAN_OK); 25841341Sstevel break; 25851341Sstevel 25861341Sstevel } 25871341Sstevel 25881341Sstevel /* is the fan bad? */ 25891341Sstevel if (fanfail) { 25901341Sstevel 25911341Sstevel /* is this condition different than we know? */ 25921341Sstevel if (softsp->pps_fan_state_count[i] == 0) { 25931341Sstevel 25941341Sstevel /* log the change to failed */ 25951341Sstevel pps_fan_state_change(softsp, i, FALSE); 25961341Sstevel } 25971341Sstevel 25981341Sstevel /* always restart the fan OK counter */ 25991341Sstevel softsp->pps_fan_state_count[i] = PPS_FROM_FAIL_TICKS; 26001341Sstevel } else { 26011341Sstevel 26021341Sstevel /* do we currently know the fan is bad? */ 26031341Sstevel if (softsp->pps_fan_state_count[i]) { 26041341Sstevel 26051341Sstevel /* yes, but has it been stable? */ 26061341Sstevel if (--softsp->pps_fan_state_count[i] == 0) { 26071341Sstevel 26081341Sstevel /* log the change to OK */ 26091341Sstevel pps_fan_state_change(softsp, i, TRUE); 26101341Sstevel } 26111341Sstevel } 26121341Sstevel } 26131341Sstevel } 26141341Sstevel 26151341Sstevel /* always check again in a bit by re-enabling the fan interrupt */ 26161341Sstevel (void) timeout(pps_fan_poll, softsp, pps_fan_timeout_hz); 26171341Sstevel } 26181341Sstevel 26191341Sstevel /* 26201341Sstevel * pps_fan_state_change() 26211341Sstevel * 26221341Sstevel * Log the changed fan condition and update the external status. 26231341Sstevel */ 26241341Sstevel static void 26251341Sstevel pps_fan_state_change(struct sysctrl_soft_state *softsp, int index, int fan_ok) 26261341Sstevel { 26271341Sstevel char *fan_type; 26281341Sstevel char *state = fan_ok ? "fans OK" : "fan failure detected"; 26291341Sstevel 26301341Sstevel switch (index) { 26311341Sstevel case RACK: 26321341Sstevel /* 4 and 5 slot systems behave the same */ 26331341Sstevel fan_type = (IS4SLOT(softsp->nslots) || 26341341Sstevel IS5SLOT(softsp->nslots)) ? 26351341Sstevel "Disk Drive" : "Rack Exhaust"; 26361341Sstevel if (fan_ok) { 26371341Sstevel softsp->pps_fan_external_state &= ~SYS_RACK_FANFAIL; 26381341Sstevel clear_fault(0, (IS4SLOT(softsp->nslots) || 26391341Sstevel IS5SLOT(softsp->nslots)) ? FT_DSK_FAN : 26401341Sstevel FT_RACK_EXH, FT_SYSTEM); 26411341Sstevel } else { 26421341Sstevel softsp->pps_fan_external_state |= SYS_RACK_FANFAIL; 26431341Sstevel reg_fault(0, (IS4SLOT(softsp->nslots) || 26441341Sstevel IS5SLOT(softsp->nslots)) ? FT_DSK_FAN : 26451341Sstevel FT_RACK_EXH, FT_SYSTEM); 26461341Sstevel } 26471341Sstevel break; 26481341Sstevel 26491341Sstevel case AC: 26501341Sstevel fan_type = "AC Box"; 26511341Sstevel if (fan_ok) { 26521341Sstevel softsp->pps_fan_external_state |= SYS_AC_FAN_OK; 26531341Sstevel clear_fault(0, FT_AC_FAN, FT_SYSTEM); 26541341Sstevel } else { 26551341Sstevel softsp->pps_fan_external_state &= ~SYS_AC_FAN_OK; 26561341Sstevel reg_fault(0, FT_AC_FAN, FT_SYSTEM); 26571341Sstevel } 26581341Sstevel break; 26591341Sstevel 26601341Sstevel case KEYSW: 26611341Sstevel fan_type = "Keyswitch"; 26621341Sstevel if (fan_ok) { 26631341Sstevel softsp->pps_fan_external_state |= SYS_KEYSW_FAN_OK; 26641341Sstevel clear_fault(0, FT_KEYSW_FAN, FT_SYSTEM); 26651341Sstevel } else { 26661341Sstevel softsp->pps_fan_external_state &= ~SYS_KEYSW_FAN_OK; 26671341Sstevel reg_fault(0, FT_KEYSW_FAN, FT_SYSTEM); 26681341Sstevel } 26691341Sstevel break; 26701341Sstevel default: 26711341Sstevel fan_type = "[invalid fan id]"; 26721341Sstevel break; 26731341Sstevel } 26741341Sstevel 26751341Sstevel /* now log the state change */ 26761341Sstevel cmn_err(fan_ok ? CE_NOTE : CE_WARN, "%s %s", fan_type, state); 26771341Sstevel } 26781341Sstevel 26791341Sstevel static uint_t 26801341Sstevel bd_insert_handler(caddr_t arg) 26811341Sstevel { 26821341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 26831341Sstevel 26841341Sstevel ASSERT(softsp); 26851341Sstevel 26861341Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, ("bd_insert_handler()")); 26871341Sstevel 26881341Sstevel (void) timeout(bd_insert_timeout, softsp, bd_insert_delay_hz); 26891341Sstevel 26901341Sstevel return (DDI_INTR_CLAIMED); 26911341Sstevel } 26921341Sstevel 26931341Sstevel void 26941341Sstevel bd_remove_poll(struct sysctrl_soft_state *softsp) 26951341Sstevel { 26961341Sstevel ASSERT(fhc_bdlist_locked()); 26971341Sstevel 26981341Sstevel if (!bd_remove_to_id) { 26991341Sstevel bd_remove_to_id = timeout(bd_remove_timeout, softsp, 27001341Sstevel bd_remove_timeout_hz); 27011341Sstevel } else { 27021341Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, 27031341Sstevel ("bd_remove_poll ignoring start request")); 27041341Sstevel } 27051341Sstevel } 27061341Sstevel 27071341Sstevel /* 27081341Sstevel * bd_insert_timeout() 27091341Sstevel * 27101341Sstevel * This routine handles the board insert interrupt. It is called from a 27111341Sstevel * timeout so that it does not run at interrupt level. The main job 27121341Sstevel * of this routine is to find hotplugged boards and de-assert the 27131341Sstevel * board insert interrupt coming from the board. For hotplug phase I, 27141341Sstevel * the routine also powers down the board. 27151341Sstevel * JTAG scan is used to find boards which have been inserted. 27161341Sstevel * All other control of the boards is also done by JTAG scan. 27171341Sstevel */ 27181341Sstevel static void 27191341Sstevel bd_insert_timeout(void *arg) 27201341Sstevel { 27211341Sstevel struct sysctrl_soft_state *softsp = arg; 27221341Sstevel int found; 27231341Sstevel 27241341Sstevel ASSERT(softsp); 27251341Sstevel 27261341Sstevel if (sysctrl_hotplug_disabled) { 27271341Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_HP_DISABLED); 27281341Sstevel } else { 27291341Sstevel /* 27301341Sstevel * Lock the board list mutex. Keep it locked until all work 27311341Sstevel * is done. 27321341Sstevel */ 27331341Sstevel (void) fhc_bdlist_lock(-1); 27341341Sstevel 27351341Sstevel found = fhc_bd_insert_scan(); 27361341Sstevel 27371341Sstevel if (found) { 27381341Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, 27391341Sstevel ("bd_insert_timeout starting bd_remove_poll()")); 27401341Sstevel bd_remove_poll(softsp); 27411341Sstevel } 27421341Sstevel 27431341Sstevel fhc_bdlist_unlock(); 27441341Sstevel } 27451341Sstevel 27461341Sstevel /* 27471341Sstevel * Enable interrupts. 27481341Sstevel */ 27491341Sstevel ddi_trigger_softintr(softsp->sbrd_gone_id); 27501341Sstevel } 27511341Sstevel 27521341Sstevel static void 27531341Sstevel bd_remove_timeout(void *arg) 27541341Sstevel { 27551341Sstevel struct sysctrl_soft_state *softsp = arg; 27561341Sstevel int keep_polling; 27571341Sstevel 27581341Sstevel ASSERT(softsp); 27591341Sstevel 27601341Sstevel /* 27611341Sstevel * Lock the board list mutex. Keep it locked until all work 27621341Sstevel * is done. 27631341Sstevel */ 27641341Sstevel (void) fhc_bdlist_lock(-1); 27651341Sstevel 27661341Sstevel bd_remove_to_id = 0; /* delete our timeout ID */ 27671341Sstevel 27681341Sstevel keep_polling = fhc_bd_remove_scan(); 27691341Sstevel 27701341Sstevel if (keep_polling) { 27711341Sstevel bd_remove_poll(softsp); 27721341Sstevel } else { 27731341Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, ("exiting bd_remove_poll.")); 27741341Sstevel } 27751341Sstevel 27761341Sstevel fhc_bdlist_unlock(); 27771341Sstevel } 27781341Sstevel 27791341Sstevel static uint_t 27801341Sstevel bd_insert_normal(caddr_t arg) 27811341Sstevel { 27821341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 27831341Sstevel uchar_t tmp_reg; 27841341Sstevel 27851341Sstevel ASSERT(softsp); 27861341Sstevel 27871341Sstevel /* has the condition been removed? */ 27881341Sstevel /* XXX add deglitch state machine here */ 27891341Sstevel if (!(*(softsp->status1) & SYS_NOT_BRD_PRES)) { 27901341Sstevel /* check again in a few */ 27911341Sstevel (void) timeout(bd_insert_timeout, softsp, bd_insert_retry_hz); 27921341Sstevel } else { 27931341Sstevel /* Turn on the enable bit for this interrupt */ 27941341Sstevel mutex_enter(&softsp->csr_mutex); 27951341Sstevel *(softsp->csr) |= SYS_SBRD_PRES_EN; 27961341Sstevel /* flush the hardware store buffer */ 27971341Sstevel tmp_reg = *(softsp->csr); 27981341Sstevel #ifdef lint 27991341Sstevel tmp_reg = tmp_reg; 28001341Sstevel #endif 28011341Sstevel mutex_exit(&softsp->csr_mutex); 28021341Sstevel } 28031341Sstevel 28041341Sstevel return (DDI_INTR_CLAIMED); 28051341Sstevel } 28061341Sstevel 28071341Sstevel /* 28081341Sstevel * blink LED handler. 28091341Sstevel * 28101341Sstevel * The actual bit manipulation needs to occur at interrupt level 28111341Sstevel * because we need access to the CSR with its CSR mutex 28121341Sstevel */ 28131341Sstevel static uint_t 28141341Sstevel blink_led_handler(caddr_t arg) 28151341Sstevel { 28161341Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 28171341Sstevel uchar_t tmp_reg; 28181341Sstevel 28191341Sstevel ASSERT(softsp); 28201341Sstevel 28211341Sstevel mutex_enter(&softsp->csr_mutex); 28221341Sstevel 28231341Sstevel /* 28241341Sstevel * XXX - The lock for the sys_led is not held here. If more 28251341Sstevel * complicated tasks are done with the System LED, then 28261341Sstevel * locking should be done here. 28271341Sstevel */ 28281341Sstevel 28291341Sstevel /* read the hardware register. */ 28301341Sstevel tmp_reg = *(softsp->csr); 28311341Sstevel 28321341Sstevel /* Only turn on the OS System LED bit if the softsp state is on. */ 28331341Sstevel if (softsp->sys_led) { 28341341Sstevel tmp_reg |= SYS_LED_RIGHT; 28351341Sstevel } else { 28361341Sstevel tmp_reg &= ~SYS_LED_RIGHT; 28371341Sstevel } 28381341Sstevel 28391341Sstevel /* Turn on the yellow LED if system fault status is set. */ 28401341Sstevel if (softsp->sys_fault) { 28411341Sstevel tmp_reg |= SYS_LED_MID; 28421341Sstevel } else { 28431341Sstevel tmp_reg &= ~SYS_LED_MID; 28441341Sstevel } 28451341Sstevel 28461341Sstevel /* write to the hardware register */ 28471341Sstevel *(softsp->csr) = tmp_reg; 28481341Sstevel 28491341Sstevel /* flush the hardware store buffer */ 28501341Sstevel tmp_reg = *(softsp->csr); 28511341Sstevel #ifdef lint 28521341Sstevel tmp_reg = tmp_reg; 28531341Sstevel #endif 28541341Sstevel mutex_exit(&softsp->csr_mutex); 28551341Sstevel 28561341Sstevel (void) timeout(blink_led_timeout, softsp, blink_led_timeout_hz); 28571341Sstevel 28581341Sstevel return (DDI_INTR_CLAIMED); 28591341Sstevel } 28601341Sstevel 28611341Sstevel /* 28621341Sstevel * simply re-trigger the interrupt handler on led timeout 28631341Sstevel */ 28641341Sstevel static void 28651341Sstevel blink_led_timeout(void *arg) 28661341Sstevel { 28671341Sstevel struct sysctrl_soft_state *softsp = arg; 28681341Sstevel int led_state; 28691341Sstevel 28701341Sstevel ASSERT(softsp); 28711341Sstevel 28721341Sstevel /* 28731341Sstevel * Process the system fault list here. This is where the driver 28741341Sstevel * must decide what yellow LEDs to turn on if any. The fault 28751341Sstevel * list is walked and each fhc_list entry is updated with it's 28761341Sstevel * yellow LED status. This info is used later by the routine 28771341Sstevel * toggle_board_green_leds(). 28781341Sstevel * 28791341Sstevel * The variable system_fault is non-zero if any non- 28801341Sstevel * suppressed faults are found in the system. 28811341Sstevel */ 28821341Sstevel softsp->sys_fault = process_fault_list(); 28831341Sstevel 28841341Sstevel /* blink the system board OS LED */ 28851341Sstevel mutex_enter(&softsp->sys_led_lock); 28861341Sstevel softsp->sys_led = !softsp->sys_led; 28871341Sstevel led_state = softsp->sys_led; 28881341Sstevel mutex_exit(&softsp->sys_led_lock); 28891341Sstevel 28901341Sstevel toggle_board_green_leds(led_state); 28911341Sstevel 28921341Sstevel ddi_trigger_softintr(softsp->blink_led_id); 28931341Sstevel } 28941341Sstevel 28951341Sstevel void 28961341Sstevel toggle_board_green_leds(int led_state) 28971341Sstevel { 28981341Sstevel fhc_bd_t *list; 28991341Sstevel 29001341Sstevel (void) fhc_bdlist_lock(-1); 29011341Sstevel for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) { 29021341Sstevel uint_t value = 0; 29031341Sstevel 29041341Sstevel if (list->sc.in_transition || 29051341Sstevel (list->sc.rstate != SYSC_CFGA_RSTATE_CONNECTED)) 29061341Sstevel continue; 29071341Sstevel 29081341Sstevel ASSERT(list->sc.type != CLOCK_BOARD); 29091341Sstevel ASSERT(list->sc.type != DISK_BOARD); 29101341Sstevel ASSERT(list->softsp); 29111341Sstevel 29121341Sstevel if ((list->sc.ostate == SYSC_CFGA_OSTATE_CONFIGURED) && 29131341Sstevel led_state) 29141341Sstevel value |= FHC_LED_RIGHT; 29151341Sstevel 29161341Sstevel if (list->fault) 29171341Sstevel value |= FHC_LED_MID; 29181341Sstevel else 29191341Sstevel value &= ~FHC_LED_MID; 29201341Sstevel 29211341Sstevel update_board_leds(list, FHC_LED_RIGHT|FHC_LED_MID, value); 29221341Sstevel } 29231341Sstevel fhc_bdlist_unlock(); 29241341Sstevel } 29251341Sstevel 29261341Sstevel /* 29271341Sstevel * timestamp an AC power failure in nvram 29281341Sstevel */ 29291341Sstevel static void 29301341Sstevel nvram_update_powerfail(struct sysctrl_soft_state *softsp) 29311341Sstevel { 29321341Sstevel char buf[80]; 29331341Sstevel int len = 0; 29341341Sstevel 29351341Sstevel numtos(gethrestime_sec(), buf); 29361341Sstevel 29371341Sstevel if (softsp->options_nodeid) { 29381341Sstevel len = prom_setprop(softsp->options_nodeid, "powerfail-time", 29391341Sstevel buf, strlen(buf)+1); 29401341Sstevel } 29411341Sstevel 29421341Sstevel if (len <= 0) { 29431341Sstevel cmn_err(CE_WARN, "sysctrl%d: failed to set powerfail-time " 29441341Sstevel "to %s\n", ddi_get_instance(softsp->dip), buf); 29451341Sstevel } 29461341Sstevel } 29471341Sstevel 29481341Sstevel void 29491341Sstevel sysctrl_add_kstats(struct sysctrl_soft_state *softsp) 29501341Sstevel { 29511341Sstevel struct kstat *ksp; /* Generic sysctrl kstats */ 29521341Sstevel struct kstat *pksp; /* Power Supply kstat */ 29531341Sstevel struct kstat *tksp; /* Sysctrl temperatrure kstat */ 29541341Sstevel struct kstat *ttsp; /* Sysctrl temperature test kstat */ 29551341Sstevel 29561341Sstevel if ((ksp = kstat_create("unix", ddi_get_instance(softsp->dip), 29571341Sstevel SYSCTRL_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED, 29581341Sstevel sizeof (struct sysctrl_kstat) / sizeof (kstat_named_t), 29591341Sstevel KSTAT_FLAG_PERSISTENT)) == NULL) { 29601341Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed", 29611341Sstevel ddi_get_instance(softsp->dip)); 29621341Sstevel } else { 29631341Sstevel struct sysctrl_kstat *sysksp; 29641341Sstevel 29651341Sstevel sysksp = (struct sysctrl_kstat *)(ksp->ks_data); 29661341Sstevel 29671341Sstevel /* now init the named kstats */ 29681341Sstevel kstat_named_init(&sysksp->csr, CSR_KSTAT_NAMED, 29691341Sstevel KSTAT_DATA_CHAR); 29701341Sstevel 29711341Sstevel kstat_named_init(&sysksp->status1, STAT1_KSTAT_NAMED, 29721341Sstevel KSTAT_DATA_CHAR); 29731341Sstevel 29741341Sstevel kstat_named_init(&sysksp->status2, STAT2_KSTAT_NAMED, 29751341Sstevel KSTAT_DATA_CHAR); 29761341Sstevel 29771341Sstevel kstat_named_init(&sysksp->clk_freq2, CLK_FREQ2_KSTAT_NAMED, 29781341Sstevel KSTAT_DATA_CHAR); 29791341Sstevel 29801341Sstevel kstat_named_init(&sysksp->fan_status, FAN_KSTAT_NAMED, 29811341Sstevel KSTAT_DATA_CHAR); 29821341Sstevel 29831341Sstevel kstat_named_init(&sysksp->key_status, KEY_KSTAT_NAMED, 29841341Sstevel KSTAT_DATA_CHAR); 29851341Sstevel 29861341Sstevel kstat_named_init(&sysksp->power_state, POWER_KSTAT_NAMED, 29871341Sstevel KSTAT_DATA_INT32); 29881341Sstevel 29891341Sstevel kstat_named_init(&sysksp->clk_ver, CLK_VER_KSTAT_NAME, 29901341Sstevel KSTAT_DATA_CHAR); 29911341Sstevel 29921341Sstevel ksp->ks_update = sysctrl_kstat_update; 29931341Sstevel ksp->ks_private = (void *)softsp; 29941341Sstevel kstat_install(ksp); 29951341Sstevel } 29961341Sstevel 29971341Sstevel if ((tksp = kstat_create("unix", CLOCK_BOARD_INDEX, 29981341Sstevel OVERTEMP_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, 29991341Sstevel sizeof (struct temp_stats), KSTAT_FLAG_PERSISTENT)) == NULL) { 30001341Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed", 30011341Sstevel ddi_get_instance(softsp->dip)); 30021341Sstevel } else { 30031341Sstevel tksp->ks_update = overtemp_kstat_update; 30041341Sstevel tksp->ks_private = (void *)&softsp->tempstat; 30051341Sstevel kstat_install(tksp); 30061341Sstevel } 30071341Sstevel 30081341Sstevel if ((ttsp = kstat_create("unix", CLOCK_BOARD_INDEX, 30091341Sstevel TEMP_OVERRIDE_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, sizeof (short), 30101341Sstevel KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) { 30111341Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed", 30121341Sstevel ddi_get_instance(softsp->dip)); 30131341Sstevel } else { 30141341Sstevel ttsp->ks_update = temp_override_kstat_update; 30151341Sstevel ttsp->ks_private = (void *)&softsp->tempstat.override; 30161341Sstevel kstat_install(ttsp); 30171341Sstevel } 30181341Sstevel 30191341Sstevel if ((pksp = kstat_create("unix", ddi_get_instance(softsp->dip), 30201341Sstevel PSSHAD_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, 30211341Sstevel SYS_PS_COUNT, KSTAT_FLAG_PERSISTENT)) == NULL) { 30221341Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed", 30231341Sstevel ddi_get_instance(softsp->dip)); 30241341Sstevel } else { 30251341Sstevel pksp->ks_update = psstat_kstat_update; 30261341Sstevel pksp->ks_private = (void *)softsp; 30271341Sstevel kstat_install(pksp); 30281341Sstevel } 30291341Sstevel } 30301341Sstevel 30311341Sstevel static int 30321341Sstevel sysctrl_kstat_update(kstat_t *ksp, int rw) 30331341Sstevel { 30341341Sstevel struct sysctrl_kstat *sysksp; 30351341Sstevel struct sysctrl_soft_state *softsp; 30361341Sstevel 30371341Sstevel sysksp = (struct sysctrl_kstat *)(ksp->ks_data); 30381341Sstevel softsp = (struct sysctrl_soft_state *)(ksp->ks_private); 30391341Sstevel 30401341Sstevel /* this is a read-only kstat. Exit on a write */ 30411341Sstevel 30421341Sstevel if (rw == KSTAT_WRITE) { 30431341Sstevel return (EACCES); 30441341Sstevel } else { 30451341Sstevel /* 30461341Sstevel * copy the current state of the hardware into the 30471341Sstevel * kstat structure. 30481341Sstevel */ 30491341Sstevel sysksp->csr.value.c[0] = *(softsp->csr); 30501341Sstevel sysksp->status1.value.c[0] = *(softsp->status1); 30511341Sstevel sysksp->status2.value.c[0] = *(softsp->status2); 30521341Sstevel sysksp->clk_freq2.value.c[0] = *(softsp->clk_freq2); 30531341Sstevel 30541341Sstevel sysksp->fan_status.value.c[0] = softsp->pps_fan_external_state; 30551341Sstevel sysksp->key_status.value.c[0] = softsp->key_shadow; 30561341Sstevel sysksp->power_state.value.i32 = softsp->power_state; 30571341Sstevel 30581341Sstevel /* 30591341Sstevel * non-existence of the clock version register returns the 30601341Sstevel * value 0xff when the hardware register location is read 30611341Sstevel */ 30621341Sstevel if (softsp->clk_ver != NULL) 30631341Sstevel sysksp->clk_ver.value.c[0] = *(softsp->clk_ver); 30641341Sstevel else 30651341Sstevel sysksp->clk_ver.value.c[0] = (char)0xff; 30661341Sstevel } 30671341Sstevel return (0); 30681341Sstevel } 30691341Sstevel 30701341Sstevel static int 30711341Sstevel psstat_kstat_update(kstat_t *ksp, int rw) 30721341Sstevel { 30731341Sstevel struct sysctrl_soft_state *softsp; 30741341Sstevel uchar_t *ptr = (uchar_t *)(ksp->ks_data); 30751341Sstevel int ps; 30761341Sstevel 30771341Sstevel softsp = (struct sysctrl_soft_state *)(ksp->ks_private); 30781341Sstevel 30791341Sstevel if (rw == KSTAT_WRITE) { 30801341Sstevel return (EACCES); 30811341Sstevel } else { 30821341Sstevel for (ps = 0; ps < SYS_PS_COUNT; ps++) { 30831341Sstevel *ptr++ = softsp->ps_stats[ps].dcshadow; 30841341Sstevel } 30851341Sstevel } 30861341Sstevel return (0); 30871341Sstevel } 30881341Sstevel 30891341Sstevel static void 30901341Sstevel sysctrl_thread_wakeup(void *arg) 30911341Sstevel { 30921341Sstevel int type = (int)(uintptr_t)arg; 30931341Sstevel 30941341Sstevel /* 30951341Sstevel * grab mutex to guarantee that our wakeup call 30961341Sstevel * arrives after we go to sleep -- so we can't sleep forever. 30971341Sstevel */ 30981341Sstevel mutex_enter(&sslist_mutex); 30991341Sstevel switch (type) { 31001341Sstevel case OVERTEMP_POLL: 31011341Sstevel cv_signal(&overtemp_cv); 31021341Sstevel break; 31031341Sstevel case KEYSWITCH_POLL: 31041341Sstevel cv_signal(&keyswitch_cv); 31051341Sstevel break; 31061341Sstevel default: 31071341Sstevel cmn_err(CE_WARN, "sysctrl: invalid type %d to wakeup\n", type); 31081341Sstevel break; 31091341Sstevel } 31101341Sstevel mutex_exit(&sslist_mutex); 31111341Sstevel } 31121341Sstevel 31131341Sstevel static void 31141341Sstevel sysctrl_overtemp_poll(void) 31151341Sstevel { 31161341Sstevel struct sysctrl_soft_state *list; 31171341Sstevel callb_cpr_t cprinfo; 31181341Sstevel 31191341Sstevel CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "overtemp"); 31201341Sstevel 31211341Sstevel /* The overtemp data structures are protected by a mutex. */ 31221341Sstevel mutex_enter(&sslist_mutex); 31231341Sstevel 31241341Sstevel while (sysctrl_do_overtemp_thread) { 31251341Sstevel 31261341Sstevel for (list = sys_list; list != NULL; list = list->next) { 31271341Sstevel if (list->temp_reg != NULL) { 31281341Sstevel update_temp(list->pdip, &list->tempstat, 31291341Sstevel *(list->temp_reg)); 31301341Sstevel } 31311341Sstevel } 31321341Sstevel 31331341Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 31341341Sstevel 31351341Sstevel /* now have this thread sleep for a while */ 31361341Sstevel (void) timeout(sysctrl_thread_wakeup, (void *)OVERTEMP_POLL, 31371341Sstevel overtemp_timeout_hz); 31381341Sstevel 31391341Sstevel cv_wait(&overtemp_cv, &sslist_mutex); 31401341Sstevel 31411341Sstevel CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex); 31421341Sstevel } 31431341Sstevel CALLB_CPR_EXIT(&cprinfo); 31441341Sstevel thread_exit(); 31451341Sstevel /* NOTREACHED */ 31461341Sstevel } 31471341Sstevel 31481341Sstevel static void 31491341Sstevel sysctrl_keyswitch_poll(void) 31501341Sstevel { 31511341Sstevel struct sysctrl_soft_state *list; 31521341Sstevel callb_cpr_t cprinfo; 31531341Sstevel 31541341Sstevel CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "keyswitch"); 31551341Sstevel 31561341Sstevel /* The keyswitch data strcutures are protected by a mutex. */ 31571341Sstevel mutex_enter(&sslist_mutex); 31581341Sstevel 31591341Sstevel while (sysctrl_do_keyswitch_thread) { 31601341Sstevel 31611341Sstevel for (list = sys_list; list != NULL; list = list->next) { 31621341Sstevel if (list->status1 != NULL) 31631341Sstevel update_key_state(list); 31641341Sstevel } 31651341Sstevel 31661341Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 31671341Sstevel 31681341Sstevel /* now have this thread sleep for a while */ 31691341Sstevel (void) timeout(sysctrl_thread_wakeup, (void *)KEYSWITCH_POLL, 31701341Sstevel keyswitch_timeout_hz); 31711341Sstevel 31721341Sstevel cv_wait(&keyswitch_cv, &sslist_mutex); 31731341Sstevel 31741341Sstevel CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex); 31751341Sstevel } 31761341Sstevel CALLB_CPR_EXIT(&cprinfo); 31771341Sstevel thread_exit(); 31781341Sstevel /* NOTREACHED */ 31791341Sstevel } 31801341Sstevel 31811341Sstevel /* 31821341Sstevel * check the key switch position for state changes 31831341Sstevel */ 31841341Sstevel static void 31851341Sstevel update_key_state(struct sysctrl_soft_state *list) 31861341Sstevel { 31871341Sstevel enum keyswitch_state key; 31881341Sstevel 31891341Sstevel /* 31901341Sstevel * snapshot current hardware key position 31911341Sstevel */ 31921341Sstevel if (*(list->status1) & SYS_NOT_SECURE) 31931341Sstevel key = KEY_NOT_SECURE; 31941341Sstevel else 31951341Sstevel key = KEY_SECURE; 31961341Sstevel 31971341Sstevel /* 31981341Sstevel * check for state transition 31991341Sstevel */ 32001341Sstevel if (key != list->key_shadow) { 32011341Sstevel 32021341Sstevel /* 32031341Sstevel * handle state transition 32041341Sstevel */ 32051341Sstevel switch (list->key_shadow) { 32061341Sstevel case KEY_BOOT: 32071341Sstevel cmn_err(CE_CONT, "?sysctrl%d: Key switch is%sin the " 32081341Sstevel "secure position\n", ddi_get_instance(list->dip), 32091341Sstevel (key == KEY_SECURE) ? " " : " not "); 32101341Sstevel list->key_shadow = key; 32111341Sstevel break; 32121341Sstevel case KEY_SECURE: 32131341Sstevel case KEY_NOT_SECURE: 32141341Sstevel cmn_err(CE_NOTE, "sysctrl%d: Key switch has changed" 32151341Sstevel " to the %s position", 32161341Sstevel ddi_get_instance(list->dip), 32171341Sstevel (key == KEY_SECURE) ? "secure" : "not-secure"); 32181341Sstevel list->key_shadow = key; 32191341Sstevel break; 32201341Sstevel default: 32211341Sstevel cmn_err(CE_CONT, 32221341Sstevel "?sysctrl%d: Key switch is in an unknown position," 32231341Sstevel "treated as being in the %s position\n", 32241341Sstevel ddi_get_instance(list->dip), 32251341Sstevel (list->key_shadow == KEY_SECURE) ? 32261341Sstevel "secure" : "not-secure"); 32271341Sstevel break; 32281341Sstevel } 32291341Sstevel } 32301341Sstevel } 32311341Sstevel 32321341Sstevel /* 32331341Sstevel * consider key switch position when handling an abort sequence 32341341Sstevel */ 32351341Sstevel static void 32361341Sstevel sysctrl_abort_seq_handler(char *msg) 32371341Sstevel { 32381341Sstevel struct sysctrl_soft_state *list; 32391341Sstevel uint_t secure = 0; 32401341Sstevel char buf[64], inst[4]; 32411341Sstevel 32421341Sstevel 32431341Sstevel /* 32441341Sstevel * if any of the key switch positions are secure, 32451341Sstevel * then disallow entry to the prom/debugger 32461341Sstevel */ 32471341Sstevel mutex_enter(&sslist_mutex); 32481341Sstevel buf[0] = (char)0; 32491341Sstevel for (list = sys_list; list != NULL; list = list->next) { 32501341Sstevel if (!(*(list->status1) & SYS_NOT_SECURE)) { 32511341Sstevel if (secure++) 32521341Sstevel (void) strcat(buf, ","); 32531341Sstevel /* 32541341Sstevel * XXX: later, replace instance number with nodeid 32551341Sstevel */ 32561341Sstevel (void) sprintf(inst, "%d", ddi_get_instance(list->dip)); 32571341Sstevel (void) strcat(buf, inst); 32581341Sstevel } 32591341Sstevel } 32601341Sstevel mutex_exit(&sslist_mutex); 32611341Sstevel 32621341Sstevel if (secure) { 32631341Sstevel cmn_err(CE_CONT, 32641341Sstevel "!sysctrl(%s): ignoring debug enter sequence\n", buf); 32651341Sstevel } else { 32661341Sstevel cmn_err(CE_CONT, "!sysctrl: allowing debug enter\n"); 32671341Sstevel debug_enter(msg); 32681341Sstevel } 32691341Sstevel } 32701341Sstevel 32711341Sstevel #define TABLE_END 0xFF 32721341Sstevel 32731341Sstevel struct uart_cmd { 32741341Sstevel uchar_t reg; 32751341Sstevel uchar_t data; 32761341Sstevel }; 32771341Sstevel 32781341Sstevel /* 32791341Sstevel * Time constant defined by this formula: 32801341Sstevel * ((4915200/32)/(baud) -2) 32811341Sstevel */ 32821341Sstevel 32831341Sstevel struct uart_cmd uart_table[] = { 32841341Sstevel { 0x09, 0xc0 }, /* Force hardware reset */ 32851341Sstevel { 0x04, 0x46 }, /* X16 clock mode, 1 stop bit/char, no parity */ 32861341Sstevel { 0x03, 0xc0 }, /* Rx is 8 bits/char */ 32871341Sstevel { 0x05, 0xe2 }, /* DTR, Tx is 8 bits/char, RTS */ 32881341Sstevel { 0x09, 0x02 }, /* No vector returned on interrupt */ 32891341Sstevel { 0x0b, 0x55 }, /* Rx Clock = Tx Clock = BR generator = ~TRxC OUT */ 32901341Sstevel { 0x0c, 0x0e }, /* Time Constant = 0x000e for 9600 baud */ 32911341Sstevel { 0x0d, 0x00 }, /* High byte of time constant */ 32921341Sstevel { 0x0e, 0x02 }, /* BR generator comes from Z-SCC's PCLK input */ 32931341Sstevel { 0x03, 0xc1 }, /* Rx is 8 bits/char, Rx is enabled */ 32941341Sstevel { 0x05, 0xea }, /* DTR, Tx is 8 bits/char, Tx is enabled, RTS */ 32951341Sstevel { 0x0e, 0x03 }, /* BR comes from PCLK, BR generator is enabled */ 32961341Sstevel { 0x00, 0x30 }, /* Error reset */ 32971341Sstevel { 0x00, 0x30 }, /* Error reset */ 32981341Sstevel { 0x00, 0x10 }, /* external status reset */ 32991341Sstevel { 0x03, 0xc1 }, /* Rx is 8 bits/char, Rx is enabled */ 33001341Sstevel { TABLE_END, 0x0 } 33011341Sstevel }; 33021341Sstevel 33031341Sstevel static void 33041341Sstevel init_remote_console_uart(struct sysctrl_soft_state *softsp) 33051341Sstevel { 33061341Sstevel int i = 0; 33071341Sstevel 33081341Sstevel /* 33091341Sstevel * Serial chip expects software to write to the control 33101341Sstevel * register first with the desired register number. Then 33111341Sstevel * write to the control register with the desired data. 33121341Sstevel * So walk thru table writing the register/data pairs to 33131341Sstevel * the serial port chip. 33141341Sstevel */ 33151341Sstevel while (uart_table[i].reg != TABLE_END) { 33161341Sstevel *(softsp->rcons_ctl) = uart_table[i].reg; 33171341Sstevel *(softsp->rcons_ctl) = uart_table[i].data; 33181341Sstevel i++; 33191341Sstevel } 33201341Sstevel } 33211341Sstevel 33221341Sstevel /* 33231341Sstevel * return the slot information of the system 33241341Sstevel * 33251341Sstevel * function take a sysctrl_soft_state, so it's ready for sunfire+ 33261341Sstevel * change which requires 2 registers to decide the system type. 33271341Sstevel */ 33281341Sstevel static void 33291341Sstevel sysc_slot_info(int nslots, int *start, int *limit, int *incr) 33301341Sstevel { 33311341Sstevel switch (nslots) { 33321341Sstevel case 8: 33331341Sstevel *start = 0; 33341341Sstevel *limit = 8; 33351341Sstevel *incr = 1; 33361341Sstevel break; 33371341Sstevel case 5: 33381341Sstevel *start = 1; 33391341Sstevel *limit = 10; 33401341Sstevel *incr = 2; 33411341Sstevel break; 33421341Sstevel case 4: 33431341Sstevel *start = 1; 33441341Sstevel *limit = 8; 33451341Sstevel *incr = 2; 33461341Sstevel break; 33471341Sstevel case 0: 33481341Sstevel case 16: 33491341Sstevel default: 33501341Sstevel *start = 0; 33511341Sstevel *limit = 16; 33521341Sstevel *incr = 1; 33531341Sstevel break; 33541341Sstevel } 33551341Sstevel } 33561341Sstevel 33571341Sstevel /* 33581341Sstevel * reinitialize the Remote Console on the clock board 33591341Sstevel * 33601341Sstevel * with V5_AUX power outage the Remote Console ends up in 33611341Sstevel * unknown state and has to be reinitilized if it was enabled 33621341Sstevel * initially. 33631341Sstevel */ 33641341Sstevel static void 33651341Sstevel rcons_reinit(struct sysctrl_soft_state *softsp) 33661341Sstevel { 33671341Sstevel uchar_t tmp_reg; 33681341Sstevel 33691341Sstevel if (!(softsp->rcons_ctl)) 33701341Sstevel /* 33711341Sstevel * There is no OBP register set for the remote console UART, 33721341Sstevel * so offset from the last register set, the misc register 33731341Sstevel * set, in order to map in the remote console UART. 33741341Sstevel */ 33751341Sstevel if (ddi_map_regs(softsp->dip, 1, (caddr_t *)&softsp->rcons_ctl, 33761341Sstevel RMT_CONS_OFFSET, RMT_CONS_LEN)) { 33771341Sstevel cmn_err(CE_WARN, "Unable to reinitialize " 33781341Sstevel "remote console."); 33791341Sstevel return; 33801341Sstevel } 33811341Sstevel 33821341Sstevel 33831341Sstevel /* Disable the remote console reset control bits. */ 33841341Sstevel *(softsp->clk_freq2) &= ~RCONS_UART_EN; 33851341Sstevel 33861341Sstevel /* flush the hardware buffers */ 33871341Sstevel tmp_reg = *(softsp->csr); 33881341Sstevel 33891341Sstevel /* 33901341Sstevel * Program the UART to watch ttya console. 33911341Sstevel */ 33921341Sstevel init_remote_console_uart(softsp); 33931341Sstevel 33941341Sstevel /* Now enable the remote console reset control bits. */ 33951341Sstevel *(softsp->clk_freq2) |= RCONS_UART_EN; 33961341Sstevel 33971341Sstevel /* flush the hardware buffers */ 33981341Sstevel tmp_reg = *(softsp->csr); 33991341Sstevel 34001341Sstevel /* print some info for user to watch */ 34011341Sstevel cmn_err(CE_NOTE, "Remote console reinitialized"); 34021341Sstevel #ifdef lint 34031341Sstevel tmp_reg = tmp_reg; 34041341Sstevel #endif 34051341Sstevel } 3406