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