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