1*29949e86Sstevel /* 2*29949e86Sstevel * CDDL HEADER START 3*29949e86Sstevel * 4*29949e86Sstevel * The contents of this file are subject to the terms of the 5*29949e86Sstevel * Common Development and Distribution License (the "License"). 6*29949e86Sstevel * You may not use this file except in compliance with the License. 7*29949e86Sstevel * 8*29949e86Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*29949e86Sstevel * or http://www.opensolaris.org/os/licensing. 10*29949e86Sstevel * See the License for the specific language governing permissions 11*29949e86Sstevel * and limitations under the License. 12*29949e86Sstevel * 13*29949e86Sstevel * When distributing Covered Code, include this CDDL HEADER in each 14*29949e86Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*29949e86Sstevel * If applicable, add the following below this CDDL HEADER, with the 16*29949e86Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 17*29949e86Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 18*29949e86Sstevel * 19*29949e86Sstevel * CDDL HEADER END 20*29949e86Sstevel */ 21*29949e86Sstevel 22*29949e86Sstevel /* 23*29949e86Sstevel * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*29949e86Sstevel * Use is subject to license terms. 25*29949e86Sstevel */ 26*29949e86Sstevel 27*29949e86Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 28*29949e86Sstevel 29*29949e86Sstevel #include <sys/types.h> 30*29949e86Sstevel #include <sys/conf.h> 31*29949e86Sstevel #include <sys/ddi.h> 32*29949e86Sstevel #include <sys/sunddi.h> 33*29949e86Sstevel #include <sys/ddi_impldefs.h> 34*29949e86Sstevel #include <sys/sunndi.h> 35*29949e86Sstevel #include <sys/ndi_impldefs.h> 36*29949e86Sstevel #include <sys/obpdefs.h> 37*29949e86Sstevel #include <sys/cmn_err.h> 38*29949e86Sstevel #include <sys/errno.h> 39*29949e86Sstevel #include <sys/kmem.h> 40*29949e86Sstevel #include <sys/debug.h> 41*29949e86Sstevel #include <sys/sysmacros.h> 42*29949e86Sstevel #include <sys/ivintr.h> 43*29949e86Sstevel #include <sys/autoconf.h> 44*29949e86Sstevel #include <sys/intreg.h> 45*29949e86Sstevel #include <sys/proc.h> 46*29949e86Sstevel #include <sys/modctl.h> 47*29949e86Sstevel #include <sys/callb.h> 48*29949e86Sstevel #include <sys/file.h> 49*29949e86Sstevel #include <sys/open.h> 50*29949e86Sstevel #include <sys/stat.h> 51*29949e86Sstevel #include <sys/fhc.h> 52*29949e86Sstevel #include <sys/sysctrl.h> 53*29949e86Sstevel #include <sys/jtag.h> 54*29949e86Sstevel #include <sys/ac.h> 55*29949e86Sstevel #include <sys/simmstat.h> 56*29949e86Sstevel #include <sys/clock.h> 57*29949e86Sstevel #include <sys/promif.h> 58*29949e86Sstevel #include <sys/promimpl.h> 59*29949e86Sstevel #include <sys/sunndi.h> 60*29949e86Sstevel #include <sys/machsystm.h> 61*29949e86Sstevel 62*29949e86Sstevel /* Useful debugging Stuff */ 63*29949e86Sstevel #ifdef DEBUG 64*29949e86Sstevel int sysc_debug_info = 1; 65*29949e86Sstevel int sysc_debug_print_level = 0; 66*29949e86Sstevel #endif 67*29949e86Sstevel 68*29949e86Sstevel /* 69*29949e86Sstevel * Function prototypes 70*29949e86Sstevel */ 71*29949e86Sstevel static int sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 72*29949e86Sstevel void **result); 73*29949e86Sstevel 74*29949e86Sstevel static int sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 75*29949e86Sstevel 76*29949e86Sstevel static int sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 77*29949e86Sstevel 78*29949e86Sstevel static int sysctrl_open(dev_t *, int, int, cred_t *); 79*29949e86Sstevel 80*29949e86Sstevel static int sysctrl_close(dev_t, int, int, cred_t *); 81*29949e86Sstevel 82*29949e86Sstevel static int sysctrl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 83*29949e86Sstevel 84*29949e86Sstevel static uint_t system_high_handler(caddr_t arg); 85*29949e86Sstevel 86*29949e86Sstevel static uint_t spur_delay(caddr_t arg); 87*29949e86Sstevel 88*29949e86Sstevel static void spur_retry(void *); 89*29949e86Sstevel 90*29949e86Sstevel static uint_t spur_reenable(caddr_t arg); 91*29949e86Sstevel 92*29949e86Sstevel static void spur_long_timeout(void *); 93*29949e86Sstevel 94*29949e86Sstevel static uint_t spur_clear_count(caddr_t arg); 95*29949e86Sstevel 96*29949e86Sstevel static uint_t ac_fail_handler(caddr_t arg); 97*29949e86Sstevel 98*29949e86Sstevel static void ac_fail_retry(void *); 99*29949e86Sstevel 100*29949e86Sstevel static uint_t ac_fail_reenable(caddr_t arg); 101*29949e86Sstevel 102*29949e86Sstevel static uint_t ps_fail_int_handler(caddr_t arg); 103*29949e86Sstevel 104*29949e86Sstevel static uint_t ps_fail_poll_handler(caddr_t arg); 105*29949e86Sstevel 106*29949e86Sstevel static uint_t ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint); 107*29949e86Sstevel 108*29949e86Sstevel enum power_state compute_power_state(struct sysctrl_soft_state *softsp, 109*29949e86Sstevel int plus_load); 110*29949e86Sstevel 111*29949e86Sstevel static void ps_log_state_change(struct sysctrl_soft_state *softsp, 112*29949e86Sstevel int index, int present); 113*29949e86Sstevel 114*29949e86Sstevel static void ps_log_pres_change(struct sysctrl_soft_state *softsp, 115*29949e86Sstevel int index, int present); 116*29949e86Sstevel 117*29949e86Sstevel static void ps_fail_retry(void *); 118*29949e86Sstevel 119*29949e86Sstevel static uint_t pps_fanfail_handler(caddr_t arg); 120*29949e86Sstevel 121*29949e86Sstevel static void pps_fanfail_retry(void *); 122*29949e86Sstevel 123*29949e86Sstevel static uint_t pps_fanfail_reenable(caddr_t arg); 124*29949e86Sstevel 125*29949e86Sstevel static void pps_fan_poll(void *); 126*29949e86Sstevel 127*29949e86Sstevel static void pps_fan_state_change(struct sysctrl_soft_state *softsp, 128*29949e86Sstevel int index, int fan_ok); 129*29949e86Sstevel 130*29949e86Sstevel static uint_t bd_insert_handler(caddr_t arg); 131*29949e86Sstevel 132*29949e86Sstevel static void bd_insert_timeout(void *); 133*29949e86Sstevel 134*29949e86Sstevel static void bd_remove_timeout(void *); 135*29949e86Sstevel 136*29949e86Sstevel static uint_t bd_insert_normal(caddr_t arg); 137*29949e86Sstevel 138*29949e86Sstevel static void sysctrl_add_kstats(struct sysctrl_soft_state *softsp); 139*29949e86Sstevel 140*29949e86Sstevel static int sysctrl_kstat_update(kstat_t *ksp, int rw); 141*29949e86Sstevel 142*29949e86Sstevel static int psstat_kstat_update(kstat_t *, int); 143*29949e86Sstevel 144*29949e86Sstevel static void init_remote_console_uart(struct sysctrl_soft_state *); 145*29949e86Sstevel 146*29949e86Sstevel static void blink_led_timeout(void *); 147*29949e86Sstevel 148*29949e86Sstevel static uint_t blink_led_handler(caddr_t arg); 149*29949e86Sstevel 150*29949e86Sstevel static void sysctrl_thread_wakeup(void *type); 151*29949e86Sstevel 152*29949e86Sstevel static void sysctrl_overtemp_poll(void); 153*29949e86Sstevel 154*29949e86Sstevel static void sysctrl_keyswitch_poll(void); 155*29949e86Sstevel 156*29949e86Sstevel static void update_key_state(struct sysctrl_soft_state *); 157*29949e86Sstevel 158*29949e86Sstevel static void sysctrl_abort_seq_handler(char *msg); 159*29949e86Sstevel 160*29949e86Sstevel static void nvram_update_powerfail(struct sysctrl_soft_state *softsp); 161*29949e86Sstevel 162*29949e86Sstevel static void toggle_board_green_leds(int); 163*29949e86Sstevel 164*29949e86Sstevel void bd_remove_poll(struct sysctrl_soft_state *); 165*29949e86Sstevel 166*29949e86Sstevel static void sysc_slot_info(int nslots, int *start, int *limit, int *incr); 167*29949e86Sstevel 168*29949e86Sstevel extern void sysc_board_connect_supported_init(void); 169*29949e86Sstevel 170*29949e86Sstevel static void rcons_reinit(struct sysctrl_soft_state *softsp); 171*29949e86Sstevel 172*29949e86Sstevel /* 173*29949e86Sstevel * Configuration data structures 174*29949e86Sstevel */ 175*29949e86Sstevel static struct cb_ops sysctrl_cb_ops = { 176*29949e86Sstevel sysctrl_open, /* open */ 177*29949e86Sstevel sysctrl_close, /* close */ 178*29949e86Sstevel nulldev, /* strategy */ 179*29949e86Sstevel nulldev, /* print */ 180*29949e86Sstevel nulldev, /* dump */ 181*29949e86Sstevel nulldev, /* read */ 182*29949e86Sstevel nulldev, /* write */ 183*29949e86Sstevel sysctrl_ioctl, /* ioctl */ 184*29949e86Sstevel nodev, /* devmap */ 185*29949e86Sstevel nodev, /* mmap */ 186*29949e86Sstevel nodev, /* segmap */ 187*29949e86Sstevel nochpoll, /* poll */ 188*29949e86Sstevel ddi_prop_op, /* cb_prop_op */ 189*29949e86Sstevel 0, /* streamtab */ 190*29949e86Sstevel D_MP|D_NEW, /* Driver compatibility flag */ 191*29949e86Sstevel CB_REV, /* rev */ 192*29949e86Sstevel nodev, /* cb_aread */ 193*29949e86Sstevel nodev /* cb_awrite */ 194*29949e86Sstevel }; 195*29949e86Sstevel 196*29949e86Sstevel static struct dev_ops sysctrl_ops = { 197*29949e86Sstevel DEVO_REV, /* devo_rev */ 198*29949e86Sstevel 0, /* refcnt */ 199*29949e86Sstevel sysctrl_info, /* getinfo */ 200*29949e86Sstevel nulldev, /* identify */ 201*29949e86Sstevel nulldev, /* probe */ 202*29949e86Sstevel sysctrl_attach, /* attach */ 203*29949e86Sstevel sysctrl_detach, /* detach */ 204*29949e86Sstevel nulldev, /* reset */ 205*29949e86Sstevel &sysctrl_cb_ops, /* cb_ops */ 206*29949e86Sstevel (struct bus_ops *)0, /* bus_ops */ 207*29949e86Sstevel nulldev /* power */ 208*29949e86Sstevel }; 209*29949e86Sstevel 210*29949e86Sstevel void *sysctrlp; /* sysctrl soft state hook */ 211*29949e86Sstevel 212*29949e86Sstevel /* # of ticks to silence spurious interrupts */ 213*29949e86Sstevel static clock_t spur_timeout_hz; 214*29949e86Sstevel 215*29949e86Sstevel /* # of ticks to count spurious interrupts to print message */ 216*29949e86Sstevel static clock_t spur_long_timeout_hz; 217*29949e86Sstevel 218*29949e86Sstevel /* # of ticks between AC failure polling */ 219*29949e86Sstevel static clock_t ac_timeout_hz; 220*29949e86Sstevel 221*29949e86Sstevel /* # of ticks between Power Supply Failure polling */ 222*29949e86Sstevel static clock_t ps_fail_timeout_hz; 223*29949e86Sstevel 224*29949e86Sstevel /* 225*29949e86Sstevel * # of ticks between Peripheral Power Supply failure polling 226*29949e86Sstevel * (used both for interrupt retry timeout and polling function) 227*29949e86Sstevel */ 228*29949e86Sstevel static clock_t pps_fan_timeout_hz; 229*29949e86Sstevel 230*29949e86Sstevel /* # of ticks delay after board insert interrupt */ 231*29949e86Sstevel static clock_t bd_insert_delay_hz; 232*29949e86Sstevel 233*29949e86Sstevel /* # of secs to wait before restarting poll if we cannot clear interrupts */ 234*29949e86Sstevel static clock_t bd_insert_retry_hz; 235*29949e86Sstevel 236*29949e86Sstevel /* # of secs between Board Removal polling */ 237*29949e86Sstevel static clock_t bd_remove_timeout_hz; 238*29949e86Sstevel 239*29949e86Sstevel /* # of secs between toggle of OS LED */ 240*29949e86Sstevel static clock_t blink_led_timeout_hz; 241*29949e86Sstevel 242*29949e86Sstevel /* overtemp polling routine timeout delay */ 243*29949e86Sstevel static clock_t overtemp_timeout_hz; 244*29949e86Sstevel 245*29949e86Sstevel /* key switch polling routine timeout delay */ 246*29949e86Sstevel static clock_t keyswitch_timeout_hz; 247*29949e86Sstevel 248*29949e86Sstevel /* Specify which system interrupt condition to monitor */ 249*29949e86Sstevel int enable_sys_interrupt = SYS_AC_PWR_FAIL_EN | SYS_PPS_FAN_FAIL_EN | 250*29949e86Sstevel SYS_PS_FAIL_EN | SYS_SBRD_PRES_EN; 251*29949e86Sstevel 252*29949e86Sstevel /* Should the overtemp_poll thread be running? */ 253*29949e86Sstevel static int sysctrl_do_overtemp_thread = 1; 254*29949e86Sstevel 255*29949e86Sstevel /* Should the keyswitch_poll thread be running? */ 256*29949e86Sstevel static int sysctrl_do_keyswitch_thread = 1; 257*29949e86Sstevel 258*29949e86Sstevel /* 259*29949e86Sstevel * This timeout ID is for board remove polling routine. It is 260*29949e86Sstevel * protected by the fhc_bdlist mutex. 261*29949e86Sstevel * XXX - This will not work for wildfire. A different scheme must be 262*29949e86Sstevel * used since there will be multiple sysctrl nodes, each with its 263*29949e86Sstevel * own list of hotplugged boards to scan. 264*29949e86Sstevel */ 265*29949e86Sstevel static timeout_id_t bd_remove_to_id = 0; 266*29949e86Sstevel 267*29949e86Sstevel /* 268*29949e86Sstevel * If this is set, the system will not shutdown when insufficient power 269*29949e86Sstevel * condition persists. 270*29949e86Sstevel */ 271*29949e86Sstevel int disable_insufficient_power_reboot = 0; 272*29949e86Sstevel 273*29949e86Sstevel /* 274*29949e86Sstevel * Set this to enable suspend/resume 275*29949e86Sstevel */ 276*29949e86Sstevel int sysctrl_enable_detach_suspend = 0; 277*29949e86Sstevel 278*29949e86Sstevel /* 279*29949e86Sstevel * Set this to reflect the OBP initialized HOTPLUG_DISABLED_PROPERTY and 280*29949e86Sstevel * during dynamic detection 281*29949e86Sstevel */ 282*29949e86Sstevel int sysctrl_hotplug_disabled = FALSE; 283*29949e86Sstevel 284*29949e86Sstevel /* Indicates whether or not the overtemp thread has been started */ 285*29949e86Sstevel static int sysctrl_overtemp_thread_started = 0; 286*29949e86Sstevel 287*29949e86Sstevel /* Indicates whether or not the key switch thread has been started */ 288*29949e86Sstevel static int sysctrl_keyswitch_thread_started = 0; 289*29949e86Sstevel 290*29949e86Sstevel /* *Mutex used to protect the soft state list */ 291*29949e86Sstevel static kmutex_t sslist_mutex; 292*29949e86Sstevel 293*29949e86Sstevel /* The CV is used to wakeup the overtemp thread when needed. */ 294*29949e86Sstevel static kcondvar_t overtemp_cv; 295*29949e86Sstevel 296*29949e86Sstevel /* The CV is used to wakeup the key switch thread when needed. */ 297*29949e86Sstevel static kcondvar_t keyswitch_cv; 298*29949e86Sstevel 299*29949e86Sstevel /* This mutex is used to protect the sysctrl_ddi_branch_init variable */ 300*29949e86Sstevel static kmutex_t sysctrl_branch_mutex; 301*29949e86Sstevel 302*29949e86Sstevel /* 303*29949e86Sstevel * This variable is set after all existing branches in the system have 304*29949e86Sstevel * been discovered and held via e_ddi_branch_hold(). This happens on 305*29949e86Sstevel * first open() of any sysctrl minor node. 306*29949e86Sstevel */ 307*29949e86Sstevel static int sysctrl_ddi_branch_init; 308*29949e86Sstevel 309*29949e86Sstevel /* 310*29949e86Sstevel * Linked list of all syctrl soft state structures. 311*29949e86Sstevel * Used for polling sysctrl state changes, i.e. temperature. 312*29949e86Sstevel */ 313*29949e86Sstevel struct sysctrl_soft_state *sys_list = NULL; 314*29949e86Sstevel 315*29949e86Sstevel extern struct mod_ops mod_driverops; 316*29949e86Sstevel 317*29949e86Sstevel static struct modldrv modldrv = { 318*29949e86Sstevel &mod_driverops, /* Type of module. This one is a driver */ 319*29949e86Sstevel "Clock Board %I%", /* name of module */ 320*29949e86Sstevel &sysctrl_ops, /* driver ops */ 321*29949e86Sstevel }; 322*29949e86Sstevel 323*29949e86Sstevel static struct modlinkage modlinkage = { 324*29949e86Sstevel MODREV_1, /* rev */ 325*29949e86Sstevel (void *)&modldrv, 326*29949e86Sstevel NULL 327*29949e86Sstevel }; 328*29949e86Sstevel 329*29949e86Sstevel #ifndef lint 330*29949e86Sstevel static char _depends_on[] = "drv/fhc"; 331*29949e86Sstevel #endif /* lint */ 332*29949e86Sstevel 333*29949e86Sstevel /* 334*29949e86Sstevel * These are the module initialization routines. 335*29949e86Sstevel */ 336*29949e86Sstevel 337*29949e86Sstevel int 338*29949e86Sstevel _init(void) 339*29949e86Sstevel { 340*29949e86Sstevel int error; 341*29949e86Sstevel 342*29949e86Sstevel if ((error = ddi_soft_state_init(&sysctrlp, 343*29949e86Sstevel sizeof (struct sysctrl_soft_state), 1)) != 0) 344*29949e86Sstevel return (error); 345*29949e86Sstevel 346*29949e86Sstevel error = mod_install(&modlinkage); 347*29949e86Sstevel if (error != 0) { 348*29949e86Sstevel ddi_soft_state_fini(&sysctrlp); 349*29949e86Sstevel return (error); 350*29949e86Sstevel } 351*29949e86Sstevel 352*29949e86Sstevel mutex_init(&sysctrl_branch_mutex, NULL, MUTEX_DRIVER, NULL); 353*29949e86Sstevel 354*29949e86Sstevel return (0); 355*29949e86Sstevel } 356*29949e86Sstevel 357*29949e86Sstevel int 358*29949e86Sstevel _fini(void) 359*29949e86Sstevel { 360*29949e86Sstevel int error; 361*29949e86Sstevel 362*29949e86Sstevel if ((error = mod_remove(&modlinkage)) != 0) 363*29949e86Sstevel return (error); 364*29949e86Sstevel 365*29949e86Sstevel ddi_soft_state_fini(&sysctrlp); 366*29949e86Sstevel 367*29949e86Sstevel mutex_destroy(&sysctrl_branch_mutex); 368*29949e86Sstevel 369*29949e86Sstevel return (0); 370*29949e86Sstevel } 371*29949e86Sstevel 372*29949e86Sstevel int 373*29949e86Sstevel _info(struct modinfo *modinfop) 374*29949e86Sstevel { 375*29949e86Sstevel return (mod_info(&modlinkage, modinfop)); 376*29949e86Sstevel } 377*29949e86Sstevel 378*29949e86Sstevel /* ARGSUSED */ 379*29949e86Sstevel static int 380*29949e86Sstevel sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 381*29949e86Sstevel { 382*29949e86Sstevel dev_t dev; 383*29949e86Sstevel int instance; 384*29949e86Sstevel 385*29949e86Sstevel if (infocmd == DDI_INFO_DEVT2INSTANCE) { 386*29949e86Sstevel dev = (dev_t)arg; 387*29949e86Sstevel instance = GETINSTANCE(dev); 388*29949e86Sstevel *result = (void *)(uintptr_t)instance; 389*29949e86Sstevel return (DDI_SUCCESS); 390*29949e86Sstevel } 391*29949e86Sstevel return (DDI_FAILURE); 392*29949e86Sstevel } 393*29949e86Sstevel 394*29949e86Sstevel static int 395*29949e86Sstevel sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 396*29949e86Sstevel { 397*29949e86Sstevel struct sysctrl_soft_state *softsp; 398*29949e86Sstevel int instance; 399*29949e86Sstevel uchar_t tmp_reg; 400*29949e86Sstevel dev_info_t *dip; 401*29949e86Sstevel char *propval; 402*29949e86Sstevel int proplen; 403*29949e86Sstevel int slot_num; 404*29949e86Sstevel int start; /* start index for scan loop */ 405*29949e86Sstevel int limit; /* board number limit for scan loop */ 406*29949e86Sstevel int incr; /* amount to incr each pass thru loop */ 407*29949e86Sstevel void set_clockbrd_info(void); 408*29949e86Sstevel 409*29949e86Sstevel 410*29949e86Sstevel switch (cmd) { 411*29949e86Sstevel case DDI_ATTACH: 412*29949e86Sstevel break; 413*29949e86Sstevel 414*29949e86Sstevel case DDI_RESUME: 415*29949e86Sstevel /* XXX see sysctrl:DDI_SUSPEND for special h/w treatment */ 416*29949e86Sstevel return (DDI_SUCCESS); 417*29949e86Sstevel 418*29949e86Sstevel default: 419*29949e86Sstevel return (DDI_FAILURE); 420*29949e86Sstevel } 421*29949e86Sstevel 422*29949e86Sstevel instance = ddi_get_instance(devi); 423*29949e86Sstevel 424*29949e86Sstevel if (ddi_soft_state_zalloc(sysctrlp, instance) != DDI_SUCCESS) 425*29949e86Sstevel return (DDI_FAILURE); 426*29949e86Sstevel 427*29949e86Sstevel softsp = GETSOFTC(instance); 428*29949e86Sstevel 429*29949e86Sstevel /* Set the dip in the soft state */ 430*29949e86Sstevel softsp->dip = devi; 431*29949e86Sstevel 432*29949e86Sstevel /* Set up the parent dip */ 433*29949e86Sstevel softsp->pdip = ddi_get_parent(softsp->dip); 434*29949e86Sstevel 435*29949e86Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, ("sysctrl: devi= 0x%p\n, softsp=0x%p\n", 436*29949e86Sstevel devi, softsp)); 437*29949e86Sstevel 438*29949e86Sstevel /* First set all of the timeout values */ 439*29949e86Sstevel spur_timeout_hz = drv_usectohz(SPUR_TIMEOUT_USEC); 440*29949e86Sstevel spur_long_timeout_hz = drv_usectohz(SPUR_LONG_TIMEOUT_USEC); 441*29949e86Sstevel ac_timeout_hz = drv_usectohz(AC_TIMEOUT_USEC); 442*29949e86Sstevel ps_fail_timeout_hz = drv_usectohz(PS_FAIL_TIMEOUT_USEC); 443*29949e86Sstevel pps_fan_timeout_hz = drv_usectohz(PPS_FAN_TIMEOUT_USEC); 444*29949e86Sstevel bd_insert_delay_hz = drv_usectohz(BRD_INSERT_DELAY_USEC); 445*29949e86Sstevel bd_insert_retry_hz = drv_usectohz(BRD_INSERT_RETRY_USEC); 446*29949e86Sstevel bd_remove_timeout_hz = drv_usectohz(BRD_REMOVE_TIMEOUT_USEC); 447*29949e86Sstevel blink_led_timeout_hz = drv_usectohz(BLINK_LED_TIMEOUT_USEC); 448*29949e86Sstevel overtemp_timeout_hz = drv_usectohz(OVERTEMP_TIMEOUT_SEC * MICROSEC); 449*29949e86Sstevel keyswitch_timeout_hz = drv_usectohz(KEYSWITCH_TIMEOUT_USEC); 450*29949e86Sstevel 451*29949e86Sstevel /* 452*29949e86Sstevel * Map in the registers sets that OBP hands us. According 453*29949e86Sstevel * to the sun4u device tree spec., the register sets are as 454*29949e86Sstevel * follows: 455*29949e86Sstevel * 456*29949e86Sstevel * 0 Clock Frequency Registers (contains the bit 457*29949e86Sstevel * for enabling the remote console reset) 458*29949e86Sstevel * 1 Misc (has all the registers that we need 459*29949e86Sstevel * 2 Clock Version Register 460*29949e86Sstevel */ 461*29949e86Sstevel if (ddi_map_regs(softsp->dip, 0, 462*29949e86Sstevel (caddr_t *)&softsp->clk_freq1, 0, 0)) { 463*29949e86Sstevel cmn_err(CE_WARN, "sysctrl%d: unable to map clock frequency " 464*29949e86Sstevel "registers", instance); 465*29949e86Sstevel goto bad0; 466*29949e86Sstevel } 467*29949e86Sstevel 468*29949e86Sstevel if (ddi_map_regs(softsp->dip, 1, 469*29949e86Sstevel (caddr_t *)&softsp->csr, 0, 0)) { 470*29949e86Sstevel cmn_err(CE_WARN, "sysctrl%d: unable to map internal" 471*29949e86Sstevel "registers", instance); 472*29949e86Sstevel goto bad1; 473*29949e86Sstevel } 474*29949e86Sstevel 475*29949e86Sstevel /* 476*29949e86Sstevel * There is a new register for newer vintage clock board nodes, 477*29949e86Sstevel * OBP register set 2 in the clock board node. 478*29949e86Sstevel * 479*29949e86Sstevel */ 480*29949e86Sstevel (void) ddi_map_regs(softsp->dip, 2, (caddr_t *)&softsp->clk_ver, 0, 0); 481*29949e86Sstevel 482*29949e86Sstevel /* 483*29949e86Sstevel * Fill in the virtual addresses of the registers in the 484*29949e86Sstevel * sysctrl_soft_state structure. We do not want to calculate 485*29949e86Sstevel * them on the fly. This way we waste a little memory, but 486*29949e86Sstevel * avoid bugs down the road. 487*29949e86Sstevel */ 488*29949e86Sstevel softsp->clk_freq2 = (uchar_t *)((caddr_t)softsp->clk_freq1 + 489*29949e86Sstevel SYS_OFF_CLK_FREQ2); 490*29949e86Sstevel 491*29949e86Sstevel softsp->status1 = (uchar_t *)((caddr_t)softsp->csr + 492*29949e86Sstevel SYS_OFF_STAT1); 493*29949e86Sstevel 494*29949e86Sstevel softsp->status2 = (uchar_t *)((caddr_t)softsp->csr + 495*29949e86Sstevel SYS_OFF_STAT2); 496*29949e86Sstevel 497*29949e86Sstevel softsp->ps_stat = (uchar_t *)((caddr_t)softsp->csr + 498*29949e86Sstevel SYS_OFF_PSSTAT); 499*29949e86Sstevel 500*29949e86Sstevel softsp->ps_pres = (uchar_t *)((caddr_t)softsp->csr + 501*29949e86Sstevel SYS_OFF_PSPRES); 502*29949e86Sstevel 503*29949e86Sstevel softsp->pppsr = (uchar_t *)((caddr_t)softsp->csr + 504*29949e86Sstevel SYS_OFF_PPPSR); 505*29949e86Sstevel 506*29949e86Sstevel softsp->temp_reg = (uchar_t *)((caddr_t)softsp->csr + 507*29949e86Sstevel SYS_OFF_TEMP); 508*29949e86Sstevel 509*29949e86Sstevel set_clockbrd_info(); 510*29949e86Sstevel 511*29949e86Sstevel /* 512*29949e86Sstevel * Enable the hardware watchdog gate on the clock board if 513*29949e86Sstevel * map_wellknown has detected that watchdog timer is available 514*29949e86Sstevel * and user wants it to be enabled. 515*29949e86Sstevel */ 516*29949e86Sstevel if (watchdog_available && watchdog_enable) 517*29949e86Sstevel *(softsp->clk_freq2) |= TOD_RESET_EN; 518*29949e86Sstevel else 519*29949e86Sstevel *(softsp->clk_freq2) &= ~TOD_RESET_EN; 520*29949e86Sstevel 521*29949e86Sstevel /* Check for inherited faults from the PROM. */ 522*29949e86Sstevel if (*softsp->csr & SYS_LED_MID) { 523*29949e86Sstevel reg_fault(0, FT_PROM, FT_SYSTEM); 524*29949e86Sstevel } 525*29949e86Sstevel 526*29949e86Sstevel /* 527*29949e86Sstevel * calculate and cache the number of slots on this system 528*29949e86Sstevel */ 529*29949e86Sstevel switch (SYS_TYPE(*softsp->status1)) { 530*29949e86Sstevel case SYS_16_SLOT: 531*29949e86Sstevel softsp->nslots = 16; 532*29949e86Sstevel break; 533*29949e86Sstevel 534*29949e86Sstevel case SYS_8_SLOT: 535*29949e86Sstevel softsp->nslots = 8; 536*29949e86Sstevel break; 537*29949e86Sstevel 538*29949e86Sstevel case SYS_4_SLOT: 539*29949e86Sstevel /* check the clk_version register - if the ptr is valid */ 540*29949e86Sstevel if ((softsp->clk_ver != NULL) && 541*29949e86Sstevel (SYS_TYPE2(*softsp->clk_ver) == SYS_PLUS_SYSTEM)) { 542*29949e86Sstevel softsp->nslots = 5; 543*29949e86Sstevel } else { 544*29949e86Sstevel softsp->nslots = 4; 545*29949e86Sstevel } 546*29949e86Sstevel break; 547*29949e86Sstevel 548*29949e86Sstevel case SYS_TESTBED: 549*29949e86Sstevel default: 550*29949e86Sstevel softsp->nslots = 0; 551*29949e86Sstevel break; 552*29949e86Sstevel } 553*29949e86Sstevel 554*29949e86Sstevel 555*29949e86Sstevel /* create the fault list kstat */ 556*29949e86Sstevel create_ft_kstats(instance); 557*29949e86Sstevel 558*29949e86Sstevel /* 559*29949e86Sstevel * Do a priming read on the ADC, and throw away the first value 560*29949e86Sstevel * read. This is a feature of the ADC hardware. After a power cycle 561*29949e86Sstevel * it does not contains valid data until a read occurs. 562*29949e86Sstevel */ 563*29949e86Sstevel tmp_reg = *(softsp->temp_reg); 564*29949e86Sstevel 565*29949e86Sstevel /* Wait 30 usec for ADC hardware to stabilize. */ 566*29949e86Sstevel DELAY(30); 567*29949e86Sstevel 568*29949e86Sstevel /* shut off all interrupt sources */ 569*29949e86Sstevel *(softsp->csr) &= ~(SYS_PPS_FAN_FAIL_EN | SYS_PS_FAIL_EN | 570*29949e86Sstevel SYS_AC_PWR_FAIL_EN | SYS_SBRD_PRES_EN); 571*29949e86Sstevel tmp_reg = *(softsp->csr); 572*29949e86Sstevel #ifdef lint 573*29949e86Sstevel tmp_reg = tmp_reg; 574*29949e86Sstevel #endif 575*29949e86Sstevel 576*29949e86Sstevel /* 577*29949e86Sstevel * Now register our high interrupt with the system. 578*29949e86Sstevel */ 579*29949e86Sstevel if (ddi_add_intr(devi, 0, &softsp->iblock, 580*29949e86Sstevel &softsp->idevice, (uint_t (*)(caddr_t))nulldev, NULL) != 581*29949e86Sstevel DDI_SUCCESS) 582*29949e86Sstevel goto bad2; 583*29949e86Sstevel 584*29949e86Sstevel mutex_init(&softsp->csr_mutex, NULL, MUTEX_DRIVER, 585*29949e86Sstevel (void *)softsp->iblock); 586*29949e86Sstevel 587*29949e86Sstevel ddi_remove_intr(devi, 0, softsp->iblock); 588*29949e86Sstevel 589*29949e86Sstevel if (ddi_add_intr(devi, 0, &softsp->iblock, 590*29949e86Sstevel &softsp->idevice, system_high_handler, (caddr_t)softsp) != 591*29949e86Sstevel DDI_SUCCESS) 592*29949e86Sstevel goto bad3; 593*29949e86Sstevel 594*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_id, 595*29949e86Sstevel &softsp->spur_int_c, NULL, spur_delay, (caddr_t)softsp) != 596*29949e86Sstevel DDI_SUCCESS) 597*29949e86Sstevel goto bad4; 598*29949e86Sstevel 599*29949e86Sstevel mutex_init(&softsp->spur_int_lock, NULL, MUTEX_DRIVER, 600*29949e86Sstevel (void *)softsp->spur_int_c); 601*29949e86Sstevel 602*29949e86Sstevel 603*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_high_id, 604*29949e86Sstevel NULL, NULL, spur_reenable, (caddr_t)softsp) != DDI_SUCCESS) 605*29949e86Sstevel goto bad5; 606*29949e86Sstevel 607*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_long_to_id, 608*29949e86Sstevel NULL, NULL, spur_clear_count, (caddr_t)softsp) != DDI_SUCCESS) 609*29949e86Sstevel goto bad6; 610*29949e86Sstevel 611*29949e86Sstevel /* 612*29949e86Sstevel * Now register low-level ac fail handler 613*29949e86Sstevel */ 614*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ac_fail_id, 615*29949e86Sstevel NULL, NULL, ac_fail_handler, (caddr_t)softsp) != DDI_SUCCESS) 616*29949e86Sstevel goto bad7; 617*29949e86Sstevel 618*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ac_fail_high_id, 619*29949e86Sstevel NULL, NULL, ac_fail_reenable, (caddr_t)softsp) != DDI_SUCCESS) 620*29949e86Sstevel goto bad8; 621*29949e86Sstevel 622*29949e86Sstevel /* 623*29949e86Sstevel * Now register low-level ps fail handler 624*29949e86Sstevel */ 625*29949e86Sstevel 626*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ps_fail_int_id, 627*29949e86Sstevel &softsp->ps_fail_c, NULL, ps_fail_int_handler, (caddr_t)softsp) != 628*29949e86Sstevel DDI_SUCCESS) 629*29949e86Sstevel goto bad9; 630*29949e86Sstevel 631*29949e86Sstevel mutex_init(&softsp->ps_fail_lock, NULL, MUTEX_DRIVER, 632*29949e86Sstevel (void *)softsp->ps_fail_c); 633*29949e86Sstevel 634*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ps_fail_poll_id, 635*29949e86Sstevel NULL, NULL, ps_fail_poll_handler, (caddr_t)softsp) != 636*29949e86Sstevel DDI_SUCCESS) 637*29949e86Sstevel goto bad10; 638*29949e86Sstevel 639*29949e86Sstevel /* 640*29949e86Sstevel * Now register low-level pps fan fail handler 641*29949e86Sstevel */ 642*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_id, 643*29949e86Sstevel NULL, NULL, pps_fanfail_handler, (caddr_t)softsp) != 644*29949e86Sstevel DDI_SUCCESS) 645*29949e86Sstevel goto bad11; 646*29949e86Sstevel 647*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_high_id, 648*29949e86Sstevel NULL, NULL, pps_fanfail_reenable, (caddr_t)softsp) != 649*29949e86Sstevel DDI_SUCCESS) 650*29949e86Sstevel goto bad12; 651*29949e86Sstevel 652*29949e86Sstevel /* 653*29949e86Sstevel * Based upon a check for a current share backplane, advise 654*29949e86Sstevel * that system does not support hot plug 655*29949e86Sstevel * 656*29949e86Sstevel */ 657*29949e86Sstevel if ((*(softsp->pppsr) & SYS_NOT_CURRENT_S) != 0) { 658*29949e86Sstevel cmn_err(CE_NOTE, "Hot Plug not supported in this system"); 659*29949e86Sstevel sysctrl_hotplug_disabled = TRUE; 660*29949e86Sstevel } 661*29949e86Sstevel 662*29949e86Sstevel /* 663*29949e86Sstevel * If the trigger circuit is busted or the NOT_BRD_PRES line 664*29949e86Sstevel * is stuck then OBP will publish this property stating that 665*29949e86Sstevel * hot plug is not available. If this happens we will complain 666*29949e86Sstevel * to the console and register a system fault. We will also 667*29949e86Sstevel * not enable the board insert interrupt for this session. 668*29949e86Sstevel */ 669*29949e86Sstevel if (ddi_prop_op(DDI_DEV_T_ANY, softsp->dip, PROP_LEN_AND_VAL_ALLOC, 670*29949e86Sstevel DDI_PROP_DONTPASS, HOTPLUG_DISABLED_PROPERTY, 671*29949e86Sstevel (caddr_t)&propval, &proplen) == DDI_PROP_SUCCESS) { 672*29949e86Sstevel cmn_err(CE_WARN, "Hot Plug Unavailable [%s]", propval); 673*29949e86Sstevel reg_fault(0, FT_HOT_PLUG, FT_SYSTEM); 674*29949e86Sstevel sysctrl_hotplug_disabled = TRUE; 675*29949e86Sstevel enable_sys_interrupt &= ~SYS_SBRD_PRES_EN; 676*29949e86Sstevel kmem_free(propval, proplen); 677*29949e86Sstevel } 678*29949e86Sstevel 679*29949e86Sstevel sysc_board_connect_supported_init(); 680*29949e86Sstevel 681*29949e86Sstevel fhc_bd_sc_register(sysc_policy_update, softsp); 682*29949e86Sstevel 683*29949e86Sstevel sysc_slot_info(softsp->nslots, &start, &limit, &incr); 684*29949e86Sstevel 685*29949e86Sstevel /* Prime the board list. */ 686*29949e86Sstevel fhc_bdlist_prime(start, limit, incr); 687*29949e86Sstevel 688*29949e86Sstevel /* 689*29949e86Sstevel * Set up a board remove timeout call. 690*29949e86Sstevel */ 691*29949e86Sstevel (void) fhc_bdlist_lock(-1); 692*29949e86Sstevel 693*29949e86Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, 694*29949e86Sstevel ("attach: start bd_remove_poll()...")); 695*29949e86Sstevel 696*29949e86Sstevel bd_remove_poll(softsp); 697*29949e86Sstevel fhc_bdlist_unlock(); 698*29949e86Sstevel 699*29949e86Sstevel /* 700*29949e86Sstevel * Now register low-level board insert handler 701*29949e86Sstevel */ 702*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_pres_id, 703*29949e86Sstevel NULL, NULL, bd_insert_handler, (caddr_t)softsp) != DDI_SUCCESS) 704*29949e86Sstevel goto bad13; 705*29949e86Sstevel 706*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_gone_id, 707*29949e86Sstevel NULL, NULL, bd_insert_normal, (caddr_t)softsp) != DDI_SUCCESS) 708*29949e86Sstevel goto bad14; 709*29949e86Sstevel 710*29949e86Sstevel /* 711*29949e86Sstevel * Now register led blink handler (interrupt level) 712*29949e86Sstevel */ 713*29949e86Sstevel if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->blink_led_id, 714*29949e86Sstevel &softsp->sys_led_c, NULL, blink_led_handler, (caddr_t)softsp) != 715*29949e86Sstevel DDI_SUCCESS) 716*29949e86Sstevel goto bad15; 717*29949e86Sstevel mutex_init(&softsp->sys_led_lock, NULL, MUTEX_DRIVER, 718*29949e86Sstevel (void *)softsp->sys_led_c); 719*29949e86Sstevel 720*29949e86Sstevel /* initialize the bit field for all pps fans to assumed good */ 721*29949e86Sstevel softsp->pps_fan_saved = softsp->pps_fan_external_state = 722*29949e86Sstevel SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK; 723*29949e86Sstevel 724*29949e86Sstevel /* prime the power supply state machines */ 725*29949e86Sstevel if (enable_sys_interrupt & SYS_PS_FAIL_EN) 726*29949e86Sstevel ddi_trigger_softintr(softsp->ps_fail_poll_id); 727*29949e86Sstevel 728*29949e86Sstevel 729*29949e86Sstevel /* kick off the OS led blinker */ 730*29949e86Sstevel softsp->sys_led = FALSE; 731*29949e86Sstevel ddi_trigger_softintr(softsp->blink_led_id); 732*29949e86Sstevel 733*29949e86Sstevel /* Now enable selected interrupt sources */ 734*29949e86Sstevel mutex_enter(&softsp->csr_mutex); 735*29949e86Sstevel *(softsp->csr) |= enable_sys_interrupt & 736*29949e86Sstevel (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN | 737*29949e86Sstevel SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN); 738*29949e86Sstevel tmp_reg = *(softsp->csr); 739*29949e86Sstevel #ifdef lint 740*29949e86Sstevel tmp_reg = tmp_reg; 741*29949e86Sstevel #endif 742*29949e86Sstevel mutex_exit(&softsp->csr_mutex); 743*29949e86Sstevel 744*29949e86Sstevel /* Initialize the temperature */ 745*29949e86Sstevel init_temp_arrays(&softsp->tempstat); 746*29949e86Sstevel 747*29949e86Sstevel /* 748*29949e86Sstevel * initialize key switch shadow state 749*29949e86Sstevel */ 750*29949e86Sstevel softsp->key_shadow = KEY_BOOT; 751*29949e86Sstevel 752*29949e86Sstevel /* 753*29949e86Sstevel * Now add this soft state structure to the front of the linked list 754*29949e86Sstevel * of soft state structures. 755*29949e86Sstevel */ 756*29949e86Sstevel if (sys_list == (struct sysctrl_soft_state *)NULL) { 757*29949e86Sstevel mutex_init(&sslist_mutex, NULL, MUTEX_DEFAULT, NULL); 758*29949e86Sstevel } 759*29949e86Sstevel mutex_enter(&sslist_mutex); 760*29949e86Sstevel softsp->next = sys_list; 761*29949e86Sstevel sys_list = softsp; 762*29949e86Sstevel mutex_exit(&sslist_mutex); 763*29949e86Sstevel 764*29949e86Sstevel /* Setup the kstats for this device */ 765*29949e86Sstevel sysctrl_add_kstats(softsp); 766*29949e86Sstevel 767*29949e86Sstevel /* kick off the PPS fan poll routine */ 768*29949e86Sstevel pps_fan_poll(softsp); 769*29949e86Sstevel 770*29949e86Sstevel if (sysctrl_overtemp_thread_started == 0) { 771*29949e86Sstevel /* 772*29949e86Sstevel * set up the overtemp condition variable before 773*29949e86Sstevel * starting the thread. 774*29949e86Sstevel */ 775*29949e86Sstevel cv_init(&overtemp_cv, NULL, CV_DRIVER, NULL); 776*29949e86Sstevel 777*29949e86Sstevel /* 778*29949e86Sstevel * start up the overtemp polling thread 779*29949e86Sstevel */ 780*29949e86Sstevel (void) thread_create(NULL, 0, (void (*)())sysctrl_overtemp_poll, 781*29949e86Sstevel NULL, 0, &p0, TS_RUN, minclsyspri); 782*29949e86Sstevel sysctrl_overtemp_thread_started++; 783*29949e86Sstevel } 784*29949e86Sstevel 785*29949e86Sstevel if (sysctrl_keyswitch_thread_started == 0) { 786*29949e86Sstevel extern void (*abort_seq_handler)(); 787*29949e86Sstevel 788*29949e86Sstevel /* 789*29949e86Sstevel * interpose sysctrl's abort sequence handler 790*29949e86Sstevel */ 791*29949e86Sstevel abort_seq_handler = sysctrl_abort_seq_handler; 792*29949e86Sstevel 793*29949e86Sstevel /* 794*29949e86Sstevel * set up the key switch condition variable before 795*29949e86Sstevel * starting the thread 796*29949e86Sstevel */ 797*29949e86Sstevel cv_init(&keyswitch_cv, NULL, CV_DRIVER, NULL); 798*29949e86Sstevel 799*29949e86Sstevel /* 800*29949e86Sstevel * start up the key switch polling thread 801*29949e86Sstevel */ 802*29949e86Sstevel (void) thread_create(NULL, 0, 803*29949e86Sstevel (void (*)())sysctrl_keyswitch_poll, NULL, 0, &p0, 804*29949e86Sstevel TS_RUN, minclsyspri); 805*29949e86Sstevel sysctrl_keyswitch_thread_started++; 806*29949e86Sstevel } 807*29949e86Sstevel 808*29949e86Sstevel /* 809*29949e86Sstevel * perform initialization to allow setting of powerfail-time 810*29949e86Sstevel */ 811*29949e86Sstevel if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL) 812*29949e86Sstevel softsp->options_nodeid = (pnode_t)NULL; 813*29949e86Sstevel else 814*29949e86Sstevel softsp->options_nodeid = (pnode_t)ddi_get_nodeid(dip); 815*29949e86Sstevel 816*29949e86Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, 817*29949e86Sstevel ("sysctrl: Creating devices start:%d, limit:%d, incr:%d\n", 818*29949e86Sstevel start, limit, incr)); 819*29949e86Sstevel 820*29949e86Sstevel /* 821*29949e86Sstevel * Create minor node for each system attachment points 822*29949e86Sstevel */ 823*29949e86Sstevel for (slot_num = start; slot_num < limit; slot_num = slot_num + incr) { 824*29949e86Sstevel char name[30]; 825*29949e86Sstevel (void) sprintf(name, "slot%d", slot_num); 826*29949e86Sstevel if (ddi_create_minor_node(devi, name, S_IFCHR, 827*29949e86Sstevel (PUTINSTANCE(instance) | slot_num), 828*29949e86Sstevel DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) { 829*29949e86Sstevel cmn_err(CE_WARN, "sysctrl%d: \"%s\" " 830*29949e86Sstevel "ddi_create_minor_node failed", 831*29949e86Sstevel instance, name); 832*29949e86Sstevel goto bad16; 833*29949e86Sstevel } 834*29949e86Sstevel } 835*29949e86Sstevel 836*29949e86Sstevel ddi_report_dev(devi); 837*29949e86Sstevel 838*29949e86Sstevel /* 839*29949e86Sstevel * Remote console is inherited from POST 840*29949e86Sstevel */ 841*29949e86Sstevel if ((*(softsp->clk_freq2) & RCONS_UART_EN) == 0) { 842*29949e86Sstevel softsp->enable_rcons_atboot = FALSE; 843*29949e86Sstevel cmn_err(CE_WARN, "Remote console not active"); 844*29949e86Sstevel } else 845*29949e86Sstevel softsp->enable_rcons_atboot = TRUE; 846*29949e86Sstevel 847*29949e86Sstevel return (DDI_SUCCESS); 848*29949e86Sstevel 849*29949e86Sstevel bad16: 850*29949e86Sstevel cv_destroy(&keyswitch_cv); 851*29949e86Sstevel cv_destroy(&overtemp_cv); 852*29949e86Sstevel mutex_destroy(&sslist_mutex); 853*29949e86Sstevel mutex_destroy(&softsp->sys_led_lock); 854*29949e86Sstevel ddi_remove_softintr(softsp->blink_led_id); 855*29949e86Sstevel bad15: 856*29949e86Sstevel ddi_remove_softintr(softsp->sbrd_gone_id); 857*29949e86Sstevel bad14: 858*29949e86Sstevel ddi_remove_softintr(softsp->sbrd_pres_id); 859*29949e86Sstevel bad13: 860*29949e86Sstevel ddi_remove_softintr(softsp->pps_fan_high_id); 861*29949e86Sstevel bad12: 862*29949e86Sstevel ddi_remove_softintr(softsp->pps_fan_id); 863*29949e86Sstevel bad11: 864*29949e86Sstevel ddi_remove_softintr(softsp->ps_fail_poll_id); 865*29949e86Sstevel bad10: 866*29949e86Sstevel mutex_destroy(&softsp->ps_fail_lock); 867*29949e86Sstevel ddi_remove_softintr(softsp->ps_fail_int_id); 868*29949e86Sstevel bad9: 869*29949e86Sstevel ddi_remove_softintr(softsp->ac_fail_high_id); 870*29949e86Sstevel bad8: 871*29949e86Sstevel ddi_remove_softintr(softsp->ac_fail_id); 872*29949e86Sstevel bad7: 873*29949e86Sstevel ddi_remove_softintr(softsp->spur_long_to_id); 874*29949e86Sstevel bad6: 875*29949e86Sstevel ddi_remove_softintr(softsp->spur_high_id); 876*29949e86Sstevel bad5: 877*29949e86Sstevel mutex_destroy(&softsp->spur_int_lock); 878*29949e86Sstevel ddi_remove_softintr(softsp->spur_id); 879*29949e86Sstevel bad4: 880*29949e86Sstevel ddi_remove_intr(devi, 0, softsp->iblock); 881*29949e86Sstevel bad3: 882*29949e86Sstevel mutex_destroy(&softsp->csr_mutex); 883*29949e86Sstevel bad2: 884*29949e86Sstevel ddi_unmap_regs(softsp->dip, 1, (caddr_t *)&softsp->csr, 0, 0); 885*29949e86Sstevel if (softsp->clk_ver != NULL) 886*29949e86Sstevel ddi_unmap_regs(softsp->dip, 2, (caddr_t *)&softsp->clk_ver, 887*29949e86Sstevel 0, 0); 888*29949e86Sstevel bad1: 889*29949e86Sstevel ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->clk_freq1, 0, 0); 890*29949e86Sstevel 891*29949e86Sstevel bad0: 892*29949e86Sstevel ddi_soft_state_free(sysctrlp, instance); 893*29949e86Sstevel ddi_remove_minor_node(dip, NULL); 894*29949e86Sstevel cmn_err(CE_WARN, 895*29949e86Sstevel "sysctrl%d: Initialization failure. Some system level events," 896*29949e86Sstevel " {AC Fail, Fan Failure, PS Failure} not detected", instance); 897*29949e86Sstevel return (DDI_FAILURE); 898*29949e86Sstevel } 899*29949e86Sstevel 900*29949e86Sstevel struct sysc_hold { 901*29949e86Sstevel int start; 902*29949e86Sstevel int limit; 903*29949e86Sstevel int incr; 904*29949e86Sstevel int hold; 905*29949e86Sstevel }; 906*29949e86Sstevel 907*29949e86Sstevel static int 908*29949e86Sstevel sysctrl_hold_rele_branches(dev_info_t *dip, void *arg) 909*29949e86Sstevel { 910*29949e86Sstevel int *rp, len, slot, i; 911*29949e86Sstevel struct sysc_hold *ap = (struct sysc_hold *)arg; 912*29949e86Sstevel 913*29949e86Sstevel /* 914*29949e86Sstevel * For Sunfire, top nodes on board are always children of root dip 915*29949e86Sstevel */ 916*29949e86Sstevel ASSERT(ddi_get_parent(dip) == ddi_root_node()); 917*29949e86Sstevel 918*29949e86Sstevel /* 919*29949e86Sstevel * Skip non-PROM and "central" nodes 920*29949e86Sstevel */ 921*29949e86Sstevel if (!ndi_dev_is_prom_node(dip) || 922*29949e86Sstevel strcmp(ddi_node_name(dip), "central") == 0) 923*29949e86Sstevel return (DDI_WALK_PRUNECHILD); 924*29949e86Sstevel 925*29949e86Sstevel /* 926*29949e86Sstevel * Extract board # from reg property. 927*29949e86Sstevel */ 928*29949e86Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 929*29949e86Sstevel DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", (caddr_t)&rp, &len) 930*29949e86Sstevel != DDI_SUCCESS) { 931*29949e86Sstevel DPRINTF(SYSC_DEBUG, ("devinfo node %s(%p) has no reg" 932*29949e86Sstevel " property\n", ddi_node_name(dip), (void *)dip)); 933*29949e86Sstevel return (DDI_WALK_PRUNECHILD); 934*29949e86Sstevel } 935*29949e86Sstevel 936*29949e86Sstevel slot = (*rp - 0x1c0) >> 2; 937*29949e86Sstevel kmem_free(rp, len); 938*29949e86Sstevel 939*29949e86Sstevel ASSERT(ap->start >= 0 && ap->start < ap->limit); 940*29949e86Sstevel 941*29949e86Sstevel for (i = ap->start; i < ap->limit; i = i + ap->incr) { 942*29949e86Sstevel if (i == slot) 943*29949e86Sstevel break; 944*29949e86Sstevel } 945*29949e86Sstevel 946*29949e86Sstevel if (i >= ap->limit) { 947*29949e86Sstevel DPRINTF(SYSC_DEBUG, ("sysctrl_hold_rele: Invalid board # (%d)" 948*29949e86Sstevel " for node %s(%p)\n", slot, ddi_node_name(dip), 949*29949e86Sstevel (void *)dip)); 950*29949e86Sstevel return (DDI_WALK_PRUNECHILD); 951*29949e86Sstevel } 952*29949e86Sstevel 953*29949e86Sstevel if (ap->hold) { 954*29949e86Sstevel ASSERT(!e_ddi_branch_held(dip)); 955*29949e86Sstevel e_ddi_branch_hold(dip); 956*29949e86Sstevel } else { 957*29949e86Sstevel ASSERT(e_ddi_branch_held(dip)); 958*29949e86Sstevel e_ddi_branch_rele(dip); 959*29949e86Sstevel } 960*29949e86Sstevel 961*29949e86Sstevel return (DDI_WALK_PRUNECHILD); 962*29949e86Sstevel } 963*29949e86Sstevel 964*29949e86Sstevel /* ARGSUSED */ 965*29949e86Sstevel static int 966*29949e86Sstevel sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 967*29949e86Sstevel { 968*29949e86Sstevel #ifdef SYSCTRL_SUPPORTS_DETACH 969*29949e86Sstevel dev_info_t *rdip; 970*29949e86Sstevel struct sysc_hold arg = {0}; 971*29949e86Sstevel struct sysctrl_soft_state *softsp; 972*29949e86Sstevel #endif /* SYSCTRL_SUPPORTS_DETACH */ 973*29949e86Sstevel 974*29949e86Sstevel if (sysctrl_enable_detach_suspend == FALSE) 975*29949e86Sstevel return (DDI_FAILURE); 976*29949e86Sstevel 977*29949e86Sstevel switch (cmd) { 978*29949e86Sstevel case DDI_SUSPEND: 979*29949e86Sstevel /* 980*29949e86Sstevel * XXX we don't presently save the state of the remote 981*29949e86Sstevel * console because it is a constant function of POST. 982*29949e86Sstevel * XXX we don't deal with the hardware watchdog here 983*29949e86Sstevel * either. It should be handled in hardclk. 984*29949e86Sstevel */ 985*29949e86Sstevel return (DDI_SUCCESS); 986*29949e86Sstevel 987*29949e86Sstevel case DDI_DETACH: 988*29949e86Sstevel break; 989*29949e86Sstevel default: 990*29949e86Sstevel return (DDI_FAILURE); 991*29949e86Sstevel } 992*29949e86Sstevel 993*29949e86Sstevel #ifdef SYSCTRL_SUPPORTS_DETACH 994*29949e86Sstevel 995*29949e86Sstevel /* 996*29949e86Sstevel * XXX If sysctrl ever supports detach, this code should be enabled 997*29949e86Sstevel * This is only the portion of the detach code dealing with 998*29949e86Sstevel * the DDI branch routines. Other parts of detach will need 999*29949e86Sstevel * to be added. 1000*29949e86Sstevel */ 1001*29949e86Sstevel 1002*29949e86Sstevel /* 1003*29949e86Sstevel * Walk immediate children of root devinfo node, releasing holds 1004*29949e86Sstevel * on branches acquired in first sysctrl_open(). 1005*29949e86Sstevel */ 1006*29949e86Sstevel 1007*29949e86Sstevel instance = ddi_get_instance(dip); 1008*29949e86Sstevel softsp = GETSOFTC(instance); 1009*29949e86Sstevel 1010*29949e86Sstevel if (softsp == NULL) { 1011*29949e86Sstevel cmn_err(CE_WARN, "sysctrl%d device not attached", instance); 1012*29949e86Sstevel return (DDI_FAILURE); 1013*29949e86Sstevel } 1014*29949e86Sstevel 1015*29949e86Sstevel sysc_slot_info(softsp->nslots, &arg.start, &arg.limit, &arg.incr); 1016*29949e86Sstevel 1017*29949e86Sstevel arg.hold = 0; 1018*29949e86Sstevel 1019*29949e86Sstevel rdip = ddi_root_node(); 1020*29949e86Sstevel 1021*29949e86Sstevel ndi_devi_enter(rdip, &circ); 1022*29949e86Sstevel ddi_walk_devs(ddi_get_child(rdip), sysctrl_hold_rele_branches, &arg); 1023*29949e86Sstevel ndi_devi_exit(rdip, circ); 1024*29949e86Sstevel 1025*29949e86Sstevel sysctrl_ddi_branch_init = 0; 1026*29949e86Sstevel 1027*29949e86Sstevel return (DDI_SUCCESS); 1028*29949e86Sstevel #endif /* SYSCTRL_SUPPORTS_DETACH */ 1029*29949e86Sstevel 1030*29949e86Sstevel return (DDI_FAILURE); 1031*29949e86Sstevel } 1032*29949e86Sstevel 1033*29949e86Sstevel /* ARGSUSED */ 1034*29949e86Sstevel static int 1035*29949e86Sstevel sysctrl_open(dev_t *devp, int flag, int otyp, cred_t *credp) 1036*29949e86Sstevel { 1037*29949e86Sstevel int instance; 1038*29949e86Sstevel int slot; 1039*29949e86Sstevel dev_t dev; 1040*29949e86Sstevel int circ; 1041*29949e86Sstevel dev_info_t *rdip; 1042*29949e86Sstevel struct sysc_hold arg = {0}; 1043*29949e86Sstevel struct sysctrl_soft_state *softsp; 1044*29949e86Sstevel 1045*29949e86Sstevel dev = *devp; 1046*29949e86Sstevel 1047*29949e86Sstevel /* 1048*29949e86Sstevel * We checked against the instance softstate structure since there 1049*29949e86Sstevel * will only be one instance of sysctrl (clock board) in UEXX00 1050*29949e86Sstevel * 1051*29949e86Sstevel * Since we only create minor devices for existing slots on a 1052*29949e86Sstevel * particular system, we don't need to worry about non-exist slot. 1053*29949e86Sstevel */ 1054*29949e86Sstevel 1055*29949e86Sstevel instance = GETINSTANCE(dev); 1056*29949e86Sstevel slot = GETSLOT(dev); 1057*29949e86Sstevel 1058*29949e86Sstevel /* Is the instance attached? */ 1059*29949e86Sstevel if ((softsp = GETSOFTC(instance)) == NULL) { 1060*29949e86Sstevel cmn_err(CE_WARN, "sysctrl%d device not attached", instance); 1061*29949e86Sstevel return (ENXIO); 1062*29949e86Sstevel } 1063*29949e86Sstevel 1064*29949e86Sstevel /* verify that otyp is appropriate */ 1065*29949e86Sstevel if (otyp != OTYP_CHR) { 1066*29949e86Sstevel return (EINVAL); 1067*29949e86Sstevel } 1068*29949e86Sstevel 1069*29949e86Sstevel if (!fhc_bd_valid(slot)) 1070*29949e86Sstevel return (ENXIO); 1071*29949e86Sstevel 1072*29949e86Sstevel /* 1073*29949e86Sstevel * On first open of a sysctrl minor walk immediate children of the 1074*29949e86Sstevel * devinfo root node and hold all branches of interest. 1075*29949e86Sstevel */ 1076*29949e86Sstevel mutex_enter(&sysctrl_branch_mutex); 1077*29949e86Sstevel if (!sysctrl_ddi_branch_init) { 1078*29949e86Sstevel 1079*29949e86Sstevel sysctrl_ddi_branch_init = 1; 1080*29949e86Sstevel 1081*29949e86Sstevel sysc_slot_info(softsp->nslots, &arg.start, &arg.limit, 1082*29949e86Sstevel &arg.incr); 1083*29949e86Sstevel arg.hold = 1; 1084*29949e86Sstevel 1085*29949e86Sstevel rdip = ddi_root_node(); 1086*29949e86Sstevel 1087*29949e86Sstevel ndi_devi_enter(rdip, &circ); 1088*29949e86Sstevel ddi_walk_devs(ddi_get_child(rdip), sysctrl_hold_rele_branches, 1089*29949e86Sstevel &arg); 1090*29949e86Sstevel ndi_devi_exit(rdip, circ); 1091*29949e86Sstevel } 1092*29949e86Sstevel mutex_exit(&sysctrl_branch_mutex); 1093*29949e86Sstevel 1094*29949e86Sstevel return (DDI_SUCCESS); 1095*29949e86Sstevel } 1096*29949e86Sstevel 1097*29949e86Sstevel /* ARGSUSED */ 1098*29949e86Sstevel static int 1099*29949e86Sstevel sysctrl_close(dev_t devp, int flag, int otyp, cred_t *credp) 1100*29949e86Sstevel { 1101*29949e86Sstevel return (DDI_SUCCESS); 1102*29949e86Sstevel } 1103*29949e86Sstevel 1104*29949e86Sstevel /* 1105*29949e86Sstevel * This function will acquire the lock and set the in_transition 1106*29949e86Sstevel * bit for the specified slot. If the slot is being used, 1107*29949e86Sstevel * we return FALSE; else set in_transition and return TRUE. 1108*29949e86Sstevel */ 1109*29949e86Sstevel static int 1110*29949e86Sstevel sysc_enter_transition(int slot) 1111*29949e86Sstevel { 1112*29949e86Sstevel fhc_bd_t *list; 1113*29949e86Sstevel sysc_cfga_stat_t *sysc_stat_lk; 1114*29949e86Sstevel fhc_bd_t *glist; 1115*29949e86Sstevel sysc_cfga_stat_t *sysc_stat_gk; 1116*29949e86Sstevel 1117*29949e86Sstevel /* mutex lock the structure */ 1118*29949e86Sstevel list = fhc_bdlist_lock(slot); 1119*29949e86Sstevel if ((slot != -1) && (list == NULL)) { 1120*29949e86Sstevel fhc_bdlist_unlock(); 1121*29949e86Sstevel return (FALSE); 1122*29949e86Sstevel } 1123*29949e86Sstevel 1124*29949e86Sstevel glist = fhc_bd_clock(); 1125*29949e86Sstevel if (slot == -1) 1126*29949e86Sstevel list = glist; 1127*29949e86Sstevel 1128*29949e86Sstevel /* change the in_transition bit */ 1129*29949e86Sstevel sysc_stat_lk = &list->sc; 1130*29949e86Sstevel sysc_stat_gk = &glist->sc; 1131*29949e86Sstevel if ((sysc_stat_lk->in_transition == TRUE) || 1132*29949e86Sstevel (sysc_stat_gk->in_transition == TRUE)) { 1133*29949e86Sstevel fhc_bdlist_unlock(); 1134*29949e86Sstevel return (FALSE); 1135*29949e86Sstevel } else { 1136*29949e86Sstevel sysc_stat_lk->in_transition = TRUE; 1137*29949e86Sstevel return (TRUE); 1138*29949e86Sstevel } 1139*29949e86Sstevel } 1140*29949e86Sstevel 1141*29949e86Sstevel /* 1142*29949e86Sstevel * This function will release the lock and clear the in_transition 1143*29949e86Sstevel * bit for the specified slot. 1144*29949e86Sstevel */ 1145*29949e86Sstevel static void 1146*29949e86Sstevel sysc_exit_transition(int slot) 1147*29949e86Sstevel { 1148*29949e86Sstevel fhc_bd_t *list; 1149*29949e86Sstevel sysc_cfga_stat_t *sysc_stat_lk; 1150*29949e86Sstevel 1151*29949e86Sstevel ASSERT(fhc_bdlist_locked()); 1152*29949e86Sstevel 1153*29949e86Sstevel if (slot == -1) 1154*29949e86Sstevel list = fhc_bd_clock(); 1155*29949e86Sstevel else 1156*29949e86Sstevel list = fhc_bd(slot); 1157*29949e86Sstevel sysc_stat_lk = &list->sc; 1158*29949e86Sstevel ASSERT(sysc_stat_lk->in_transition == TRUE); 1159*29949e86Sstevel sysc_stat_lk->in_transition = FALSE; 1160*29949e86Sstevel fhc_bdlist_unlock(); 1161*29949e86Sstevel } 1162*29949e86Sstevel 1163*29949e86Sstevel static int 1164*29949e86Sstevel sysc_pkt_init(sysc_cfga_pkt_t *pkt, intptr_t arg, int flag) 1165*29949e86Sstevel { 1166*29949e86Sstevel #ifdef _MULTI_DATAMODEL 1167*29949e86Sstevel if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) { 1168*29949e86Sstevel sysc_cfga_cmd32_t sysc_cmd32; 1169*29949e86Sstevel 1170*29949e86Sstevel if (ddi_copyin((void *)arg, &sysc_cmd32, 1171*29949e86Sstevel sizeof (sysc_cfga_cmd32_t), flag) != 0) { 1172*29949e86Sstevel return (EFAULT); 1173*29949e86Sstevel } 1174*29949e86Sstevel pkt->cmd_cfga.force = sysc_cmd32.force; 1175*29949e86Sstevel pkt->cmd_cfga.test = sysc_cmd32.test; 1176*29949e86Sstevel pkt->cmd_cfga.arg = sysc_cmd32.arg; 1177*29949e86Sstevel pkt->cmd_cfga.errtype = sysc_cmd32.errtype; 1178*29949e86Sstevel pkt->cmd_cfga.outputstr = 1179*29949e86Sstevel (char *)(uintptr_t)sysc_cmd32.outputstr; 1180*29949e86Sstevel } else 1181*29949e86Sstevel #endif /* _MULTI_DATAMODEL */ 1182*29949e86Sstevel if (ddi_copyin((void *)arg, &(pkt->cmd_cfga), 1183*29949e86Sstevel sizeof (sysc_cfga_cmd_t), flag) != 0) { 1184*29949e86Sstevel return (EFAULT); 1185*29949e86Sstevel } 1186*29949e86Sstevel pkt->errbuf = kmem_zalloc(SYSC_OUTPUT_LEN, KM_SLEEP); 1187*29949e86Sstevel return (0); 1188*29949e86Sstevel } 1189*29949e86Sstevel 1190*29949e86Sstevel static int 1191*29949e86Sstevel sysc_pkt_fini(sysc_cfga_pkt_t *pkt, intptr_t arg, int flag) 1192*29949e86Sstevel { 1193*29949e86Sstevel int ret = TRUE; 1194*29949e86Sstevel 1195*29949e86Sstevel #ifdef _MULTI_DATAMODEL 1196*29949e86Sstevel if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) { 1197*29949e86Sstevel 1198*29949e86Sstevel if (ddi_copyout(&(pkt->cmd_cfga.errtype), 1199*29949e86Sstevel (void *)&(((sysc_cfga_cmd32_t *)arg)->errtype), 1200*29949e86Sstevel sizeof (sysc_err_t), flag) != 0) { 1201*29949e86Sstevel ret = FALSE; 1202*29949e86Sstevel } 1203*29949e86Sstevel } else 1204*29949e86Sstevel #endif 1205*29949e86Sstevel if (ddi_copyout(&(pkt->cmd_cfga.errtype), 1206*29949e86Sstevel (void *)&(((sysc_cfga_cmd_t *)arg)->errtype), 1207*29949e86Sstevel sizeof (sysc_err_t), flag) != 0) { 1208*29949e86Sstevel ret = FALSE; 1209*29949e86Sstevel } 1210*29949e86Sstevel 1211*29949e86Sstevel if ((ret != FALSE) && ((pkt->cmd_cfga.outputstr != NULL) && 1212*29949e86Sstevel (ddi_copyout(pkt->errbuf, pkt->cmd_cfga.outputstr, 1213*29949e86Sstevel SYSC_OUTPUT_LEN, flag) != 0))) { 1214*29949e86Sstevel ret = FALSE; 1215*29949e86Sstevel } 1216*29949e86Sstevel 1217*29949e86Sstevel kmem_free(pkt->errbuf, SYSC_OUTPUT_LEN); 1218*29949e86Sstevel return (ret); 1219*29949e86Sstevel } 1220*29949e86Sstevel 1221*29949e86Sstevel /* ARGSUSED */ 1222*29949e86Sstevel static int 1223*29949e86Sstevel sysctrl_ioctl(dev_t devt, int cmd, intptr_t arg, int flag, cred_t *cred_p, 1224*29949e86Sstevel int *rval_p) 1225*29949e86Sstevel { 1226*29949e86Sstevel struct sysctrl_soft_state *softsp; 1227*29949e86Sstevel sysc_cfga_pkt_t sysc_pkt; 1228*29949e86Sstevel fhc_bd_t *fhc_list = NULL; 1229*29949e86Sstevel sysc_cfga_stat_t *sc_list = NULL; 1230*29949e86Sstevel fhc_bd_t *bdp; 1231*29949e86Sstevel sysc_cfga_stat_t *sc = NULL; 1232*29949e86Sstevel int instance; 1233*29949e86Sstevel int slot; 1234*29949e86Sstevel int retval = 0; 1235*29949e86Sstevel int i; 1236*29949e86Sstevel 1237*29949e86Sstevel instance = GETINSTANCE(devt); 1238*29949e86Sstevel softsp = GETSOFTC(instance); 1239*29949e86Sstevel if (softsp == NULL) { 1240*29949e86Sstevel cmn_err(CE_CONT, 1241*29949e86Sstevel "sysctrl_ioctl(%d): NULL softstate ptr!\n", 1242*29949e86Sstevel (int)GETSLOT(devt)); 1243*29949e86Sstevel return (ENXIO); 1244*29949e86Sstevel } 1245*29949e86Sstevel 1246*29949e86Sstevel slot = GETSLOT(devt); 1247*29949e86Sstevel 1248*29949e86Sstevel /* 1249*29949e86Sstevel * First switch is to do correct locking and do ddi_copyin() 1250*29949e86Sstevel */ 1251*29949e86Sstevel switch (cmd) { 1252*29949e86Sstevel case SYSC_CFGA_CMD_GETSTATUS: 1253*29949e86Sstevel /* mutex lock the whole list */ 1254*29949e86Sstevel if (sysc_enter_transition(-1) != TRUE) { 1255*29949e86Sstevel retval = EBUSY; 1256*29949e86Sstevel goto cleanup_exit; 1257*29949e86Sstevel } 1258*29949e86Sstevel 1259*29949e86Sstevel /* allocate the memory before acquiring mutex */ 1260*29949e86Sstevel fhc_list = kmem_zalloc(sizeof (fhc_bd_t) * fhc_max_boards(), 1261*29949e86Sstevel KM_SLEEP); 1262*29949e86Sstevel 1263*29949e86Sstevel sc_list = kmem_zalloc(sizeof (sysc_cfga_stat_t) * 1264*29949e86Sstevel fhc_max_boards(), KM_SLEEP); 1265*29949e86Sstevel 1266*29949e86Sstevel break; 1267*29949e86Sstevel 1268*29949e86Sstevel case SYSC_CFGA_CMD_EJECT: 1269*29949e86Sstevel case SYSC_CFGA_CMD_INSERT: 1270*29949e86Sstevel retval = ENOTSUP; 1271*29949e86Sstevel goto cleanup_exit; 1272*29949e86Sstevel 1273*29949e86Sstevel case SYSC_CFGA_CMD_CONNECT: 1274*29949e86Sstevel case SYSC_CFGA_CMD_DISCONNECT: 1275*29949e86Sstevel case SYSC_CFGA_CMD_UNCONFIGURE: 1276*29949e86Sstevel case SYSC_CFGA_CMD_CONFIGURE: 1277*29949e86Sstevel case SYSC_CFGA_CMD_TEST: 1278*29949e86Sstevel case SYSC_CFGA_CMD_TEST_SET_COND: 1279*29949e86Sstevel case SYSC_CFGA_CMD_QUIESCE_TEST: 1280*29949e86Sstevel 1281*29949e86Sstevel /* ioctls allowed if caller has write permission */ 1282*29949e86Sstevel if (!(flag & FWRITE)) { 1283*29949e86Sstevel retval = EPERM; 1284*29949e86Sstevel goto cleanup_exit; 1285*29949e86Sstevel } 1286*29949e86Sstevel 1287*29949e86Sstevel retval = sysc_pkt_init(&sysc_pkt, arg, flag); 1288*29949e86Sstevel if (retval != 0) 1289*29949e86Sstevel goto cleanup_exit; 1290*29949e86Sstevel 1291*29949e86Sstevel /* grasp lock and set in_transition bit */ 1292*29949e86Sstevel if (sysc_enter_transition(cmd == SYSC_CFGA_CMD_QUIESCE_TEST 1293*29949e86Sstevel ? -1 : slot) != TRUE) { 1294*29949e86Sstevel retval = EBUSY; 1295*29949e86Sstevel SYSC_ERR_SET(&sysc_pkt, SYSC_ERR_INTRANS); 1296*29949e86Sstevel goto cleanup_copyout; 1297*29949e86Sstevel } 1298*29949e86Sstevel 1299*29949e86Sstevel /* get the status structure for the slot */ 1300*29949e86Sstevel bdp = fhc_bd(slot); 1301*29949e86Sstevel sc = &bdp->sc; 1302*29949e86Sstevel break; 1303*29949e86Sstevel 1304*29949e86Sstevel /* POSIX definition: return ENOTTY if unsupported command */ 1305*29949e86Sstevel default: 1306*29949e86Sstevel retval = ENOTTY; 1307*29949e86Sstevel goto cleanup_exit; 1308*29949e86Sstevel } 1309*29949e86Sstevel 1310*29949e86Sstevel /* 1311*29949e86Sstevel * Second switch is to call the underlayer workhorse. 1312*29949e86Sstevel */ 1313*29949e86Sstevel switch (cmd) { 1314*29949e86Sstevel case SYSC_CFGA_CMD_GETSTATUS: 1315*29949e86Sstevel for (i = 0; i < fhc_max_boards(); i++) { 1316*29949e86Sstevel if (fhc_bd_valid(i)) { 1317*29949e86Sstevel bdp = fhc_bd(i); 1318*29949e86Sstevel if (fhc_bd_is_jtag_master(i)) 1319*29949e86Sstevel bdp->sc.no_detach = 1; 1320*29949e86Sstevel else 1321*29949e86Sstevel bdp->sc.no_detach = 0; 1322*29949e86Sstevel bcopy((caddr_t)&bdp->sc, 1323*29949e86Sstevel &sc_list[i], sizeof (sysc_cfga_stat_t)); 1324*29949e86Sstevel } else { 1325*29949e86Sstevel sc_list[i].board = -1; 1326*29949e86Sstevel sc_list[i].rstate = SYSC_CFGA_RSTATE_EMPTY; 1327*29949e86Sstevel } 1328*29949e86Sstevel } 1329*29949e86Sstevel 1330*29949e86Sstevel sysc_exit_transition(-1); 1331*29949e86Sstevel 1332*29949e86Sstevel break; 1333*29949e86Sstevel 1334*29949e86Sstevel case SYSC_CFGA_CMD_EJECT: 1335*29949e86Sstevel case SYSC_CFGA_CMD_INSERT: 1336*29949e86Sstevel retval = ENOTSUP; 1337*29949e86Sstevel goto cleanup_exit; 1338*29949e86Sstevel 1339*29949e86Sstevel case SYSC_CFGA_CMD_CONNECT: 1340*29949e86Sstevel retval = sysc_policy_connect(softsp, &sysc_pkt, sc); 1341*29949e86Sstevel sysc_exit_transition(slot); 1342*29949e86Sstevel break; 1343*29949e86Sstevel 1344*29949e86Sstevel case SYSC_CFGA_CMD_DISCONNECT: 1345*29949e86Sstevel retval = sysc_policy_disconnect(softsp, &sysc_pkt, sc); 1346*29949e86Sstevel sysc_exit_transition(slot); 1347*29949e86Sstevel break; 1348*29949e86Sstevel 1349*29949e86Sstevel case SYSC_CFGA_CMD_UNCONFIGURE: 1350*29949e86Sstevel retval = sysc_policy_unconfigure(softsp, &sysc_pkt, sc); 1351*29949e86Sstevel sysc_exit_transition(slot); 1352*29949e86Sstevel break; 1353*29949e86Sstevel 1354*29949e86Sstevel case SYSC_CFGA_CMD_CONFIGURE: 1355*29949e86Sstevel retval = sysc_policy_configure(softsp, &sysc_pkt, sc); 1356*29949e86Sstevel sysc_exit_transition(slot); 1357*29949e86Sstevel break; 1358*29949e86Sstevel 1359*29949e86Sstevel case SYSC_CFGA_CMD_TEST: 1360*29949e86Sstevel retval = fhc_bd_test(slot, &sysc_pkt); 1361*29949e86Sstevel sysc_exit_transition(slot); 1362*29949e86Sstevel break; 1363*29949e86Sstevel 1364*29949e86Sstevel case SYSC_CFGA_CMD_TEST_SET_COND: 1365*29949e86Sstevel retval = fhc_bd_test_set_cond(slot, &sysc_pkt); 1366*29949e86Sstevel sysc_exit_transition(slot); 1367*29949e86Sstevel break; 1368*29949e86Sstevel 1369*29949e86Sstevel case SYSC_CFGA_CMD_QUIESCE_TEST: 1370*29949e86Sstevel sysctrl_suspend_prepare(); 1371*29949e86Sstevel fhc_bdlist_unlock(); 1372*29949e86Sstevel 1373*29949e86Sstevel if (sysctrl_suspend(&sysc_pkt) == DDI_SUCCESS) { 1374*29949e86Sstevel sysctrl_resume(&sysc_pkt); 1375*29949e86Sstevel } else { 1376*29949e86Sstevel retval = EBUSY; 1377*29949e86Sstevel } 1378*29949e86Sstevel 1379*29949e86Sstevel (void) fhc_bdlist_lock(-1); 1380*29949e86Sstevel sysc_exit_transition(-1); 1381*29949e86Sstevel break; 1382*29949e86Sstevel 1383*29949e86Sstevel default: 1384*29949e86Sstevel retval = ENOTTY; 1385*29949e86Sstevel goto cleanup_exit; 1386*29949e86Sstevel } 1387*29949e86Sstevel 1388*29949e86Sstevel cleanup_copyout: 1389*29949e86Sstevel /* 1390*29949e86Sstevel * 3rd switch is to do appropriate copyout and reset locks 1391*29949e86Sstevel */ 1392*29949e86Sstevel switch (cmd) { 1393*29949e86Sstevel case SYSC_CFGA_CMD_GETSTATUS: 1394*29949e86Sstevel if (ddi_copyout(sc_list, (void *)arg, 1395*29949e86Sstevel sizeof (sysc_cfga_stat_t) * fhc_max_boards(), 1396*29949e86Sstevel flag) != 0) { 1397*29949e86Sstevel retval = EFAULT; 1398*29949e86Sstevel } 1399*29949e86Sstevel 1400*29949e86Sstevel /* cleanup memory */ 1401*29949e86Sstevel kmem_free(fhc_list, sizeof (fhc_bd_t) * fhc_max_boards()); 1402*29949e86Sstevel kmem_free(sc_list, sizeof (sysc_cfga_stat_t) * 1403*29949e86Sstevel fhc_max_boards()); 1404*29949e86Sstevel break; 1405*29949e86Sstevel 1406*29949e86Sstevel case SYSC_CFGA_CMD_EJECT: 1407*29949e86Sstevel case SYSC_CFGA_CMD_INSERT: 1408*29949e86Sstevel retval = ENOTSUP; 1409*29949e86Sstevel break; 1410*29949e86Sstevel 1411*29949e86Sstevel case SYSC_CFGA_CMD_CONNECT: 1412*29949e86Sstevel case SYSC_CFGA_CMD_DISCONNECT: 1413*29949e86Sstevel case SYSC_CFGA_CMD_UNCONFIGURE: 1414*29949e86Sstevel case SYSC_CFGA_CMD_CONFIGURE: 1415*29949e86Sstevel case SYSC_CFGA_CMD_TEST: 1416*29949e86Sstevel case SYSC_CFGA_CMD_TEST_SET_COND: 1417*29949e86Sstevel case SYSC_CFGA_CMD_QUIESCE_TEST: 1418*29949e86Sstevel if (sysc_pkt_fini(&sysc_pkt, arg, flag) != TRUE) 1419*29949e86Sstevel return (EFAULT); 1420*29949e86Sstevel break; 1421*29949e86Sstevel 1422*29949e86Sstevel default: 1423*29949e86Sstevel retval = ENOTTY; 1424*29949e86Sstevel break; 1425*29949e86Sstevel } 1426*29949e86Sstevel 1427*29949e86Sstevel cleanup_exit: 1428*29949e86Sstevel return (retval); 1429*29949e86Sstevel } 1430*29949e86Sstevel 1431*29949e86Sstevel /* 1432*29949e86Sstevel * system_high_handler() 1433*29949e86Sstevel * This routine handles system interrupts. 1434*29949e86Sstevel * 1435*29949e86Sstevel * This routine goes through all the interrupt sources and masks 1436*29949e86Sstevel * off the enable bit if interrupting. Because of the special 1437*29949e86Sstevel * nature of the pps fan source bits, we also cache the state 1438*29949e86Sstevel * of the fan bits for that special case. 1439*29949e86Sstevel * 1440*29949e86Sstevel * The rest of the work is done in the low level handlers 1441*29949e86Sstevel */ 1442*29949e86Sstevel static uint_t 1443*29949e86Sstevel system_high_handler(caddr_t arg) 1444*29949e86Sstevel { 1445*29949e86Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 1446*29949e86Sstevel uchar_t csr; 1447*29949e86Sstevel uchar_t status2; 1448*29949e86Sstevel uchar_t tmp_reg; 1449*29949e86Sstevel int serviced = 0; 1450*29949e86Sstevel 1451*29949e86Sstevel ASSERT(softsp); 1452*29949e86Sstevel 1453*29949e86Sstevel mutex_enter(&softsp->csr_mutex); 1454*29949e86Sstevel 1455*29949e86Sstevel /* read in the hardware registers */ 1456*29949e86Sstevel csr = *(softsp->csr); 1457*29949e86Sstevel status2 = *(softsp->status2); 1458*29949e86Sstevel 1459*29949e86Sstevel if (csr & SYS_AC_PWR_FAIL_EN) { 1460*29949e86Sstevel if (status2 & SYS_AC_FAIL) { 1461*29949e86Sstevel 1462*29949e86Sstevel /* save the powerfail state in nvram */ 1463*29949e86Sstevel nvram_update_powerfail(softsp); 1464*29949e86Sstevel 1465*29949e86Sstevel /* disable this interrupt source */ 1466*29949e86Sstevel csr &= ~SYS_AC_PWR_FAIL_EN; 1467*29949e86Sstevel 1468*29949e86Sstevel ddi_trigger_softintr(softsp->ac_fail_id); 1469*29949e86Sstevel serviced++; 1470*29949e86Sstevel } 1471*29949e86Sstevel } 1472*29949e86Sstevel 1473*29949e86Sstevel if (csr & SYS_PS_FAIL_EN) { 1474*29949e86Sstevel if ((*(softsp->ps_stat) != 0xff) || 1475*29949e86Sstevel ((~status2) & (SYS_PPS0_OK | SYS_CLK_33_OK | 1476*29949e86Sstevel SYS_CLK_50_OK)) || 1477*29949e86Sstevel (~(*(softsp->pppsr)) & SYS_PPPSR_BITS)) { 1478*29949e86Sstevel 1479*29949e86Sstevel /* disable this interrupt source */ 1480*29949e86Sstevel csr &= ~SYS_PS_FAIL_EN; 1481*29949e86Sstevel 1482*29949e86Sstevel ddi_trigger_softintr(softsp->ps_fail_int_id); 1483*29949e86Sstevel serviced++; 1484*29949e86Sstevel } 1485*29949e86Sstevel } 1486*29949e86Sstevel 1487*29949e86Sstevel if (csr & SYS_PPS_FAN_FAIL_EN) { 1488*29949e86Sstevel if (status2 & SYS_RACK_FANFAIL || 1489*29949e86Sstevel !(status2 & SYS_AC_FAN_OK) || 1490*29949e86Sstevel !(status2 & SYS_KEYSW_FAN_OK)) { 1491*29949e86Sstevel 1492*29949e86Sstevel /* 1493*29949e86Sstevel * we must cache the fan status because it goes 1494*29949e86Sstevel * away when we disable interrupts !?!?! 1495*29949e86Sstevel */ 1496*29949e86Sstevel softsp->pps_fan_saved = status2; 1497*29949e86Sstevel 1498*29949e86Sstevel /* disable this interrupt source */ 1499*29949e86Sstevel csr &= ~SYS_PPS_FAN_FAIL_EN; 1500*29949e86Sstevel 1501*29949e86Sstevel ddi_trigger_softintr(softsp->pps_fan_id); 1502*29949e86Sstevel serviced++; 1503*29949e86Sstevel } 1504*29949e86Sstevel } 1505*29949e86Sstevel 1506*29949e86Sstevel if (csr & SYS_SBRD_PRES_EN) { 1507*29949e86Sstevel if (!(*(softsp->status1) & SYS_NOT_BRD_PRES)) { 1508*29949e86Sstevel 1509*29949e86Sstevel /* disable this interrupt source */ 1510*29949e86Sstevel csr &= ~SYS_SBRD_PRES_EN; 1511*29949e86Sstevel 1512*29949e86Sstevel ddi_trigger_softintr(softsp->sbrd_pres_id); 1513*29949e86Sstevel serviced++; 1514*29949e86Sstevel } 1515*29949e86Sstevel } 1516*29949e86Sstevel 1517*29949e86Sstevel if (!serviced) { 1518*29949e86Sstevel 1519*29949e86Sstevel /* 1520*29949e86Sstevel * if we get here than it is likely that contact bounce 1521*29949e86Sstevel * is messing with us. so, we need to shut this interrupt 1522*29949e86Sstevel * up for a while to let the contacts settle down. 1523*29949e86Sstevel * Then we will re-enable the interrupts that are enabled 1524*29949e86Sstevel * right now. The trick is to disable the appropriate 1525*29949e86Sstevel * interrupts and then to re-enable them correctly, even 1526*29949e86Sstevel * though intervening handlers might have been working. 1527*29949e86Sstevel */ 1528*29949e86Sstevel 1529*29949e86Sstevel /* remember all interrupts that could have caused it */ 1530*29949e86Sstevel softsp->saved_en_state |= csr & 1531*29949e86Sstevel (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN | 1532*29949e86Sstevel SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN); 1533*29949e86Sstevel 1534*29949e86Sstevel /* and then turn them off */ 1535*29949e86Sstevel csr &= ~(SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN | 1536*29949e86Sstevel SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN); 1537*29949e86Sstevel 1538*29949e86Sstevel /* and then bump the counter */ 1539*29949e86Sstevel softsp->spur_count++; 1540*29949e86Sstevel 1541*29949e86Sstevel /* and kick off the timeout */ 1542*29949e86Sstevel ddi_trigger_softintr(softsp->spur_id); 1543*29949e86Sstevel } 1544*29949e86Sstevel 1545*29949e86Sstevel /* update the real csr */ 1546*29949e86Sstevel *(softsp->csr) = csr; 1547*29949e86Sstevel tmp_reg = *(softsp->csr); 1548*29949e86Sstevel #ifdef lint 1549*29949e86Sstevel tmp_reg = tmp_reg; 1550*29949e86Sstevel #endif 1551*29949e86Sstevel mutex_exit(&softsp->csr_mutex); 1552*29949e86Sstevel 1553*29949e86Sstevel return (DDI_INTR_CLAIMED); 1554*29949e86Sstevel } 1555*29949e86Sstevel 1556*29949e86Sstevel /* 1557*29949e86Sstevel * we've detected a spurious interrupt. 1558*29949e86Sstevel * determine if we should log a message and if we need another timeout 1559*29949e86Sstevel */ 1560*29949e86Sstevel static uint_t 1561*29949e86Sstevel spur_delay(caddr_t arg) 1562*29949e86Sstevel { 1563*29949e86Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 1564*29949e86Sstevel 1565*29949e86Sstevel ASSERT(softsp); 1566*29949e86Sstevel 1567*29949e86Sstevel /* do we need to complain? */ 1568*29949e86Sstevel mutex_enter(&softsp->csr_mutex); 1569*29949e86Sstevel 1570*29949e86Sstevel /* NOTE: this is == because we want one message per long timeout */ 1571*29949e86Sstevel if (softsp->spur_count == MAX_SPUR_COUNT) { 1572*29949e86Sstevel char buf[128]; 1573*29949e86Sstevel 1574*29949e86Sstevel /* print out the candidates known at this time */ 1575*29949e86Sstevel /* XXX not perfect because of re-entrant nature but close */ 1576*29949e86Sstevel buf[0] = '\0'; 1577*29949e86Sstevel if (softsp->saved_en_state & SYS_AC_PWR_FAIL_EN) 1578*29949e86Sstevel (void) strcat(buf, "AC FAIL"); 1579*29949e86Sstevel if (softsp->saved_en_state & SYS_PPS_FAN_FAIL_EN) 1580*29949e86Sstevel (void) strcat(buf, buf[0] ? "|PPS FANS" : "PPS FANS"); 1581*29949e86Sstevel if (softsp->saved_en_state & SYS_PS_FAIL_EN) 1582*29949e86Sstevel (void) strcat(buf, buf[0] ? "|PS FAIL" : "PS FAIL"); 1583*29949e86Sstevel if (softsp->saved_en_state & SYS_SBRD_PRES_EN) 1584*29949e86Sstevel (void) strcat(buf, 1585*29949e86Sstevel buf[0] ? "|BOARD INSERT" : "BOARD INSERT"); 1586*29949e86Sstevel 1587*29949e86Sstevel /* 1588*29949e86Sstevel * This is a high level mutex, therefore it needs to be 1589*29949e86Sstevel * dropped before calling cmn_err. 1590*29949e86Sstevel */ 1591*29949e86Sstevel mutex_exit(&softsp->csr_mutex); 1592*29949e86Sstevel 1593*29949e86Sstevel cmn_err(CE_WARN, "sysctrl%d: unserviced interrupt." 1594*29949e86Sstevel " possible sources [%s].", 1595*29949e86Sstevel ddi_get_instance(softsp->dip), buf); 1596*29949e86Sstevel } else 1597*29949e86Sstevel mutex_exit(&softsp->csr_mutex); 1598*29949e86Sstevel 1599*29949e86Sstevel mutex_enter(&softsp->spur_int_lock); 1600*29949e86Sstevel 1601*29949e86Sstevel /* do we need to start the short timeout? */ 1602*29949e86Sstevel if (softsp->spur_timeout_id == 0) { 1603*29949e86Sstevel softsp->spur_timeout_id = timeout(spur_retry, softsp, 1604*29949e86Sstevel spur_timeout_hz); 1605*29949e86Sstevel } 1606*29949e86Sstevel 1607*29949e86Sstevel /* do we need to start the long timeout? */ 1608*29949e86Sstevel if (softsp->spur_long_timeout_id == 0) { 1609*29949e86Sstevel softsp->spur_long_timeout_id = timeout(spur_long_timeout, 1610*29949e86Sstevel softsp, spur_long_timeout_hz); 1611*29949e86Sstevel } 1612*29949e86Sstevel 1613*29949e86Sstevel mutex_exit(&softsp->spur_int_lock); 1614*29949e86Sstevel 1615*29949e86Sstevel return (DDI_INTR_CLAIMED); 1616*29949e86Sstevel } 1617*29949e86Sstevel 1618*29949e86Sstevel /* 1619*29949e86Sstevel * spur_retry 1620*29949e86Sstevel * 1621*29949e86Sstevel * this routine simply triggers the interrupt which will re-enable 1622*29949e86Sstevel * the interrupts disabled by the spurious int detection. 1623*29949e86Sstevel */ 1624*29949e86Sstevel static void 1625*29949e86Sstevel spur_retry(void *arg) 1626*29949e86Sstevel { 1627*29949e86Sstevel struct sysctrl_soft_state *softsp = arg; 1628*29949e86Sstevel 1629*29949e86Sstevel ASSERT(softsp); 1630*29949e86Sstevel 1631*29949e86Sstevel ddi_trigger_softintr(softsp->spur_high_id); 1632*29949e86Sstevel 1633*29949e86Sstevel mutex_enter(&softsp->spur_int_lock); 1634*29949e86Sstevel softsp->spur_timeout_id = 0; 1635*29949e86Sstevel mutex_exit(&softsp->spur_int_lock); 1636*29949e86Sstevel } 1637*29949e86Sstevel 1638*29949e86Sstevel /* 1639*29949e86Sstevel * spur_reenable 1640*29949e86Sstevel * 1641*29949e86Sstevel * OK, we've been slient for a while. Go ahead and re-enable the 1642*29949e86Sstevel * interrupts that were enabled at the time of the spurious detection. 1643*29949e86Sstevel */ 1644*29949e86Sstevel static uint_t 1645*29949e86Sstevel spur_reenable(caddr_t arg) 1646*29949e86Sstevel { 1647*29949e86Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 1648*29949e86Sstevel uchar_t tmp_reg; 1649*29949e86Sstevel 1650*29949e86Sstevel ASSERT(softsp); 1651*29949e86Sstevel 1652*29949e86Sstevel mutex_enter(&softsp->csr_mutex); 1653*29949e86Sstevel 1654*29949e86Sstevel /* reenable those who were spurious candidates */ 1655*29949e86Sstevel *(softsp->csr) |= softsp->saved_en_state & 1656*29949e86Sstevel (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN | 1657*29949e86Sstevel SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN); 1658*29949e86Sstevel tmp_reg = *(softsp->csr); 1659*29949e86Sstevel #ifdef lint 1660*29949e86Sstevel tmp_reg = tmp_reg; 1661*29949e86Sstevel #endif 1662*29949e86Sstevel 1663*29949e86Sstevel /* clear out the saved state */ 1664*29949e86Sstevel softsp->saved_en_state = 0; 1665*29949e86Sstevel 1666*29949e86Sstevel mutex_exit(&softsp->csr_mutex); 1667*29949e86Sstevel 1668*29949e86Sstevel return (DDI_INTR_CLAIMED); 1669*29949e86Sstevel } 1670*29949e86Sstevel 1671*29949e86Sstevel /* 1672*29949e86Sstevel * spur_long_timeout 1673*29949e86Sstevel * 1674*29949e86Sstevel * this routine merely resets the spurious interrupt counter thus ending 1675*29949e86Sstevel * the interval of interest. of course this is done by triggering a 1676*29949e86Sstevel * softint because the counter is protected by an interrupt mutex. 1677*29949e86Sstevel */ 1678*29949e86Sstevel static void 1679*29949e86Sstevel spur_long_timeout(void *arg) 1680*29949e86Sstevel { 1681*29949e86Sstevel struct sysctrl_soft_state *softsp = arg; 1682*29949e86Sstevel 1683*29949e86Sstevel ASSERT(softsp); 1684*29949e86Sstevel 1685*29949e86Sstevel ddi_trigger_softintr(softsp->spur_long_to_id); 1686*29949e86Sstevel 1687*29949e86Sstevel mutex_enter(&softsp->spur_int_lock); 1688*29949e86Sstevel softsp->spur_long_timeout_id = 0; 1689*29949e86Sstevel mutex_exit(&softsp->spur_int_lock); 1690*29949e86Sstevel } 1691*29949e86Sstevel 1692*29949e86Sstevel /* 1693*29949e86Sstevel * spur_clear_count 1694*29949e86Sstevel * 1695*29949e86Sstevel * simply clear out the spurious interrupt counter. 1696*29949e86Sstevel * 1697*29949e86Sstevel * softint level only 1698*29949e86Sstevel */ 1699*29949e86Sstevel static uint_t 1700*29949e86Sstevel spur_clear_count(caddr_t arg) 1701*29949e86Sstevel { 1702*29949e86Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 1703*29949e86Sstevel 1704*29949e86Sstevel ASSERT(softsp); 1705*29949e86Sstevel 1706*29949e86Sstevel mutex_enter(&softsp->csr_mutex); 1707*29949e86Sstevel softsp->spur_count = 0; 1708*29949e86Sstevel mutex_exit(&softsp->csr_mutex); 1709*29949e86Sstevel 1710*29949e86Sstevel return (DDI_INTR_CLAIMED); 1711*29949e86Sstevel } 1712*29949e86Sstevel 1713*29949e86Sstevel /* 1714*29949e86Sstevel * ac_fail_handler 1715*29949e86Sstevel * 1716*29949e86Sstevel * This routine polls the AC power failure bit in the system status2 1717*29949e86Sstevel * register. If we get to this routine, then we sensed an ac fail 1718*29949e86Sstevel * condition. Note the fact and check again in a few. 1719*29949e86Sstevel * 1720*29949e86Sstevel * Called as softint from high interrupt. 1721*29949e86Sstevel */ 1722*29949e86Sstevel static uint_t 1723*29949e86Sstevel ac_fail_handler(caddr_t arg) 1724*29949e86Sstevel { 1725*29949e86Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 1726*29949e86Sstevel 1727*29949e86Sstevel ASSERT(softsp); 1728*29949e86Sstevel 1729*29949e86Sstevel cmn_err(CE_WARN, "%s failure detected", ft_str_table[FT_AC_PWR]); 1730*29949e86Sstevel reg_fault(0, FT_AC_PWR, FT_SYSTEM); 1731*29949e86Sstevel (void) timeout(ac_fail_retry, softsp, ac_timeout_hz); 1732*29949e86Sstevel 1733*29949e86Sstevel return (DDI_INTR_CLAIMED); 1734*29949e86Sstevel } 1735*29949e86Sstevel 1736*29949e86Sstevel /* 1737*29949e86Sstevel * The timeout from ac_fail_handler() that checks to see if the 1738*29949e86Sstevel * condition persists. 1739*29949e86Sstevel */ 1740*29949e86Sstevel static void 1741*29949e86Sstevel ac_fail_retry(void *arg) 1742*29949e86Sstevel { 1743*29949e86Sstevel struct sysctrl_soft_state *softsp = arg; 1744*29949e86Sstevel 1745*29949e86Sstevel ASSERT(softsp); 1746*29949e86Sstevel 1747*29949e86Sstevel if (*softsp->status2 & SYS_AC_FAIL) { /* still bad? */ 1748*29949e86Sstevel (void) timeout(ac_fail_retry, softsp, ac_timeout_hz); 1749*29949e86Sstevel } else { 1750*29949e86Sstevel cmn_err(CE_NOTE, "%s failure no longer detected", 1751*29949e86Sstevel ft_str_table[FT_AC_PWR]); 1752*29949e86Sstevel clear_fault(0, FT_AC_PWR, FT_SYSTEM); 1753*29949e86Sstevel ddi_trigger_softintr(softsp->ac_fail_high_id); 1754*29949e86Sstevel } 1755*29949e86Sstevel } 1756*29949e86Sstevel 1757*29949e86Sstevel /* 1758*29949e86Sstevel * The interrupt routine that we use to re-enable the interrupt. 1759*29949e86Sstevel * Called from ddi_trigger_softint() in the ac_fail_retry() when 1760*29949e86Sstevel * the AC is better. 1761*29949e86Sstevel */ 1762*29949e86Sstevel static uint_t 1763*29949e86Sstevel ac_fail_reenable(caddr_t arg) 1764*29949e86Sstevel { 1765*29949e86Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 1766*29949e86Sstevel uchar_t tmp_reg; 1767*29949e86Sstevel 1768*29949e86Sstevel ASSERT(softsp); 1769*29949e86Sstevel 1770*29949e86Sstevel mutex_enter(&softsp->csr_mutex); 1771*29949e86Sstevel *(softsp->csr) |= SYS_AC_PWR_FAIL_EN; 1772*29949e86Sstevel tmp_reg = *(softsp->csr); 1773*29949e86Sstevel #ifdef lint 1774*29949e86Sstevel tmp_reg = tmp_reg; 1775*29949e86Sstevel #endif 1776*29949e86Sstevel mutex_exit(&softsp->csr_mutex); 1777*29949e86Sstevel 1778*29949e86Sstevel return (DDI_INTR_CLAIMED); 1779*29949e86Sstevel } 1780*29949e86Sstevel 1781*29949e86Sstevel /* 1782*29949e86Sstevel * ps_fail_int_handler 1783*29949e86Sstevel * 1784*29949e86Sstevel * Handle power supply failure interrupt. 1785*29949e86Sstevel * 1786*29949e86Sstevel * This wrapper is called as softint from hardware interrupt routine. 1787*29949e86Sstevel */ 1788*29949e86Sstevel static uint_t 1789*29949e86Sstevel ps_fail_int_handler(caddr_t arg) 1790*29949e86Sstevel { 1791*29949e86Sstevel return (ps_fail_handler((struct sysctrl_soft_state *)arg, 1)); 1792*29949e86Sstevel } 1793*29949e86Sstevel 1794*29949e86Sstevel /* 1795*29949e86Sstevel * ps_fail_poll_handler 1796*29949e86Sstevel * 1797*29949e86Sstevel * Handle power supply failure interrupt. 1798*29949e86Sstevel * 1799*29949e86Sstevel * This wrapper is called as softint from power supply poll routine. 1800*29949e86Sstevel */ 1801*29949e86Sstevel static uint_t 1802*29949e86Sstevel ps_fail_poll_handler(caddr_t arg) 1803*29949e86Sstevel { 1804*29949e86Sstevel return (ps_fail_handler((struct sysctrl_soft_state *)arg, 0)); 1805*29949e86Sstevel } 1806*29949e86Sstevel 1807*29949e86Sstevel /* 1808*29949e86Sstevel * ps_fail_handler 1809*29949e86Sstevel * 1810*29949e86Sstevel * This routine checks all eight of the board power supplies that are 1811*29949e86Sstevel * installed plus the Peripheral power supply and the two DC OK. Since the 1812*29949e86Sstevel * hardware bits are not enough to indicate Power Supply failure 1813*29949e86Sstevel * vs. being turned off via software, the driver must maintain a 1814*29949e86Sstevel * shadow state for the Power Supply status and monitor all changes. 1815*29949e86Sstevel * 1816*29949e86Sstevel * Called as a softint only. 1817*29949e86Sstevel */ 1818*29949e86Sstevel static uint_t 1819*29949e86Sstevel ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint) 1820*29949e86Sstevel { 1821*29949e86Sstevel int i; 1822*29949e86Sstevel struct ps_state *pstatp; 1823*29949e86Sstevel int poll_needed = 0; 1824*29949e86Sstevel uchar_t ps_stat, ps_pres, status1, status2, pppsr; 1825*29949e86Sstevel uchar_t tmp_reg; 1826*29949e86Sstevel enum power_state current_power_state; 1827*29949e86Sstevel 1828*29949e86Sstevel ASSERT(softsp); 1829*29949e86Sstevel 1830*29949e86Sstevel /* pre-read the hardware state */ 1831*29949e86Sstevel ps_stat = *softsp->ps_stat; 1832*29949e86Sstevel ps_pres = *softsp->ps_pres; 1833*29949e86Sstevel status1 = *softsp->status1; 1834*29949e86Sstevel status2 = *softsp->status2; 1835*29949e86Sstevel pppsr = *softsp->pppsr; 1836*29949e86Sstevel 1837*29949e86Sstevel (void) fhc_bdlist_lock(-1); 1838*29949e86Sstevel 1839*29949e86Sstevel mutex_enter(&softsp->ps_fail_lock); 1840*29949e86Sstevel 1841*29949e86Sstevel for (i = 0, pstatp = &softsp->ps_stats[0]; i < SYS_PS_COUNT; 1842*29949e86Sstevel i++, pstatp++) { 1843*29949e86Sstevel int temp_psok; 1844*29949e86Sstevel int temp_pres; 1845*29949e86Sstevel int is_precharge = FALSE; 1846*29949e86Sstevel int is_fan_assy = FALSE; 1847*29949e86Sstevel 1848*29949e86Sstevel /* 1849*29949e86Sstevel * pre-compute the presence and ok bits for this 1850*29949e86Sstevel * power supply from the hardware registers. 1851*29949e86Sstevel * NOTE: 4-slot pps1 is the same as core ps 7... 1852*29949e86Sstevel */ 1853*29949e86Sstevel switch (i) { 1854*29949e86Sstevel /* the core power supplies */ 1855*29949e86Sstevel case 0: case 1: case 2: case 3: 1856*29949e86Sstevel case 4: case 5: case 6: case 7: 1857*29949e86Sstevel temp_pres = !((ps_pres >> i) & 0x1); 1858*29949e86Sstevel temp_psok = (ps_stat >> i) & 0x1; 1859*29949e86Sstevel break; 1860*29949e86Sstevel 1861*29949e86Sstevel /* the first peripheral power supply */ 1862*29949e86Sstevel case SYS_PPS0_INDEX: 1863*29949e86Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES); 1864*29949e86Sstevel temp_psok = status2 & SYS_PPS0_OK; 1865*29949e86Sstevel break; 1866*29949e86Sstevel 1867*29949e86Sstevel /* shared 3.3v clock power */ 1868*29949e86Sstevel case SYS_CLK_33_INDEX: 1869*29949e86Sstevel temp_pres = TRUE; 1870*29949e86Sstevel temp_psok = status2 & SYS_CLK_33_OK; 1871*29949e86Sstevel break; 1872*29949e86Sstevel 1873*29949e86Sstevel /* shared 5.0v clock power */ 1874*29949e86Sstevel case SYS_CLK_50_INDEX: 1875*29949e86Sstevel temp_pres = TRUE; 1876*29949e86Sstevel temp_psok = status2 & SYS_CLK_50_OK; 1877*29949e86Sstevel break; 1878*29949e86Sstevel 1879*29949e86Sstevel /* peripheral 5v */ 1880*29949e86Sstevel case SYS_V5_P_INDEX: 1881*29949e86Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES) || 1882*29949e86Sstevel ((IS4SLOT(softsp->nslots) || 1883*29949e86Sstevel IS5SLOT(softsp->nslots)) && 1884*29949e86Sstevel !(ps_pres & SYS_NOT_PPS1_PRES)); 1885*29949e86Sstevel temp_psok = pppsr & SYS_V5_P_OK; 1886*29949e86Sstevel break; 1887*29949e86Sstevel 1888*29949e86Sstevel /* peripheral 12v */ 1889*29949e86Sstevel case SYS_V12_P_INDEX: 1890*29949e86Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES) || 1891*29949e86Sstevel ((IS4SLOT(softsp->nslots) || 1892*29949e86Sstevel IS5SLOT(softsp->nslots)) && 1893*29949e86Sstevel !(ps_pres & SYS_NOT_PPS1_PRES)); 1894*29949e86Sstevel temp_psok = pppsr & SYS_V12_P_OK; 1895*29949e86Sstevel break; 1896*29949e86Sstevel 1897*29949e86Sstevel /* aux 5v */ 1898*29949e86Sstevel case SYS_V5_AUX_INDEX: 1899*29949e86Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES); 1900*29949e86Sstevel temp_psok = pppsr & SYS_V5_AUX_OK; 1901*29949e86Sstevel break; 1902*29949e86Sstevel 1903*29949e86Sstevel /* peripheral 5v precharge */ 1904*29949e86Sstevel case SYS_V5_P_PCH_INDEX: 1905*29949e86Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES); 1906*29949e86Sstevel temp_psok = pppsr & SYS_V5_P_PCH_OK; 1907*29949e86Sstevel is_precharge = TRUE; 1908*29949e86Sstevel break; 1909*29949e86Sstevel 1910*29949e86Sstevel /* peripheral 12v precharge */ 1911*29949e86Sstevel case SYS_V12_P_PCH_INDEX: 1912*29949e86Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES); 1913*29949e86Sstevel temp_psok = pppsr & SYS_V12_P_PCH_OK; 1914*29949e86Sstevel is_precharge = TRUE; 1915*29949e86Sstevel break; 1916*29949e86Sstevel 1917*29949e86Sstevel /* 3.3v precharge */ 1918*29949e86Sstevel case SYS_V3_PCH_INDEX: 1919*29949e86Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES); 1920*29949e86Sstevel temp_psok = pppsr & SYS_V3_PCH_OK; 1921*29949e86Sstevel is_precharge = TRUE; 1922*29949e86Sstevel break; 1923*29949e86Sstevel 1924*29949e86Sstevel /* 5v precharge */ 1925*29949e86Sstevel case SYS_V5_PCH_INDEX: 1926*29949e86Sstevel temp_pres = !(status1 & SYS_NOT_PPS0_PRES); 1927*29949e86Sstevel temp_psok = pppsr & SYS_V5_PCH_OK; 1928*29949e86Sstevel is_precharge = TRUE; 1929*29949e86Sstevel break; 1930*29949e86Sstevel 1931*29949e86Sstevel /* peripheral fan assy */ 1932*29949e86Sstevel case SYS_P_FAN_INDEX: 1933*29949e86Sstevel temp_pres = (IS4SLOT(softsp->nslots) || 1934*29949e86Sstevel IS5SLOT(softsp->nslots)) && 1935*29949e86Sstevel !(status1 & SYS_NOT_P_FAN_PRES); 1936*29949e86Sstevel temp_psok = softsp->pps_fan_saved & 1937*29949e86Sstevel SYS_AC_FAN_OK; 1938*29949e86Sstevel is_fan_assy = TRUE; 1939*29949e86Sstevel break; 1940*29949e86Sstevel } 1941*29949e86Sstevel 1942*29949e86Sstevel /* *** Phase 1 -- power supply presence tests *** */ 1943*29949e86Sstevel 1944*29949e86Sstevel /* do we know the presence status for this power supply? */ 1945*29949e86Sstevel if (pstatp->pshadow == PRES_UNKNOWN) { 1946*29949e86Sstevel pstatp->pshadow = temp_pres ? PRES_IN : PRES_OUT; 1947*29949e86Sstevel pstatp->dcshadow = temp_pres ? PS_BOOT : PS_OUT; 1948*29949e86Sstevel } else { 1949*29949e86Sstevel /* has the ps presence state changed? */ 1950*29949e86Sstevel if (!temp_pres ^ (pstatp->pshadow == PRES_IN)) { 1951*29949e86Sstevel pstatp->pctr = 0; 1952*29949e86Sstevel } else { 1953*29949e86Sstevel /* a change! are we counting? */ 1954*29949e86Sstevel if (pstatp->pctr == 0) { 1955*29949e86Sstevel pstatp->pctr = PS_PRES_CHANGE_TICKS; 1956*29949e86Sstevel } else if (--pstatp->pctr == 0) { 1957*29949e86Sstevel pstatp->pshadow = temp_pres ? 1958*29949e86Sstevel PRES_IN : PRES_OUT; 1959*29949e86Sstevel pstatp->dcshadow = temp_pres ? 1960*29949e86Sstevel PS_UNKNOWN : PS_OUT; 1961*29949e86Sstevel 1962*29949e86Sstevel /* 1963*29949e86Sstevel * Now we know the state has 1964*29949e86Sstevel * changed, so we should log it. 1965*29949e86Sstevel */ 1966*29949e86Sstevel ps_log_pres_change(softsp, 1967*29949e86Sstevel i, temp_pres); 1968*29949e86Sstevel } 1969*29949e86Sstevel } 1970*29949e86Sstevel } 1971*29949e86Sstevel 1972*29949e86Sstevel /* *** Phase 2 -- power supply status tests *** */ 1973*29949e86Sstevel 1974*29949e86Sstevel /* check if the Power Supply is removed or same as before */ 1975*29949e86Sstevel if ((pstatp->dcshadow == PS_OUT) || 1976*29949e86Sstevel ((pstatp->dcshadow == PS_OK) && temp_psok) || 1977*29949e86Sstevel ((pstatp->dcshadow == PS_FAIL) && !temp_psok)) { 1978*29949e86Sstevel pstatp->dcctr = 0; 1979*29949e86Sstevel } else { 1980*29949e86Sstevel 1981*29949e86Sstevel /* OK, a change, do we start the timer? */ 1982*29949e86Sstevel if (pstatp->dcctr == 0) { 1983*29949e86Sstevel switch (pstatp->dcshadow) { 1984*29949e86Sstevel case PS_BOOT: 1985*29949e86Sstevel pstatp->dcctr = PS_FROM_BOOT_TICKS; 1986*29949e86Sstevel break; 1987*29949e86Sstevel 1988*29949e86Sstevel case PS_UNKNOWN: 1989*29949e86Sstevel pstatp->dcctr = is_fan_assy ? 1990*29949e86Sstevel PS_P_FAN_FROM_UNKNOWN_TICKS : 1991*29949e86Sstevel PS_FROM_UNKNOWN_TICKS; 1992*29949e86Sstevel break; 1993*29949e86Sstevel 1994*29949e86Sstevel case PS_OK: 1995*29949e86Sstevel pstatp->dcctr = is_precharge ? 1996*29949e86Sstevel PS_PCH_FROM_OK_TICKS : 1997*29949e86Sstevel PS_FROM_OK_TICKS; 1998*29949e86Sstevel break; 1999*29949e86Sstevel 2000*29949e86Sstevel case PS_FAIL: 2001*29949e86Sstevel pstatp->dcctr = PS_FROM_FAIL_TICKS; 2002*29949e86Sstevel break; 2003*29949e86Sstevel 2004*29949e86Sstevel default: 2005*29949e86Sstevel panic("sysctrl%d: Unknown Power " 2006*29949e86Sstevel "Supply State %d", pstatp->dcshadow, 2007*29949e86Sstevel ddi_get_instance(softsp->dip)); 2008*29949e86Sstevel } 2009*29949e86Sstevel } 2010*29949e86Sstevel 2011*29949e86Sstevel /* has the ticker expired? */ 2012*29949e86Sstevel if (--pstatp->dcctr == 0) { 2013*29949e86Sstevel 2014*29949e86Sstevel /* we'll skip OK messages during boot */ 2015*29949e86Sstevel if (!((pstatp->dcshadow == PS_BOOT) && 2016*29949e86Sstevel temp_psok)) { 2017*29949e86Sstevel ps_log_state_change(softsp, 2018*29949e86Sstevel i, temp_psok); 2019*29949e86Sstevel } 2020*29949e86Sstevel 2021*29949e86Sstevel /* 2022*29949e86Sstevel * remote console interface has to be 2023*29949e86Sstevel * reinitialized on the rising edge V5_AUX 2024*29949e86Sstevel * when it is NOT boot. At the boot time an 2025*29949e86Sstevel * an error condition exists if it was not 2026*29949e86Sstevel * enabled before. 2027*29949e86Sstevel */ 2028*29949e86Sstevel if ((i == SYS_V5_AUX_INDEX) && 2029*29949e86Sstevel (pstatp->dcshadow != PS_BOOT) && 2030*29949e86Sstevel (softsp->enable_rcons_atboot)) { 2031*29949e86Sstevel if (temp_psok) 2032*29949e86Sstevel rcons_reinit(softsp); 2033*29949e86Sstevel else 2034*29949e86Sstevel /* disable rconsole */ 2035*29949e86Sstevel *(softsp->clk_freq2) &= 2036*29949e86Sstevel ~RCONS_UART_EN; 2037*29949e86Sstevel tmp_reg = *(softsp->csr); 2038*29949e86Sstevel #ifdef lint 2039*29949e86Sstevel tmp_reg = tmp_reg; 2040*29949e86Sstevel #endif 2041*29949e86Sstevel 2042*29949e86Sstevel } 2043*29949e86Sstevel 2044*29949e86Sstevel /* regardless, update the shadow state */ 2045*29949e86Sstevel pstatp->dcshadow = temp_psok ? PS_OK : PS_FAIL; 2046*29949e86Sstevel 2047*29949e86Sstevel /* always update board condition */ 2048*29949e86Sstevel sysc_policy_update(softsp, NULL, 2049*29949e86Sstevel SYSC_EVT_BD_PS_CHANGE); 2050*29949e86Sstevel 2051*29949e86Sstevel } 2052*29949e86Sstevel } 2053*29949e86Sstevel 2054*29949e86Sstevel /* 2055*29949e86Sstevel * We will need to continue polling for three reasons: 2056*29949e86Sstevel * - a failing power supply is detected and we haven't yet 2057*29949e86Sstevel * determined the power supplies existence. 2058*29949e86Sstevel * - the power supply is just installed and we're waiting 2059*29949e86Sstevel * to give it a change to power up, 2060*29949e86Sstevel * - a failed power supply state is recognized 2061*29949e86Sstevel * 2062*29949e86Sstevel * NOTE: PS_FAIL shadow state is not the same as !temp_psok 2063*29949e86Sstevel * because of the persistence of PS_FAIL->PS_OK. 2064*29949e86Sstevel */ 2065*29949e86Sstevel if (!temp_psok || 2066*29949e86Sstevel (pstatp->dcshadow == PS_UNKNOWN) || 2067*29949e86Sstevel (pstatp->dcshadow == PS_FAIL)) { 2068*29949e86Sstevel poll_needed++; 2069*29949e86Sstevel } 2070*29949e86Sstevel } 2071*29949e86Sstevel 2072*29949e86Sstevel /* 2073*29949e86Sstevel * Now, get the current power state for this instance. 2074*29949e86Sstevel * If the current state is different than what was known, complain. 2075*29949e86Sstevel */ 2076*29949e86Sstevel current_power_state = compute_power_state(softsp, 0); 2077*29949e86Sstevel 2078*29949e86Sstevel if (softsp->power_state != current_power_state) { 2079*29949e86Sstevel switch (current_power_state) { 2080*29949e86Sstevel case BELOW_MINIMUM: 2081*29949e86Sstevel cmn_err(CE_WARN, 2082*29949e86Sstevel "Insufficient power available to system"); 2083*29949e86Sstevel if (!disable_insufficient_power_reboot) { 2084*29949e86Sstevel cmn_err(CE_WARN, "System reboot in %d seconds", 2085*29949e86Sstevel PS_INSUFFICIENT_COUNTDOWN_SEC); 2086*29949e86Sstevel } 2087*29949e86Sstevel reg_fault(1, FT_INSUFFICIENT_POWER, FT_SYSTEM); 2088*29949e86Sstevel softsp->power_countdown = PS_POWER_COUNTDOWN_TICKS; 2089*29949e86Sstevel break; 2090*29949e86Sstevel 2091*29949e86Sstevel case MINIMUM: 2092*29949e86Sstevel /* If we came from REDUNDANT, complain */ 2093*29949e86Sstevel if (softsp->power_state == REDUNDANT) { 2094*29949e86Sstevel cmn_err(CE_WARN, "Redundant power lost"); 2095*29949e86Sstevel /* If we came from BELOW_MINIMUM, hurrah! */ 2096*29949e86Sstevel } else if (softsp->power_state == BELOW_MINIMUM) { 2097*29949e86Sstevel cmn_err(CE_NOTE, "Minimum power available"); 2098*29949e86Sstevel clear_fault(1, FT_INSUFFICIENT_POWER, 2099*29949e86Sstevel FT_SYSTEM); 2100*29949e86Sstevel } 2101*29949e86Sstevel break; 2102*29949e86Sstevel 2103*29949e86Sstevel case REDUNDANT: 2104*29949e86Sstevel /* If we aren't from boot, spread the good news */ 2105*29949e86Sstevel if (softsp->power_state != BOOT) { 2106*29949e86Sstevel cmn_err(CE_NOTE, "Redundant power available"); 2107*29949e86Sstevel clear_fault(1, FT_INSUFFICIENT_POWER, 2108*29949e86Sstevel FT_SYSTEM); 2109*29949e86Sstevel } 2110*29949e86Sstevel break; 2111*29949e86Sstevel 2112*29949e86Sstevel default: 2113*29949e86Sstevel break; 2114*29949e86Sstevel } 2115*29949e86Sstevel softsp->power_state = current_power_state; 2116*29949e86Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE); 2117*29949e86Sstevel } 2118*29949e86Sstevel 2119*29949e86Sstevel mutex_exit(&softsp->ps_fail_lock); 2120*29949e86Sstevel 2121*29949e86Sstevel fhc_bdlist_unlock(); 2122*29949e86Sstevel 2123*29949e86Sstevel /* 2124*29949e86Sstevel * Are we in insufficient powerstate? 2125*29949e86Sstevel * If so, is it time to take action? 2126*29949e86Sstevel */ 2127*29949e86Sstevel if (softsp->power_state == BELOW_MINIMUM && 2128*29949e86Sstevel softsp->power_countdown > 0 && --(softsp->power_countdown) == 0 && 2129*29949e86Sstevel !disable_insufficient_power_reboot) { 2130*29949e86Sstevel cmn_err(CE_WARN, 2131*29949e86Sstevel "Insufficient power. System Reboot Started..."); 2132*29949e86Sstevel 2133*29949e86Sstevel fhc_reboot(); 2134*29949e86Sstevel } 2135*29949e86Sstevel 2136*29949e86Sstevel /* 2137*29949e86Sstevel * If we don't have ps problems that need to be polled for, then 2138*29949e86Sstevel * enable interrupts. 2139*29949e86Sstevel */ 2140*29949e86Sstevel if (!poll_needed) { 2141*29949e86Sstevel mutex_enter(&softsp->csr_mutex); 2142*29949e86Sstevel *(softsp->csr) |= SYS_PS_FAIL_EN; 2143*29949e86Sstevel tmp_reg = *(softsp->csr); 2144*29949e86Sstevel #ifdef lint 2145*29949e86Sstevel tmp_reg = tmp_reg; 2146*29949e86Sstevel #endif 2147*29949e86Sstevel mutex_exit(&softsp->csr_mutex); 2148*29949e86Sstevel } 2149*29949e86Sstevel 2150*29949e86Sstevel /* 2151*29949e86Sstevel * Only the polling loop re-triggers the polling loop timeout 2152*29949e86Sstevel */ 2153*29949e86Sstevel if (!fromint) { 2154*29949e86Sstevel (void) timeout(ps_fail_retry, softsp, ps_fail_timeout_hz); 2155*29949e86Sstevel } 2156*29949e86Sstevel 2157*29949e86Sstevel return (DDI_INTR_CLAIMED); 2158*29949e86Sstevel } 2159*29949e86Sstevel 2160*29949e86Sstevel /* 2161*29949e86Sstevel * Compute the current power configuration for this system. 2162*29949e86Sstevel * Disk boards and Clock boards are not counted. 2163*29949e86Sstevel * 2164*29949e86Sstevel * This function must be called with the ps_fail_lock held. 2165*29949e86Sstevel */ 2166*29949e86Sstevel enum power_state 2167*29949e86Sstevel compute_power_state(struct sysctrl_soft_state *softsp, int plus_load) 2168*29949e86Sstevel { 2169*29949e86Sstevel int i; 2170*29949e86Sstevel int ok_supply_count = 0; 2171*29949e86Sstevel int load_count = 0; 2172*29949e86Sstevel int minimum_power_count; 2173*29949e86Sstevel int pps_ok; 2174*29949e86Sstevel fhc_bd_t *list; 2175*29949e86Sstevel 2176*29949e86Sstevel ASSERT(mutex_owned(&softsp->ps_fail_lock)); 2177*29949e86Sstevel 2178*29949e86Sstevel /* 2179*29949e86Sstevel * Walk down the interesting power supplies and 2180*29949e86Sstevel * count the operational power units 2181*29949e86Sstevel */ 2182*29949e86Sstevel for (i = 0; i < 8; i++) { 2183*29949e86Sstevel /* 2184*29949e86Sstevel * power supply id 7 on a 4 or 5 slot system is PPS1. 2185*29949e86Sstevel * don't include it in the redundant core power calculation. 2186*29949e86Sstevel */ 2187*29949e86Sstevel if (i == 7 && 2188*29949e86Sstevel (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots))) 2189*29949e86Sstevel continue; 2190*29949e86Sstevel 2191*29949e86Sstevel if (softsp->ps_stats[i].dcshadow == PS_OK) 2192*29949e86Sstevel ok_supply_count++; 2193*29949e86Sstevel } 2194*29949e86Sstevel 2195*29949e86Sstevel /* Note the state of the PPS... */ 2196*29949e86Sstevel pps_ok = (softsp->ps_stats[SYS_PPS0_INDEX].dcshadow == PS_OK); 2197*29949e86Sstevel 2198*29949e86Sstevel /* 2199*29949e86Sstevel * Dynamically compute the load count in the system. 2200*29949e86Sstevel * Don't count disk boards or boards in low power state. 2201*29949e86Sstevel */ 2202*29949e86Sstevel for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) { 2203*29949e86Sstevel ASSERT(list->sc.type != CLOCK_BOARD); 2204*29949e86Sstevel if (list->sc.rstate == SYSC_CFGA_RSTATE_CONNECTED) { 2205*29949e86Sstevel load_count++; 2206*29949e86Sstevel } 2207*29949e86Sstevel } 2208*29949e86Sstevel 2209*29949e86Sstevel load_count += plus_load; 2210*29949e86Sstevel /* 2211*29949e86Sstevel * If we are 8 slot and we have 7 or 8 boards, then the PPS 2212*29949e86Sstevel * can count as a power supply... 2213*29949e86Sstevel */ 2214*29949e86Sstevel if (IS8SLOT(softsp->nslots) && load_count >= 7 && pps_ok) 2215*29949e86Sstevel ok_supply_count++; 2216*29949e86Sstevel 2217*29949e86Sstevel /* 2218*29949e86Sstevel * This is to cover the corner case of a UE3500 having 5 2219*29949e86Sstevel * boards installed and still giving it N+1 power status. 2220*29949e86Sstevel */ 2221*29949e86Sstevel if (IS5SLOT(softsp->nslots) && (load_count >= 5)) 2222*29949e86Sstevel ok_supply_count++; 2223*29949e86Sstevel 2224*29949e86Sstevel /* 2225*29949e86Sstevel * Determine our power situation. This is a simple step 2226*29949e86Sstevel * function right now: 2227*29949e86Sstevel * 2228*29949e86Sstevel * minimum power count = min(7, floor((board count + 1) / 2)) 2229*29949e86Sstevel */ 2230*29949e86Sstevel minimum_power_count = (load_count + 1) / 2; 2231*29949e86Sstevel if (minimum_power_count > 7) 2232*29949e86Sstevel minimum_power_count = 7; 2233*29949e86Sstevel 2234*29949e86Sstevel if (ok_supply_count > minimum_power_count) 2235*29949e86Sstevel return (REDUNDANT); 2236*29949e86Sstevel else if (ok_supply_count == minimum_power_count) 2237*29949e86Sstevel return (MINIMUM); 2238*29949e86Sstevel else 2239*29949e86Sstevel return (BELOW_MINIMUM); 2240*29949e86Sstevel } 2241*29949e86Sstevel 2242*29949e86Sstevel /* 2243*29949e86Sstevel * log the change of power supply presence 2244*29949e86Sstevel */ 2245*29949e86Sstevel static void 2246*29949e86Sstevel ps_log_pres_change(struct sysctrl_soft_state *softsp, int index, int present) 2247*29949e86Sstevel { 2248*29949e86Sstevel char *trans = present ? "Installed" : "Removed"; 2249*29949e86Sstevel 2250*29949e86Sstevel switch (index) { 2251*29949e86Sstevel /* the core power supplies (except for 7) */ 2252*29949e86Sstevel case 0: case 1: case 2: case 3: 2253*29949e86Sstevel case 4: case 5: case 6: 2254*29949e86Sstevel cmn_err(CE_NOTE, "%s %d %s", ft_str_table[FT_CORE_PS], index, 2255*29949e86Sstevel trans); 2256*29949e86Sstevel if (!present) { 2257*29949e86Sstevel clear_fault(index, FT_CORE_PS, FT_SYSTEM); 2258*29949e86Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE); 2259*29949e86Sstevel } 2260*29949e86Sstevel break; 2261*29949e86Sstevel 2262*29949e86Sstevel /* power supply 7 / pps 1 */ 2263*29949e86Sstevel case 7: 2264*29949e86Sstevel if (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)) { 2265*29949e86Sstevel cmn_err(CE_NOTE, "%s 1 %s", ft_str_table[FT_PPS], trans); 2266*29949e86Sstevel if (!present) { 2267*29949e86Sstevel clear_fault(1, FT_PPS, FT_SYSTEM); 2268*29949e86Sstevel } 2269*29949e86Sstevel } else { 2270*29949e86Sstevel cmn_err(CE_NOTE, "%s %d %s", ft_str_table[FT_CORE_PS], 2271*29949e86Sstevel index, trans); 2272*29949e86Sstevel if (!present) { 2273*29949e86Sstevel clear_fault(7, FT_CORE_PS, FT_SYSTEM); 2274*29949e86Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE); 2275*29949e86Sstevel } 2276*29949e86Sstevel } 2277*29949e86Sstevel break; 2278*29949e86Sstevel 2279*29949e86Sstevel /* the peripheral power supply 0 */ 2280*29949e86Sstevel case SYS_PPS0_INDEX: 2281*29949e86Sstevel cmn_err(CE_NOTE, "%s 0 %s", ft_str_table[FT_PPS], trans); 2282*29949e86Sstevel if (!present) { 2283*29949e86Sstevel clear_fault(0, FT_PPS, FT_SYSTEM); 2284*29949e86Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE); 2285*29949e86Sstevel } 2286*29949e86Sstevel break; 2287*29949e86Sstevel 2288*29949e86Sstevel /* the peripheral rack fan assy */ 2289*29949e86Sstevel case SYS_P_FAN_INDEX: 2290*29949e86Sstevel cmn_err(CE_NOTE, "%s %s", ft_str_table[FT_PPS_FAN], trans); 2291*29949e86Sstevel if (!present) { 2292*29949e86Sstevel clear_fault(0, FT_PPS_FAN, FT_SYSTEM); 2293*29949e86Sstevel } 2294*29949e86Sstevel break; 2295*29949e86Sstevel 2296*29949e86Sstevel /* we don't mention a change of presence state for any other power */ 2297*29949e86Sstevel } 2298*29949e86Sstevel } 2299*29949e86Sstevel 2300*29949e86Sstevel /* 2301*29949e86Sstevel * log the change of power supply status 2302*29949e86Sstevel */ 2303*29949e86Sstevel static void 2304*29949e86Sstevel ps_log_state_change(struct sysctrl_soft_state *softsp, int index, int ps_ok) 2305*29949e86Sstevel { 2306*29949e86Sstevel int level = ps_ok ? CE_NOTE : CE_WARN; 2307*29949e86Sstevel char *s = ps_ok ? "OK" : "Failing"; 2308*29949e86Sstevel 2309*29949e86Sstevel switch (index) { 2310*29949e86Sstevel /* the core power supplies (except 7) */ 2311*29949e86Sstevel case 0: case 1: case 2: case 3: 2312*29949e86Sstevel case 4: case 5: case 6: 2313*29949e86Sstevel cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS], index, s); 2314*29949e86Sstevel if (ps_ok) { 2315*29949e86Sstevel clear_fault(index, FT_CORE_PS, FT_SYSTEM); 2316*29949e86Sstevel } else { 2317*29949e86Sstevel reg_fault(index, FT_CORE_PS, FT_SYSTEM); 2318*29949e86Sstevel } 2319*29949e86Sstevel break; 2320*29949e86Sstevel 2321*29949e86Sstevel /* power supply 7 / pps 1 */ 2322*29949e86Sstevel case 7: 2323*29949e86Sstevel if (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)) { 2324*29949e86Sstevel cmn_err(level, "%s 1 %s", ft_str_table[FT_PPS], s); 2325*29949e86Sstevel if (ps_ok) { 2326*29949e86Sstevel clear_fault(1, FT_PPS, FT_SYSTEM); 2327*29949e86Sstevel } else { 2328*29949e86Sstevel reg_fault(1, FT_PPS, FT_SYSTEM); 2329*29949e86Sstevel } 2330*29949e86Sstevel } else { 2331*29949e86Sstevel cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS], 2332*29949e86Sstevel index, s); 2333*29949e86Sstevel if (ps_ok) { 2334*29949e86Sstevel clear_fault(index, FT_CORE_PS, FT_SYSTEM); 2335*29949e86Sstevel } else { 2336*29949e86Sstevel reg_fault(index, FT_CORE_PS, FT_SYSTEM); 2337*29949e86Sstevel } 2338*29949e86Sstevel } 2339*29949e86Sstevel break; 2340*29949e86Sstevel 2341*29949e86Sstevel /* the peripheral power supply */ 2342*29949e86Sstevel case SYS_PPS0_INDEX: 2343*29949e86Sstevel cmn_err(level, "%s %s", ft_str_table[FT_PPS], s); 2344*29949e86Sstevel if (ps_ok) { 2345*29949e86Sstevel clear_fault(0, FT_PPS, FT_SYSTEM); 2346*29949e86Sstevel } else { 2347*29949e86Sstevel reg_fault(0, FT_PPS, FT_SYSTEM); 2348*29949e86Sstevel } 2349*29949e86Sstevel break; 2350*29949e86Sstevel 2351*29949e86Sstevel /* shared 3.3v clock power */ 2352*29949e86Sstevel case SYS_CLK_33_INDEX: 2353*29949e86Sstevel cmn_err(level, "%s %s", ft_str_table[FT_CLK_33], s); 2354*29949e86Sstevel if (ps_ok) { 2355*29949e86Sstevel clear_fault(0, FT_CLK_33, FT_SYSTEM); 2356*29949e86Sstevel } else { 2357*29949e86Sstevel reg_fault(0, FT_CLK_33, FT_SYSTEM); 2358*29949e86Sstevel } 2359*29949e86Sstevel break; 2360*29949e86Sstevel 2361*29949e86Sstevel /* shared 5.0v clock power */ 2362*29949e86Sstevel case SYS_CLK_50_INDEX: 2363*29949e86Sstevel cmn_err(level, "%s %s", ft_str_table[FT_CLK_50], s); 2364*29949e86Sstevel if (ps_ok) { 2365*29949e86Sstevel clear_fault(0, FT_CLK_50, FT_SYSTEM); 2366*29949e86Sstevel } else { 2367*29949e86Sstevel reg_fault(0, FT_CLK_50, FT_SYSTEM); 2368*29949e86Sstevel } 2369*29949e86Sstevel break; 2370*29949e86Sstevel 2371*29949e86Sstevel /* peripheral 5v */ 2372*29949e86Sstevel case SYS_V5_P_INDEX: 2373*29949e86Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_P], s); 2374*29949e86Sstevel if (ps_ok) { 2375*29949e86Sstevel clear_fault(0, FT_V5_P, FT_SYSTEM); 2376*29949e86Sstevel } else { 2377*29949e86Sstevel reg_fault(0, FT_V5_P, FT_SYSTEM); 2378*29949e86Sstevel } 2379*29949e86Sstevel break; 2380*29949e86Sstevel 2381*29949e86Sstevel /* peripheral 12v */ 2382*29949e86Sstevel case SYS_V12_P_INDEX: 2383*29949e86Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V12_P], s); 2384*29949e86Sstevel if (ps_ok) { 2385*29949e86Sstevel clear_fault(0, FT_V12_P, FT_SYSTEM); 2386*29949e86Sstevel } else { 2387*29949e86Sstevel reg_fault(0, FT_V12_P, FT_SYSTEM); 2388*29949e86Sstevel } 2389*29949e86Sstevel break; 2390*29949e86Sstevel 2391*29949e86Sstevel /* aux 5v */ 2392*29949e86Sstevel case SYS_V5_AUX_INDEX: 2393*29949e86Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_AUX], s); 2394*29949e86Sstevel if (ps_ok) { 2395*29949e86Sstevel clear_fault(0, FT_V5_AUX, FT_SYSTEM); 2396*29949e86Sstevel } else { 2397*29949e86Sstevel reg_fault(0, FT_V5_AUX, FT_SYSTEM); 2398*29949e86Sstevel } 2399*29949e86Sstevel break; 2400*29949e86Sstevel 2401*29949e86Sstevel /* peripheral 5v precharge */ 2402*29949e86Sstevel case SYS_V5_P_PCH_INDEX: 2403*29949e86Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_P_PCH], s); 2404*29949e86Sstevel if (ps_ok) { 2405*29949e86Sstevel clear_fault(0, FT_V5_P_PCH, FT_SYSTEM); 2406*29949e86Sstevel } else { 2407*29949e86Sstevel reg_fault(0, FT_V5_P_PCH, FT_SYSTEM); 2408*29949e86Sstevel } 2409*29949e86Sstevel break; 2410*29949e86Sstevel 2411*29949e86Sstevel /* peripheral 12v precharge */ 2412*29949e86Sstevel case SYS_V12_P_PCH_INDEX: 2413*29949e86Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V12_P_PCH], s); 2414*29949e86Sstevel if (ps_ok) { 2415*29949e86Sstevel clear_fault(0, FT_V12_P_PCH, FT_SYSTEM); 2416*29949e86Sstevel } else { 2417*29949e86Sstevel reg_fault(0, FT_V12_P_PCH, FT_SYSTEM); 2418*29949e86Sstevel } 2419*29949e86Sstevel break; 2420*29949e86Sstevel 2421*29949e86Sstevel /* 3.3v precharge */ 2422*29949e86Sstevel case SYS_V3_PCH_INDEX: 2423*29949e86Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V3_PCH], s); 2424*29949e86Sstevel if (ps_ok) { 2425*29949e86Sstevel clear_fault(0, FT_V3_PCH, FT_SYSTEM); 2426*29949e86Sstevel } else { 2427*29949e86Sstevel reg_fault(0, FT_V3_PCH, FT_SYSTEM); 2428*29949e86Sstevel } 2429*29949e86Sstevel break; 2430*29949e86Sstevel 2431*29949e86Sstevel /* 5v precharge */ 2432*29949e86Sstevel case SYS_V5_PCH_INDEX: 2433*29949e86Sstevel cmn_err(level, "%s %s", ft_str_table[FT_V5_PCH], s); 2434*29949e86Sstevel if (ps_ok) { 2435*29949e86Sstevel clear_fault(0, FT_V5_PCH, FT_SYSTEM); 2436*29949e86Sstevel } else { 2437*29949e86Sstevel reg_fault(0, FT_V5_PCH, FT_SYSTEM); 2438*29949e86Sstevel } 2439*29949e86Sstevel break; 2440*29949e86Sstevel 2441*29949e86Sstevel /* peripheral power supply fans */ 2442*29949e86Sstevel case SYS_P_FAN_INDEX: 2443*29949e86Sstevel cmn_err(level, "%s %s", ft_str_table[FT_PPS_FAN], s); 2444*29949e86Sstevel if (ps_ok) { 2445*29949e86Sstevel clear_fault(0, FT_PPS_FAN, FT_SYSTEM); 2446*29949e86Sstevel } else { 2447*29949e86Sstevel reg_fault(0, FT_PPS_FAN, FT_SYSTEM); 2448*29949e86Sstevel } 2449*29949e86Sstevel break; 2450*29949e86Sstevel } 2451*29949e86Sstevel } 2452*29949e86Sstevel 2453*29949e86Sstevel /* 2454*29949e86Sstevel * The timeout from ps_fail_handler() that simply re-triggers a check 2455*29949e86Sstevel * of the ps condition. 2456*29949e86Sstevel */ 2457*29949e86Sstevel static void 2458*29949e86Sstevel ps_fail_retry(void *arg) 2459*29949e86Sstevel { 2460*29949e86Sstevel struct sysctrl_soft_state *softsp = arg; 2461*29949e86Sstevel 2462*29949e86Sstevel ASSERT(softsp); 2463*29949e86Sstevel 2464*29949e86Sstevel ddi_trigger_softintr(softsp->ps_fail_poll_id); 2465*29949e86Sstevel } 2466*29949e86Sstevel 2467*29949e86Sstevel /* 2468*29949e86Sstevel * pps_fanfail_handler 2469*29949e86Sstevel * 2470*29949e86Sstevel * This routine is called from the high level handler. 2471*29949e86Sstevel */ 2472*29949e86Sstevel static uint_t 2473*29949e86Sstevel pps_fanfail_handler(caddr_t arg) 2474*29949e86Sstevel { 2475*29949e86Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 2476*29949e86Sstevel 2477*29949e86Sstevel ASSERT(softsp); 2478*29949e86Sstevel 2479*29949e86Sstevel /* always check again in a bit by re-enabling the fan interrupt */ 2480*29949e86Sstevel (void) timeout(pps_fanfail_retry, softsp, pps_fan_timeout_hz); 2481*29949e86Sstevel 2482*29949e86Sstevel return (DDI_INTR_CLAIMED); 2483*29949e86Sstevel } 2484*29949e86Sstevel 2485*29949e86Sstevel /* 2486*29949e86Sstevel * After a bit of waiting, we simply re-enable the interrupt to 2487*29949e86Sstevel * see if we get another one. The softintr triggered routine does 2488*29949e86Sstevel * the dirty work for us since it runs in the interrupt context. 2489*29949e86Sstevel */ 2490*29949e86Sstevel static void 2491*29949e86Sstevel pps_fanfail_retry(void *arg) 2492*29949e86Sstevel { 2493*29949e86Sstevel struct sysctrl_soft_state *softsp = arg; 2494*29949e86Sstevel 2495*29949e86Sstevel ASSERT(softsp); 2496*29949e86Sstevel 2497*29949e86Sstevel ddi_trigger_softintr(softsp->pps_fan_high_id); 2498*29949e86Sstevel } 2499*29949e86Sstevel 2500*29949e86Sstevel /* 2501*29949e86Sstevel * The other half of the retry handler run from the interrupt context 2502*29949e86Sstevel */ 2503*29949e86Sstevel static uint_t 2504*29949e86Sstevel pps_fanfail_reenable(caddr_t arg) 2505*29949e86Sstevel { 2506*29949e86Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 2507*29949e86Sstevel uchar_t tmp_reg; 2508*29949e86Sstevel 2509*29949e86Sstevel ASSERT(softsp); 2510*29949e86Sstevel 2511*29949e86Sstevel mutex_enter(&softsp->csr_mutex); 2512*29949e86Sstevel 2513*29949e86Sstevel /* 2514*29949e86Sstevel * re-initialize the bit field for all pps fans to assumed good. 2515*29949e86Sstevel * If the fans are still bad, we're going to get an immediate system 2516*29949e86Sstevel * interrupt which will put the correct state back anyway. 2517*29949e86Sstevel * 2518*29949e86Sstevel * NOTE: the polling routines that use this state understand the 2519*29949e86Sstevel * pulse resulting from above... 2520*29949e86Sstevel */ 2521*29949e86Sstevel softsp->pps_fan_saved = SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK; 2522*29949e86Sstevel 2523*29949e86Sstevel *(softsp->csr) |= SYS_PPS_FAN_FAIL_EN; 2524*29949e86Sstevel tmp_reg = *(softsp->csr); 2525*29949e86Sstevel #ifdef lint 2526*29949e86Sstevel tmp_reg = tmp_reg; 2527*29949e86Sstevel #endif 2528*29949e86Sstevel mutex_exit(&softsp->csr_mutex); 2529*29949e86Sstevel 2530*29949e86Sstevel return (DDI_INTR_CLAIMED); 2531*29949e86Sstevel } 2532*29949e86Sstevel 2533*29949e86Sstevel /* 2534*29949e86Sstevel * 2535*29949e86Sstevel * Poll the hardware shadow state to determine the pps fan status. 2536*29949e86Sstevel * The shadow state is maintained by the system_high handler and its 2537*29949e86Sstevel * associated pps_* functions (above). 2538*29949e86Sstevel * 2539*29949e86Sstevel * There is a short time interval where the shadow state is pulsed to 2540*29949e86Sstevel * the OK state even when the fans are bad. However, this polling 2541*29949e86Sstevel * routine has some built in hysteresis to filter out those _normal_ 2542*29949e86Sstevel * events. 2543*29949e86Sstevel */ 2544*29949e86Sstevel static void 2545*29949e86Sstevel pps_fan_poll(void *arg) 2546*29949e86Sstevel { 2547*29949e86Sstevel struct sysctrl_soft_state *softsp = arg; 2548*29949e86Sstevel int i; 2549*29949e86Sstevel 2550*29949e86Sstevel ASSERT(softsp); 2551*29949e86Sstevel 2552*29949e86Sstevel for (i = 0; i < SYS_PPS_FAN_COUNT; i++) { 2553*29949e86Sstevel int fanfail = FALSE; 2554*29949e86Sstevel 2555*29949e86Sstevel /* determine fan status */ 2556*29949e86Sstevel switch (i) { 2557*29949e86Sstevel case RACK: 2558*29949e86Sstevel fanfail = softsp->pps_fan_saved & SYS_RACK_FANFAIL; 2559*29949e86Sstevel break; 2560*29949e86Sstevel 2561*29949e86Sstevel case AC: 2562*29949e86Sstevel /* 2563*29949e86Sstevel * Don't bother polling the AC fan on 4 and 5 slot 2564*29949e86Sstevel * systems. 2565*29949e86Sstevel * Rather, it is handled by the power supply loop. 2566*29949e86Sstevel */ 2567*29949e86Sstevel fanfail = !(IS4SLOT(softsp->nslots) || 2568*29949e86Sstevel IS5SLOT(softsp->nslots)) && 2569*29949e86Sstevel !(softsp->pps_fan_saved & SYS_AC_FAN_OK); 2570*29949e86Sstevel break; 2571*29949e86Sstevel 2572*29949e86Sstevel case KEYSW: 2573*29949e86Sstevel /* 2574*29949e86Sstevel * This signal is not usable if aux5v is missing 2575*29949e86Sstevel * so we will synthesize a failed fan when aux5v 2576*29949e86Sstevel * fails or when pps0 is out. 2577*29949e86Sstevel * The 4 and 5 slot systems behave the same. 2578*29949e86Sstevel */ 2579*29949e86Sstevel fanfail = (!(IS4SLOT(softsp->nslots) || 2580*29949e86Sstevel IS5SLOT(softsp->nslots)) && 2581*29949e86Sstevel (softsp->ps_stats[SYS_V5_AUX_INDEX].dcshadow != 2582*29949e86Sstevel PS_OK)) || 2583*29949e86Sstevel !(softsp->pps_fan_saved & SYS_KEYSW_FAN_OK); 2584*29949e86Sstevel break; 2585*29949e86Sstevel 2586*29949e86Sstevel } 2587*29949e86Sstevel 2588*29949e86Sstevel /* is the fan bad? */ 2589*29949e86Sstevel if (fanfail) { 2590*29949e86Sstevel 2591*29949e86Sstevel /* is this condition different than we know? */ 2592*29949e86Sstevel if (softsp->pps_fan_state_count[i] == 0) { 2593*29949e86Sstevel 2594*29949e86Sstevel /* log the change to failed */ 2595*29949e86Sstevel pps_fan_state_change(softsp, i, FALSE); 2596*29949e86Sstevel } 2597*29949e86Sstevel 2598*29949e86Sstevel /* always restart the fan OK counter */ 2599*29949e86Sstevel softsp->pps_fan_state_count[i] = PPS_FROM_FAIL_TICKS; 2600*29949e86Sstevel } else { 2601*29949e86Sstevel 2602*29949e86Sstevel /* do we currently know the fan is bad? */ 2603*29949e86Sstevel if (softsp->pps_fan_state_count[i]) { 2604*29949e86Sstevel 2605*29949e86Sstevel /* yes, but has it been stable? */ 2606*29949e86Sstevel if (--softsp->pps_fan_state_count[i] == 0) { 2607*29949e86Sstevel 2608*29949e86Sstevel /* log the change to OK */ 2609*29949e86Sstevel pps_fan_state_change(softsp, i, TRUE); 2610*29949e86Sstevel } 2611*29949e86Sstevel } 2612*29949e86Sstevel } 2613*29949e86Sstevel } 2614*29949e86Sstevel 2615*29949e86Sstevel /* always check again in a bit by re-enabling the fan interrupt */ 2616*29949e86Sstevel (void) timeout(pps_fan_poll, softsp, pps_fan_timeout_hz); 2617*29949e86Sstevel } 2618*29949e86Sstevel 2619*29949e86Sstevel /* 2620*29949e86Sstevel * pps_fan_state_change() 2621*29949e86Sstevel * 2622*29949e86Sstevel * Log the changed fan condition and update the external status. 2623*29949e86Sstevel */ 2624*29949e86Sstevel static void 2625*29949e86Sstevel pps_fan_state_change(struct sysctrl_soft_state *softsp, int index, int fan_ok) 2626*29949e86Sstevel { 2627*29949e86Sstevel char *fan_type; 2628*29949e86Sstevel char *state = fan_ok ? "fans OK" : "fan failure detected"; 2629*29949e86Sstevel 2630*29949e86Sstevel switch (index) { 2631*29949e86Sstevel case RACK: 2632*29949e86Sstevel /* 4 and 5 slot systems behave the same */ 2633*29949e86Sstevel fan_type = (IS4SLOT(softsp->nslots) || 2634*29949e86Sstevel IS5SLOT(softsp->nslots)) ? 2635*29949e86Sstevel "Disk Drive" : "Rack Exhaust"; 2636*29949e86Sstevel if (fan_ok) { 2637*29949e86Sstevel softsp->pps_fan_external_state &= ~SYS_RACK_FANFAIL; 2638*29949e86Sstevel clear_fault(0, (IS4SLOT(softsp->nslots) || 2639*29949e86Sstevel IS5SLOT(softsp->nslots)) ? FT_DSK_FAN : 2640*29949e86Sstevel FT_RACK_EXH, FT_SYSTEM); 2641*29949e86Sstevel } else { 2642*29949e86Sstevel softsp->pps_fan_external_state |= SYS_RACK_FANFAIL; 2643*29949e86Sstevel reg_fault(0, (IS4SLOT(softsp->nslots) || 2644*29949e86Sstevel IS5SLOT(softsp->nslots)) ? FT_DSK_FAN : 2645*29949e86Sstevel FT_RACK_EXH, FT_SYSTEM); 2646*29949e86Sstevel } 2647*29949e86Sstevel break; 2648*29949e86Sstevel 2649*29949e86Sstevel case AC: 2650*29949e86Sstevel fan_type = "AC Box"; 2651*29949e86Sstevel if (fan_ok) { 2652*29949e86Sstevel softsp->pps_fan_external_state |= SYS_AC_FAN_OK; 2653*29949e86Sstevel clear_fault(0, FT_AC_FAN, FT_SYSTEM); 2654*29949e86Sstevel } else { 2655*29949e86Sstevel softsp->pps_fan_external_state &= ~SYS_AC_FAN_OK; 2656*29949e86Sstevel reg_fault(0, FT_AC_FAN, FT_SYSTEM); 2657*29949e86Sstevel } 2658*29949e86Sstevel break; 2659*29949e86Sstevel 2660*29949e86Sstevel case KEYSW: 2661*29949e86Sstevel fan_type = "Keyswitch"; 2662*29949e86Sstevel if (fan_ok) { 2663*29949e86Sstevel softsp->pps_fan_external_state |= SYS_KEYSW_FAN_OK; 2664*29949e86Sstevel clear_fault(0, FT_KEYSW_FAN, FT_SYSTEM); 2665*29949e86Sstevel } else { 2666*29949e86Sstevel softsp->pps_fan_external_state &= ~SYS_KEYSW_FAN_OK; 2667*29949e86Sstevel reg_fault(0, FT_KEYSW_FAN, FT_SYSTEM); 2668*29949e86Sstevel } 2669*29949e86Sstevel break; 2670*29949e86Sstevel default: 2671*29949e86Sstevel fan_type = "[invalid fan id]"; 2672*29949e86Sstevel break; 2673*29949e86Sstevel } 2674*29949e86Sstevel 2675*29949e86Sstevel /* now log the state change */ 2676*29949e86Sstevel cmn_err(fan_ok ? CE_NOTE : CE_WARN, "%s %s", fan_type, state); 2677*29949e86Sstevel } 2678*29949e86Sstevel 2679*29949e86Sstevel static uint_t 2680*29949e86Sstevel bd_insert_handler(caddr_t arg) 2681*29949e86Sstevel { 2682*29949e86Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 2683*29949e86Sstevel 2684*29949e86Sstevel ASSERT(softsp); 2685*29949e86Sstevel 2686*29949e86Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, ("bd_insert_handler()")); 2687*29949e86Sstevel 2688*29949e86Sstevel (void) timeout(bd_insert_timeout, softsp, bd_insert_delay_hz); 2689*29949e86Sstevel 2690*29949e86Sstevel return (DDI_INTR_CLAIMED); 2691*29949e86Sstevel } 2692*29949e86Sstevel 2693*29949e86Sstevel void 2694*29949e86Sstevel bd_remove_poll(struct sysctrl_soft_state *softsp) 2695*29949e86Sstevel { 2696*29949e86Sstevel ASSERT(fhc_bdlist_locked()); 2697*29949e86Sstevel 2698*29949e86Sstevel if (!bd_remove_to_id) { 2699*29949e86Sstevel bd_remove_to_id = timeout(bd_remove_timeout, softsp, 2700*29949e86Sstevel bd_remove_timeout_hz); 2701*29949e86Sstevel } else { 2702*29949e86Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, 2703*29949e86Sstevel ("bd_remove_poll ignoring start request")); 2704*29949e86Sstevel } 2705*29949e86Sstevel } 2706*29949e86Sstevel 2707*29949e86Sstevel /* 2708*29949e86Sstevel * bd_insert_timeout() 2709*29949e86Sstevel * 2710*29949e86Sstevel * This routine handles the board insert interrupt. It is called from a 2711*29949e86Sstevel * timeout so that it does not run at interrupt level. The main job 2712*29949e86Sstevel * of this routine is to find hotplugged boards and de-assert the 2713*29949e86Sstevel * board insert interrupt coming from the board. For hotplug phase I, 2714*29949e86Sstevel * the routine also powers down the board. 2715*29949e86Sstevel * JTAG scan is used to find boards which have been inserted. 2716*29949e86Sstevel * All other control of the boards is also done by JTAG scan. 2717*29949e86Sstevel */ 2718*29949e86Sstevel static void 2719*29949e86Sstevel bd_insert_timeout(void *arg) 2720*29949e86Sstevel { 2721*29949e86Sstevel struct sysctrl_soft_state *softsp = arg; 2722*29949e86Sstevel int found; 2723*29949e86Sstevel 2724*29949e86Sstevel ASSERT(softsp); 2725*29949e86Sstevel 2726*29949e86Sstevel if (sysctrl_hotplug_disabled) { 2727*29949e86Sstevel sysc_policy_update(softsp, NULL, SYSC_EVT_BD_HP_DISABLED); 2728*29949e86Sstevel } else { 2729*29949e86Sstevel /* 2730*29949e86Sstevel * Lock the board list mutex. Keep it locked until all work 2731*29949e86Sstevel * is done. 2732*29949e86Sstevel */ 2733*29949e86Sstevel (void) fhc_bdlist_lock(-1); 2734*29949e86Sstevel 2735*29949e86Sstevel found = fhc_bd_insert_scan(); 2736*29949e86Sstevel 2737*29949e86Sstevel if (found) { 2738*29949e86Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, 2739*29949e86Sstevel ("bd_insert_timeout starting bd_remove_poll()")); 2740*29949e86Sstevel bd_remove_poll(softsp); 2741*29949e86Sstevel } 2742*29949e86Sstevel 2743*29949e86Sstevel fhc_bdlist_unlock(); 2744*29949e86Sstevel } 2745*29949e86Sstevel 2746*29949e86Sstevel /* 2747*29949e86Sstevel * Enable interrupts. 2748*29949e86Sstevel */ 2749*29949e86Sstevel ddi_trigger_softintr(softsp->sbrd_gone_id); 2750*29949e86Sstevel } 2751*29949e86Sstevel 2752*29949e86Sstevel static void 2753*29949e86Sstevel bd_remove_timeout(void *arg) 2754*29949e86Sstevel { 2755*29949e86Sstevel struct sysctrl_soft_state *softsp = arg; 2756*29949e86Sstevel int keep_polling; 2757*29949e86Sstevel 2758*29949e86Sstevel ASSERT(softsp); 2759*29949e86Sstevel 2760*29949e86Sstevel /* 2761*29949e86Sstevel * Lock the board list mutex. Keep it locked until all work 2762*29949e86Sstevel * is done. 2763*29949e86Sstevel */ 2764*29949e86Sstevel (void) fhc_bdlist_lock(-1); 2765*29949e86Sstevel 2766*29949e86Sstevel bd_remove_to_id = 0; /* delete our timeout ID */ 2767*29949e86Sstevel 2768*29949e86Sstevel keep_polling = fhc_bd_remove_scan(); 2769*29949e86Sstevel 2770*29949e86Sstevel if (keep_polling) { 2771*29949e86Sstevel bd_remove_poll(softsp); 2772*29949e86Sstevel } else { 2773*29949e86Sstevel DPRINTF(SYSCTRL_ATTACH_DEBUG, ("exiting bd_remove_poll.")); 2774*29949e86Sstevel } 2775*29949e86Sstevel 2776*29949e86Sstevel fhc_bdlist_unlock(); 2777*29949e86Sstevel } 2778*29949e86Sstevel 2779*29949e86Sstevel static uint_t 2780*29949e86Sstevel bd_insert_normal(caddr_t arg) 2781*29949e86Sstevel { 2782*29949e86Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 2783*29949e86Sstevel uchar_t tmp_reg; 2784*29949e86Sstevel 2785*29949e86Sstevel ASSERT(softsp); 2786*29949e86Sstevel 2787*29949e86Sstevel /* has the condition been removed? */ 2788*29949e86Sstevel /* XXX add deglitch state machine here */ 2789*29949e86Sstevel if (!(*(softsp->status1) & SYS_NOT_BRD_PRES)) { 2790*29949e86Sstevel /* check again in a few */ 2791*29949e86Sstevel (void) timeout(bd_insert_timeout, softsp, bd_insert_retry_hz); 2792*29949e86Sstevel } else { 2793*29949e86Sstevel /* Turn on the enable bit for this interrupt */ 2794*29949e86Sstevel mutex_enter(&softsp->csr_mutex); 2795*29949e86Sstevel *(softsp->csr) |= SYS_SBRD_PRES_EN; 2796*29949e86Sstevel /* flush the hardware store buffer */ 2797*29949e86Sstevel tmp_reg = *(softsp->csr); 2798*29949e86Sstevel #ifdef lint 2799*29949e86Sstevel tmp_reg = tmp_reg; 2800*29949e86Sstevel #endif 2801*29949e86Sstevel mutex_exit(&softsp->csr_mutex); 2802*29949e86Sstevel } 2803*29949e86Sstevel 2804*29949e86Sstevel return (DDI_INTR_CLAIMED); 2805*29949e86Sstevel } 2806*29949e86Sstevel 2807*29949e86Sstevel /* 2808*29949e86Sstevel * blink LED handler. 2809*29949e86Sstevel * 2810*29949e86Sstevel * The actual bit manipulation needs to occur at interrupt level 2811*29949e86Sstevel * because we need access to the CSR with its CSR mutex 2812*29949e86Sstevel */ 2813*29949e86Sstevel static uint_t 2814*29949e86Sstevel blink_led_handler(caddr_t arg) 2815*29949e86Sstevel { 2816*29949e86Sstevel struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg; 2817*29949e86Sstevel uchar_t tmp_reg; 2818*29949e86Sstevel 2819*29949e86Sstevel ASSERT(softsp); 2820*29949e86Sstevel 2821*29949e86Sstevel mutex_enter(&softsp->csr_mutex); 2822*29949e86Sstevel 2823*29949e86Sstevel /* 2824*29949e86Sstevel * XXX - The lock for the sys_led is not held here. If more 2825*29949e86Sstevel * complicated tasks are done with the System LED, then 2826*29949e86Sstevel * locking should be done here. 2827*29949e86Sstevel */ 2828*29949e86Sstevel 2829*29949e86Sstevel /* read the hardware register. */ 2830*29949e86Sstevel tmp_reg = *(softsp->csr); 2831*29949e86Sstevel 2832*29949e86Sstevel /* Only turn on the OS System LED bit if the softsp state is on. */ 2833*29949e86Sstevel if (softsp->sys_led) { 2834*29949e86Sstevel tmp_reg |= SYS_LED_RIGHT; 2835*29949e86Sstevel } else { 2836*29949e86Sstevel tmp_reg &= ~SYS_LED_RIGHT; 2837*29949e86Sstevel } 2838*29949e86Sstevel 2839*29949e86Sstevel /* Turn on the yellow LED if system fault status is set. */ 2840*29949e86Sstevel if (softsp->sys_fault) { 2841*29949e86Sstevel tmp_reg |= SYS_LED_MID; 2842*29949e86Sstevel } else { 2843*29949e86Sstevel tmp_reg &= ~SYS_LED_MID; 2844*29949e86Sstevel } 2845*29949e86Sstevel 2846*29949e86Sstevel /* write to the hardware register */ 2847*29949e86Sstevel *(softsp->csr) = tmp_reg; 2848*29949e86Sstevel 2849*29949e86Sstevel /* flush the hardware store buffer */ 2850*29949e86Sstevel tmp_reg = *(softsp->csr); 2851*29949e86Sstevel #ifdef lint 2852*29949e86Sstevel tmp_reg = tmp_reg; 2853*29949e86Sstevel #endif 2854*29949e86Sstevel mutex_exit(&softsp->csr_mutex); 2855*29949e86Sstevel 2856*29949e86Sstevel (void) timeout(blink_led_timeout, softsp, blink_led_timeout_hz); 2857*29949e86Sstevel 2858*29949e86Sstevel return (DDI_INTR_CLAIMED); 2859*29949e86Sstevel } 2860*29949e86Sstevel 2861*29949e86Sstevel /* 2862*29949e86Sstevel * simply re-trigger the interrupt handler on led timeout 2863*29949e86Sstevel */ 2864*29949e86Sstevel static void 2865*29949e86Sstevel blink_led_timeout(void *arg) 2866*29949e86Sstevel { 2867*29949e86Sstevel struct sysctrl_soft_state *softsp = arg; 2868*29949e86Sstevel int led_state; 2869*29949e86Sstevel 2870*29949e86Sstevel ASSERT(softsp); 2871*29949e86Sstevel 2872*29949e86Sstevel /* 2873*29949e86Sstevel * Process the system fault list here. This is where the driver 2874*29949e86Sstevel * must decide what yellow LEDs to turn on if any. The fault 2875*29949e86Sstevel * list is walked and each fhc_list entry is updated with it's 2876*29949e86Sstevel * yellow LED status. This info is used later by the routine 2877*29949e86Sstevel * toggle_board_green_leds(). 2878*29949e86Sstevel * 2879*29949e86Sstevel * The variable system_fault is non-zero if any non- 2880*29949e86Sstevel * suppressed faults are found in the system. 2881*29949e86Sstevel */ 2882*29949e86Sstevel softsp->sys_fault = process_fault_list(); 2883*29949e86Sstevel 2884*29949e86Sstevel /* blink the system board OS LED */ 2885*29949e86Sstevel mutex_enter(&softsp->sys_led_lock); 2886*29949e86Sstevel softsp->sys_led = !softsp->sys_led; 2887*29949e86Sstevel led_state = softsp->sys_led; 2888*29949e86Sstevel mutex_exit(&softsp->sys_led_lock); 2889*29949e86Sstevel 2890*29949e86Sstevel toggle_board_green_leds(led_state); 2891*29949e86Sstevel 2892*29949e86Sstevel ddi_trigger_softintr(softsp->blink_led_id); 2893*29949e86Sstevel } 2894*29949e86Sstevel 2895*29949e86Sstevel void 2896*29949e86Sstevel toggle_board_green_leds(int led_state) 2897*29949e86Sstevel { 2898*29949e86Sstevel fhc_bd_t *list; 2899*29949e86Sstevel 2900*29949e86Sstevel (void) fhc_bdlist_lock(-1); 2901*29949e86Sstevel for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) { 2902*29949e86Sstevel uint_t value = 0; 2903*29949e86Sstevel 2904*29949e86Sstevel if (list->sc.in_transition || 2905*29949e86Sstevel (list->sc.rstate != SYSC_CFGA_RSTATE_CONNECTED)) 2906*29949e86Sstevel continue; 2907*29949e86Sstevel 2908*29949e86Sstevel ASSERT(list->sc.type != CLOCK_BOARD); 2909*29949e86Sstevel ASSERT(list->sc.type != DISK_BOARD); 2910*29949e86Sstevel ASSERT(list->softsp); 2911*29949e86Sstevel 2912*29949e86Sstevel if ((list->sc.ostate == SYSC_CFGA_OSTATE_CONFIGURED) && 2913*29949e86Sstevel led_state) 2914*29949e86Sstevel value |= FHC_LED_RIGHT; 2915*29949e86Sstevel 2916*29949e86Sstevel if (list->fault) 2917*29949e86Sstevel value |= FHC_LED_MID; 2918*29949e86Sstevel else 2919*29949e86Sstevel value &= ~FHC_LED_MID; 2920*29949e86Sstevel 2921*29949e86Sstevel update_board_leds(list, FHC_LED_RIGHT|FHC_LED_MID, value); 2922*29949e86Sstevel } 2923*29949e86Sstevel fhc_bdlist_unlock(); 2924*29949e86Sstevel } 2925*29949e86Sstevel 2926*29949e86Sstevel /* 2927*29949e86Sstevel * timestamp an AC power failure in nvram 2928*29949e86Sstevel */ 2929*29949e86Sstevel static void 2930*29949e86Sstevel nvram_update_powerfail(struct sysctrl_soft_state *softsp) 2931*29949e86Sstevel { 2932*29949e86Sstevel char buf[80]; 2933*29949e86Sstevel int len = 0; 2934*29949e86Sstevel 2935*29949e86Sstevel numtos(gethrestime_sec(), buf); 2936*29949e86Sstevel 2937*29949e86Sstevel if (softsp->options_nodeid) { 2938*29949e86Sstevel len = prom_setprop(softsp->options_nodeid, "powerfail-time", 2939*29949e86Sstevel buf, strlen(buf)+1); 2940*29949e86Sstevel } 2941*29949e86Sstevel 2942*29949e86Sstevel if (len <= 0) { 2943*29949e86Sstevel cmn_err(CE_WARN, "sysctrl%d: failed to set powerfail-time " 2944*29949e86Sstevel "to %s\n", ddi_get_instance(softsp->dip), buf); 2945*29949e86Sstevel } 2946*29949e86Sstevel } 2947*29949e86Sstevel 2948*29949e86Sstevel void 2949*29949e86Sstevel sysctrl_add_kstats(struct sysctrl_soft_state *softsp) 2950*29949e86Sstevel { 2951*29949e86Sstevel struct kstat *ksp; /* Generic sysctrl kstats */ 2952*29949e86Sstevel struct kstat *pksp; /* Power Supply kstat */ 2953*29949e86Sstevel struct kstat *tksp; /* Sysctrl temperatrure kstat */ 2954*29949e86Sstevel struct kstat *ttsp; /* Sysctrl temperature test kstat */ 2955*29949e86Sstevel 2956*29949e86Sstevel if ((ksp = kstat_create("unix", ddi_get_instance(softsp->dip), 2957*29949e86Sstevel SYSCTRL_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED, 2958*29949e86Sstevel sizeof (struct sysctrl_kstat) / sizeof (kstat_named_t), 2959*29949e86Sstevel KSTAT_FLAG_PERSISTENT)) == NULL) { 2960*29949e86Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed", 2961*29949e86Sstevel ddi_get_instance(softsp->dip)); 2962*29949e86Sstevel } else { 2963*29949e86Sstevel struct sysctrl_kstat *sysksp; 2964*29949e86Sstevel 2965*29949e86Sstevel sysksp = (struct sysctrl_kstat *)(ksp->ks_data); 2966*29949e86Sstevel 2967*29949e86Sstevel /* now init the named kstats */ 2968*29949e86Sstevel kstat_named_init(&sysksp->csr, CSR_KSTAT_NAMED, 2969*29949e86Sstevel KSTAT_DATA_CHAR); 2970*29949e86Sstevel 2971*29949e86Sstevel kstat_named_init(&sysksp->status1, STAT1_KSTAT_NAMED, 2972*29949e86Sstevel KSTAT_DATA_CHAR); 2973*29949e86Sstevel 2974*29949e86Sstevel kstat_named_init(&sysksp->status2, STAT2_KSTAT_NAMED, 2975*29949e86Sstevel KSTAT_DATA_CHAR); 2976*29949e86Sstevel 2977*29949e86Sstevel kstat_named_init(&sysksp->clk_freq2, CLK_FREQ2_KSTAT_NAMED, 2978*29949e86Sstevel KSTAT_DATA_CHAR); 2979*29949e86Sstevel 2980*29949e86Sstevel kstat_named_init(&sysksp->fan_status, FAN_KSTAT_NAMED, 2981*29949e86Sstevel KSTAT_DATA_CHAR); 2982*29949e86Sstevel 2983*29949e86Sstevel kstat_named_init(&sysksp->key_status, KEY_KSTAT_NAMED, 2984*29949e86Sstevel KSTAT_DATA_CHAR); 2985*29949e86Sstevel 2986*29949e86Sstevel kstat_named_init(&sysksp->power_state, POWER_KSTAT_NAMED, 2987*29949e86Sstevel KSTAT_DATA_INT32); 2988*29949e86Sstevel 2989*29949e86Sstevel kstat_named_init(&sysksp->clk_ver, CLK_VER_KSTAT_NAME, 2990*29949e86Sstevel KSTAT_DATA_CHAR); 2991*29949e86Sstevel 2992*29949e86Sstevel ksp->ks_update = sysctrl_kstat_update; 2993*29949e86Sstevel ksp->ks_private = (void *)softsp; 2994*29949e86Sstevel kstat_install(ksp); 2995*29949e86Sstevel } 2996*29949e86Sstevel 2997*29949e86Sstevel if ((tksp = kstat_create("unix", CLOCK_BOARD_INDEX, 2998*29949e86Sstevel OVERTEMP_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, 2999*29949e86Sstevel sizeof (struct temp_stats), KSTAT_FLAG_PERSISTENT)) == NULL) { 3000*29949e86Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed", 3001*29949e86Sstevel ddi_get_instance(softsp->dip)); 3002*29949e86Sstevel } else { 3003*29949e86Sstevel tksp->ks_update = overtemp_kstat_update; 3004*29949e86Sstevel tksp->ks_private = (void *)&softsp->tempstat; 3005*29949e86Sstevel kstat_install(tksp); 3006*29949e86Sstevel } 3007*29949e86Sstevel 3008*29949e86Sstevel if ((ttsp = kstat_create("unix", CLOCK_BOARD_INDEX, 3009*29949e86Sstevel TEMP_OVERRIDE_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, sizeof (short), 3010*29949e86Sstevel KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) { 3011*29949e86Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed", 3012*29949e86Sstevel ddi_get_instance(softsp->dip)); 3013*29949e86Sstevel } else { 3014*29949e86Sstevel ttsp->ks_update = temp_override_kstat_update; 3015*29949e86Sstevel ttsp->ks_private = (void *)&softsp->tempstat.override; 3016*29949e86Sstevel kstat_install(ttsp); 3017*29949e86Sstevel } 3018*29949e86Sstevel 3019*29949e86Sstevel if ((pksp = kstat_create("unix", ddi_get_instance(softsp->dip), 3020*29949e86Sstevel PSSHAD_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, 3021*29949e86Sstevel SYS_PS_COUNT, KSTAT_FLAG_PERSISTENT)) == NULL) { 3022*29949e86Sstevel cmn_err(CE_WARN, "sysctrl%d: kstat_create failed", 3023*29949e86Sstevel ddi_get_instance(softsp->dip)); 3024*29949e86Sstevel } else { 3025*29949e86Sstevel pksp->ks_update = psstat_kstat_update; 3026*29949e86Sstevel pksp->ks_private = (void *)softsp; 3027*29949e86Sstevel kstat_install(pksp); 3028*29949e86Sstevel } 3029*29949e86Sstevel } 3030*29949e86Sstevel 3031*29949e86Sstevel static int 3032*29949e86Sstevel sysctrl_kstat_update(kstat_t *ksp, int rw) 3033*29949e86Sstevel { 3034*29949e86Sstevel struct sysctrl_kstat *sysksp; 3035*29949e86Sstevel struct sysctrl_soft_state *softsp; 3036*29949e86Sstevel 3037*29949e86Sstevel sysksp = (struct sysctrl_kstat *)(ksp->ks_data); 3038*29949e86Sstevel softsp = (struct sysctrl_soft_state *)(ksp->ks_private); 3039*29949e86Sstevel 3040*29949e86Sstevel /* this is a read-only kstat. Exit on a write */ 3041*29949e86Sstevel 3042*29949e86Sstevel if (rw == KSTAT_WRITE) { 3043*29949e86Sstevel return (EACCES); 3044*29949e86Sstevel } else { 3045*29949e86Sstevel /* 3046*29949e86Sstevel * copy the current state of the hardware into the 3047*29949e86Sstevel * kstat structure. 3048*29949e86Sstevel */ 3049*29949e86Sstevel sysksp->csr.value.c[0] = *(softsp->csr); 3050*29949e86Sstevel sysksp->status1.value.c[0] = *(softsp->status1); 3051*29949e86Sstevel sysksp->status2.value.c[0] = *(softsp->status2); 3052*29949e86Sstevel sysksp->clk_freq2.value.c[0] = *(softsp->clk_freq2); 3053*29949e86Sstevel 3054*29949e86Sstevel sysksp->fan_status.value.c[0] = softsp->pps_fan_external_state; 3055*29949e86Sstevel sysksp->key_status.value.c[0] = softsp->key_shadow; 3056*29949e86Sstevel sysksp->power_state.value.i32 = softsp->power_state; 3057*29949e86Sstevel 3058*29949e86Sstevel /* 3059*29949e86Sstevel * non-existence of the clock version register returns the 3060*29949e86Sstevel * value 0xff when the hardware register location is read 3061*29949e86Sstevel */ 3062*29949e86Sstevel if (softsp->clk_ver != NULL) 3063*29949e86Sstevel sysksp->clk_ver.value.c[0] = *(softsp->clk_ver); 3064*29949e86Sstevel else 3065*29949e86Sstevel sysksp->clk_ver.value.c[0] = (char)0xff; 3066*29949e86Sstevel } 3067*29949e86Sstevel return (0); 3068*29949e86Sstevel } 3069*29949e86Sstevel 3070*29949e86Sstevel static int 3071*29949e86Sstevel psstat_kstat_update(kstat_t *ksp, int rw) 3072*29949e86Sstevel { 3073*29949e86Sstevel struct sysctrl_soft_state *softsp; 3074*29949e86Sstevel uchar_t *ptr = (uchar_t *)(ksp->ks_data); 3075*29949e86Sstevel int ps; 3076*29949e86Sstevel 3077*29949e86Sstevel softsp = (struct sysctrl_soft_state *)(ksp->ks_private); 3078*29949e86Sstevel 3079*29949e86Sstevel if (rw == KSTAT_WRITE) { 3080*29949e86Sstevel return (EACCES); 3081*29949e86Sstevel } else { 3082*29949e86Sstevel for (ps = 0; ps < SYS_PS_COUNT; ps++) { 3083*29949e86Sstevel *ptr++ = softsp->ps_stats[ps].dcshadow; 3084*29949e86Sstevel } 3085*29949e86Sstevel } 3086*29949e86Sstevel return (0); 3087*29949e86Sstevel } 3088*29949e86Sstevel 3089*29949e86Sstevel static void 3090*29949e86Sstevel sysctrl_thread_wakeup(void *arg) 3091*29949e86Sstevel { 3092*29949e86Sstevel int type = (int)(uintptr_t)arg; 3093*29949e86Sstevel 3094*29949e86Sstevel /* 3095*29949e86Sstevel * grab mutex to guarantee that our wakeup call 3096*29949e86Sstevel * arrives after we go to sleep -- so we can't sleep forever. 3097*29949e86Sstevel */ 3098*29949e86Sstevel mutex_enter(&sslist_mutex); 3099*29949e86Sstevel switch (type) { 3100*29949e86Sstevel case OVERTEMP_POLL: 3101*29949e86Sstevel cv_signal(&overtemp_cv); 3102*29949e86Sstevel break; 3103*29949e86Sstevel case KEYSWITCH_POLL: 3104*29949e86Sstevel cv_signal(&keyswitch_cv); 3105*29949e86Sstevel break; 3106*29949e86Sstevel default: 3107*29949e86Sstevel cmn_err(CE_WARN, "sysctrl: invalid type %d to wakeup\n", type); 3108*29949e86Sstevel break; 3109*29949e86Sstevel } 3110*29949e86Sstevel mutex_exit(&sslist_mutex); 3111*29949e86Sstevel } 3112*29949e86Sstevel 3113*29949e86Sstevel static void 3114*29949e86Sstevel sysctrl_overtemp_poll(void) 3115*29949e86Sstevel { 3116*29949e86Sstevel struct sysctrl_soft_state *list; 3117*29949e86Sstevel callb_cpr_t cprinfo; 3118*29949e86Sstevel 3119*29949e86Sstevel CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "overtemp"); 3120*29949e86Sstevel 3121*29949e86Sstevel /* The overtemp data structures are protected by a mutex. */ 3122*29949e86Sstevel mutex_enter(&sslist_mutex); 3123*29949e86Sstevel 3124*29949e86Sstevel while (sysctrl_do_overtemp_thread) { 3125*29949e86Sstevel 3126*29949e86Sstevel for (list = sys_list; list != NULL; list = list->next) { 3127*29949e86Sstevel if (list->temp_reg != NULL) { 3128*29949e86Sstevel update_temp(list->pdip, &list->tempstat, 3129*29949e86Sstevel *(list->temp_reg)); 3130*29949e86Sstevel } 3131*29949e86Sstevel } 3132*29949e86Sstevel 3133*29949e86Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 3134*29949e86Sstevel 3135*29949e86Sstevel /* now have this thread sleep for a while */ 3136*29949e86Sstevel (void) timeout(sysctrl_thread_wakeup, (void *)OVERTEMP_POLL, 3137*29949e86Sstevel overtemp_timeout_hz); 3138*29949e86Sstevel 3139*29949e86Sstevel cv_wait(&overtemp_cv, &sslist_mutex); 3140*29949e86Sstevel 3141*29949e86Sstevel CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex); 3142*29949e86Sstevel } 3143*29949e86Sstevel CALLB_CPR_EXIT(&cprinfo); 3144*29949e86Sstevel thread_exit(); 3145*29949e86Sstevel /* NOTREACHED */ 3146*29949e86Sstevel } 3147*29949e86Sstevel 3148*29949e86Sstevel static void 3149*29949e86Sstevel sysctrl_keyswitch_poll(void) 3150*29949e86Sstevel { 3151*29949e86Sstevel struct sysctrl_soft_state *list; 3152*29949e86Sstevel callb_cpr_t cprinfo; 3153*29949e86Sstevel 3154*29949e86Sstevel CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "keyswitch"); 3155*29949e86Sstevel 3156*29949e86Sstevel /* The keyswitch data strcutures are protected by a mutex. */ 3157*29949e86Sstevel mutex_enter(&sslist_mutex); 3158*29949e86Sstevel 3159*29949e86Sstevel while (sysctrl_do_keyswitch_thread) { 3160*29949e86Sstevel 3161*29949e86Sstevel for (list = sys_list; list != NULL; list = list->next) { 3162*29949e86Sstevel if (list->status1 != NULL) 3163*29949e86Sstevel update_key_state(list); 3164*29949e86Sstevel } 3165*29949e86Sstevel 3166*29949e86Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 3167*29949e86Sstevel 3168*29949e86Sstevel /* now have this thread sleep for a while */ 3169*29949e86Sstevel (void) timeout(sysctrl_thread_wakeup, (void *)KEYSWITCH_POLL, 3170*29949e86Sstevel keyswitch_timeout_hz); 3171*29949e86Sstevel 3172*29949e86Sstevel cv_wait(&keyswitch_cv, &sslist_mutex); 3173*29949e86Sstevel 3174*29949e86Sstevel CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex); 3175*29949e86Sstevel } 3176*29949e86Sstevel CALLB_CPR_EXIT(&cprinfo); 3177*29949e86Sstevel thread_exit(); 3178*29949e86Sstevel /* NOTREACHED */ 3179*29949e86Sstevel } 3180*29949e86Sstevel 3181*29949e86Sstevel /* 3182*29949e86Sstevel * check the key switch position for state changes 3183*29949e86Sstevel */ 3184*29949e86Sstevel static void 3185*29949e86Sstevel update_key_state(struct sysctrl_soft_state *list) 3186*29949e86Sstevel { 3187*29949e86Sstevel enum keyswitch_state key; 3188*29949e86Sstevel 3189*29949e86Sstevel /* 3190*29949e86Sstevel * snapshot current hardware key position 3191*29949e86Sstevel */ 3192*29949e86Sstevel if (*(list->status1) & SYS_NOT_SECURE) 3193*29949e86Sstevel key = KEY_NOT_SECURE; 3194*29949e86Sstevel else 3195*29949e86Sstevel key = KEY_SECURE; 3196*29949e86Sstevel 3197*29949e86Sstevel /* 3198*29949e86Sstevel * check for state transition 3199*29949e86Sstevel */ 3200*29949e86Sstevel if (key != list->key_shadow) { 3201*29949e86Sstevel 3202*29949e86Sstevel /* 3203*29949e86Sstevel * handle state transition 3204*29949e86Sstevel */ 3205*29949e86Sstevel switch (list->key_shadow) { 3206*29949e86Sstevel case KEY_BOOT: 3207*29949e86Sstevel cmn_err(CE_CONT, "?sysctrl%d: Key switch is%sin the " 3208*29949e86Sstevel "secure position\n", ddi_get_instance(list->dip), 3209*29949e86Sstevel (key == KEY_SECURE) ? " " : " not "); 3210*29949e86Sstevel list->key_shadow = key; 3211*29949e86Sstevel break; 3212*29949e86Sstevel case KEY_SECURE: 3213*29949e86Sstevel case KEY_NOT_SECURE: 3214*29949e86Sstevel cmn_err(CE_NOTE, "sysctrl%d: Key switch has changed" 3215*29949e86Sstevel " to the %s position", 3216*29949e86Sstevel ddi_get_instance(list->dip), 3217*29949e86Sstevel (key == KEY_SECURE) ? "secure" : "not-secure"); 3218*29949e86Sstevel list->key_shadow = key; 3219*29949e86Sstevel break; 3220*29949e86Sstevel default: 3221*29949e86Sstevel cmn_err(CE_CONT, 3222*29949e86Sstevel "?sysctrl%d: Key switch is in an unknown position," 3223*29949e86Sstevel "treated as being in the %s position\n", 3224*29949e86Sstevel ddi_get_instance(list->dip), 3225*29949e86Sstevel (list->key_shadow == KEY_SECURE) ? 3226*29949e86Sstevel "secure" : "not-secure"); 3227*29949e86Sstevel break; 3228*29949e86Sstevel } 3229*29949e86Sstevel } 3230*29949e86Sstevel } 3231*29949e86Sstevel 3232*29949e86Sstevel /* 3233*29949e86Sstevel * consider key switch position when handling an abort sequence 3234*29949e86Sstevel */ 3235*29949e86Sstevel static void 3236*29949e86Sstevel sysctrl_abort_seq_handler(char *msg) 3237*29949e86Sstevel { 3238*29949e86Sstevel struct sysctrl_soft_state *list; 3239*29949e86Sstevel uint_t secure = 0; 3240*29949e86Sstevel char buf[64], inst[4]; 3241*29949e86Sstevel 3242*29949e86Sstevel 3243*29949e86Sstevel /* 3244*29949e86Sstevel * if any of the key switch positions are secure, 3245*29949e86Sstevel * then disallow entry to the prom/debugger 3246*29949e86Sstevel */ 3247*29949e86Sstevel mutex_enter(&sslist_mutex); 3248*29949e86Sstevel buf[0] = (char)0; 3249*29949e86Sstevel for (list = sys_list; list != NULL; list = list->next) { 3250*29949e86Sstevel if (!(*(list->status1) & SYS_NOT_SECURE)) { 3251*29949e86Sstevel if (secure++) 3252*29949e86Sstevel (void) strcat(buf, ","); 3253*29949e86Sstevel /* 3254*29949e86Sstevel * XXX: later, replace instance number with nodeid 3255*29949e86Sstevel */ 3256*29949e86Sstevel (void) sprintf(inst, "%d", ddi_get_instance(list->dip)); 3257*29949e86Sstevel (void) strcat(buf, inst); 3258*29949e86Sstevel } 3259*29949e86Sstevel } 3260*29949e86Sstevel mutex_exit(&sslist_mutex); 3261*29949e86Sstevel 3262*29949e86Sstevel if (secure) { 3263*29949e86Sstevel cmn_err(CE_CONT, 3264*29949e86Sstevel "!sysctrl(%s): ignoring debug enter sequence\n", buf); 3265*29949e86Sstevel } else { 3266*29949e86Sstevel cmn_err(CE_CONT, "!sysctrl: allowing debug enter\n"); 3267*29949e86Sstevel debug_enter(msg); 3268*29949e86Sstevel } 3269*29949e86Sstevel } 3270*29949e86Sstevel 3271*29949e86Sstevel #define TABLE_END 0xFF 3272*29949e86Sstevel 3273*29949e86Sstevel struct uart_cmd { 3274*29949e86Sstevel uchar_t reg; 3275*29949e86Sstevel uchar_t data; 3276*29949e86Sstevel }; 3277*29949e86Sstevel 3278*29949e86Sstevel /* 3279*29949e86Sstevel * Time constant defined by this formula: 3280*29949e86Sstevel * ((4915200/32)/(baud) -2) 3281*29949e86Sstevel */ 3282*29949e86Sstevel 3283*29949e86Sstevel struct uart_cmd uart_table[] = { 3284*29949e86Sstevel { 0x09, 0xc0 }, /* Force hardware reset */ 3285*29949e86Sstevel { 0x04, 0x46 }, /* X16 clock mode, 1 stop bit/char, no parity */ 3286*29949e86Sstevel { 0x03, 0xc0 }, /* Rx is 8 bits/char */ 3287*29949e86Sstevel { 0x05, 0xe2 }, /* DTR, Tx is 8 bits/char, RTS */ 3288*29949e86Sstevel { 0x09, 0x02 }, /* No vector returned on interrupt */ 3289*29949e86Sstevel { 0x0b, 0x55 }, /* Rx Clock = Tx Clock = BR generator = ~TRxC OUT */ 3290*29949e86Sstevel { 0x0c, 0x0e }, /* Time Constant = 0x000e for 9600 baud */ 3291*29949e86Sstevel { 0x0d, 0x00 }, /* High byte of time constant */ 3292*29949e86Sstevel { 0x0e, 0x02 }, /* BR generator comes from Z-SCC's PCLK input */ 3293*29949e86Sstevel { 0x03, 0xc1 }, /* Rx is 8 bits/char, Rx is enabled */ 3294*29949e86Sstevel { 0x05, 0xea }, /* DTR, Tx is 8 bits/char, Tx is enabled, RTS */ 3295*29949e86Sstevel { 0x0e, 0x03 }, /* BR comes from PCLK, BR generator is enabled */ 3296*29949e86Sstevel { 0x00, 0x30 }, /* Error reset */ 3297*29949e86Sstevel { 0x00, 0x30 }, /* Error reset */ 3298*29949e86Sstevel { 0x00, 0x10 }, /* external status reset */ 3299*29949e86Sstevel { 0x03, 0xc1 }, /* Rx is 8 bits/char, Rx is enabled */ 3300*29949e86Sstevel { TABLE_END, 0x0 } 3301*29949e86Sstevel }; 3302*29949e86Sstevel 3303*29949e86Sstevel static void 3304*29949e86Sstevel init_remote_console_uart(struct sysctrl_soft_state *softsp) 3305*29949e86Sstevel { 3306*29949e86Sstevel int i = 0; 3307*29949e86Sstevel 3308*29949e86Sstevel /* 3309*29949e86Sstevel * Serial chip expects software to write to the control 3310*29949e86Sstevel * register first with the desired register number. Then 3311*29949e86Sstevel * write to the control register with the desired data. 3312*29949e86Sstevel * So walk thru table writing the register/data pairs to 3313*29949e86Sstevel * the serial port chip. 3314*29949e86Sstevel */ 3315*29949e86Sstevel while (uart_table[i].reg != TABLE_END) { 3316*29949e86Sstevel *(softsp->rcons_ctl) = uart_table[i].reg; 3317*29949e86Sstevel *(softsp->rcons_ctl) = uart_table[i].data; 3318*29949e86Sstevel i++; 3319*29949e86Sstevel } 3320*29949e86Sstevel } 3321*29949e86Sstevel 3322*29949e86Sstevel /* 3323*29949e86Sstevel * return the slot information of the system 3324*29949e86Sstevel * 3325*29949e86Sstevel * function take a sysctrl_soft_state, so it's ready for sunfire+ 3326*29949e86Sstevel * change which requires 2 registers to decide the system type. 3327*29949e86Sstevel */ 3328*29949e86Sstevel static void 3329*29949e86Sstevel sysc_slot_info(int nslots, int *start, int *limit, int *incr) 3330*29949e86Sstevel { 3331*29949e86Sstevel switch (nslots) { 3332*29949e86Sstevel case 8: 3333*29949e86Sstevel *start = 0; 3334*29949e86Sstevel *limit = 8; 3335*29949e86Sstevel *incr = 1; 3336*29949e86Sstevel break; 3337*29949e86Sstevel case 5: 3338*29949e86Sstevel *start = 1; 3339*29949e86Sstevel *limit = 10; 3340*29949e86Sstevel *incr = 2; 3341*29949e86Sstevel break; 3342*29949e86Sstevel case 4: 3343*29949e86Sstevel *start = 1; 3344*29949e86Sstevel *limit = 8; 3345*29949e86Sstevel *incr = 2; 3346*29949e86Sstevel break; 3347*29949e86Sstevel case 0: 3348*29949e86Sstevel case 16: 3349*29949e86Sstevel default: 3350*29949e86Sstevel *start = 0; 3351*29949e86Sstevel *limit = 16; 3352*29949e86Sstevel *incr = 1; 3353*29949e86Sstevel break; 3354*29949e86Sstevel } 3355*29949e86Sstevel } 3356*29949e86Sstevel 3357*29949e86Sstevel /* 3358*29949e86Sstevel * reinitialize the Remote Console on the clock board 3359*29949e86Sstevel * 3360*29949e86Sstevel * with V5_AUX power outage the Remote Console ends up in 3361*29949e86Sstevel * unknown state and has to be reinitilized if it was enabled 3362*29949e86Sstevel * initially. 3363*29949e86Sstevel */ 3364*29949e86Sstevel static void 3365*29949e86Sstevel rcons_reinit(struct sysctrl_soft_state *softsp) 3366*29949e86Sstevel { 3367*29949e86Sstevel uchar_t tmp_reg; 3368*29949e86Sstevel 3369*29949e86Sstevel if (!(softsp->rcons_ctl)) 3370*29949e86Sstevel /* 3371*29949e86Sstevel * There is no OBP register set for the remote console UART, 3372*29949e86Sstevel * so offset from the last register set, the misc register 3373*29949e86Sstevel * set, in order to map in the remote console UART. 3374*29949e86Sstevel */ 3375*29949e86Sstevel if (ddi_map_regs(softsp->dip, 1, (caddr_t *)&softsp->rcons_ctl, 3376*29949e86Sstevel RMT_CONS_OFFSET, RMT_CONS_LEN)) { 3377*29949e86Sstevel cmn_err(CE_WARN, "Unable to reinitialize " 3378*29949e86Sstevel "remote console."); 3379*29949e86Sstevel return; 3380*29949e86Sstevel } 3381*29949e86Sstevel 3382*29949e86Sstevel 3383*29949e86Sstevel /* Disable the remote console reset control bits. */ 3384*29949e86Sstevel *(softsp->clk_freq2) &= ~RCONS_UART_EN; 3385*29949e86Sstevel 3386*29949e86Sstevel /* flush the hardware buffers */ 3387*29949e86Sstevel tmp_reg = *(softsp->csr); 3388*29949e86Sstevel 3389*29949e86Sstevel /* 3390*29949e86Sstevel * Program the UART to watch ttya console. 3391*29949e86Sstevel */ 3392*29949e86Sstevel init_remote_console_uart(softsp); 3393*29949e86Sstevel 3394*29949e86Sstevel /* Now enable the remote console reset control bits. */ 3395*29949e86Sstevel *(softsp->clk_freq2) |= RCONS_UART_EN; 3396*29949e86Sstevel 3397*29949e86Sstevel /* flush the hardware buffers */ 3398*29949e86Sstevel tmp_reg = *(softsp->csr); 3399*29949e86Sstevel 3400*29949e86Sstevel /* print some info for user to watch */ 3401*29949e86Sstevel cmn_err(CE_NOTE, "Remote console reinitialized"); 3402*29949e86Sstevel #ifdef lint 3403*29949e86Sstevel tmp_reg = tmp_reg; 3404*29949e86Sstevel #endif 3405*29949e86Sstevel } 3406