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