1*1c42de6dSgd78059 /* 2*1c42de6dSgd78059 * CDDL HEADER START 3*1c42de6dSgd78059 * 4*1c42de6dSgd78059 * The contents of this file are subject to the terms of the 5*1c42de6dSgd78059 * Common Development and Distribution License (the "License"). 6*1c42de6dSgd78059 * You may not use this file except in compliance with the License. 7*1c42de6dSgd78059 * 8*1c42de6dSgd78059 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1c42de6dSgd78059 * or http://www.opensolaris.org/os/licensing. 10*1c42de6dSgd78059 * See the License for the specific language governing permissions 11*1c42de6dSgd78059 * and limitations under the License. 12*1c42de6dSgd78059 * 13*1c42de6dSgd78059 * When distributing Covered Code, include this CDDL HEADER in each 14*1c42de6dSgd78059 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1c42de6dSgd78059 * If applicable, add the following below this CDDL HEADER, with the 16*1c42de6dSgd78059 * fields enclosed by brackets "[]" replaced with your own identifying 17*1c42de6dSgd78059 * information: Portions Copyright [yyyy] [name of copyright owner] 18*1c42de6dSgd78059 * 19*1c42de6dSgd78059 * CDDL HEADER END 20*1c42de6dSgd78059 */ 21*1c42de6dSgd78059 /* 22*1c42de6dSgd78059 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 23*1c42de6dSgd78059 * Use is subject to license terms. 24*1c42de6dSgd78059 */ 25*1c42de6dSgd78059 26*1c42de6dSgd78059 #pragma ident "%Z%%M% %I% %E% SMI" 27*1c42de6dSgd78059 28*1c42de6dSgd78059 /* 29*1c42de6dSgd78059 * bscv.c - multi-threaded lom driver for the Stiletto platform. 30*1c42de6dSgd78059 */ 31*1c42de6dSgd78059 32*1c42de6dSgd78059 /* 33*1c42de6dSgd78059 * Included files. 34*1c42de6dSgd78059 */ 35*1c42de6dSgd78059 36*1c42de6dSgd78059 #include <sys/note.h> 37*1c42de6dSgd78059 #include <sys/types.h> 38*1c42de6dSgd78059 #include <sys/param.h> 39*1c42de6dSgd78059 #include <sys/uio.h> 40*1c42de6dSgd78059 #include <sys/open.h> 41*1c42de6dSgd78059 #include <sys/cred.h> 42*1c42de6dSgd78059 #include <sys/stream.h> 43*1c42de6dSgd78059 #include <sys/systm.h> 44*1c42de6dSgd78059 #include <sys/conf.h> 45*1c42de6dSgd78059 #include <sys/cyclic.h> 46*1c42de6dSgd78059 #include <sys/reboot.h> 47*1c42de6dSgd78059 #include <sys/modctl.h> 48*1c42de6dSgd78059 #include <sys/mkdev.h> 49*1c42de6dSgd78059 #include <sys/errno.h> 50*1c42de6dSgd78059 #include <sys/debug.h> 51*1c42de6dSgd78059 #include <sys/kmem.h> 52*1c42de6dSgd78059 #include <sys/consdev.h> 53*1c42de6dSgd78059 #include <sys/file.h> 54*1c42de6dSgd78059 #include <sys/stat.h> 55*1c42de6dSgd78059 #include <sys/time.h> 56*1c42de6dSgd78059 #include <sys/disp.h> 57*1c42de6dSgd78059 #include <sys/ddi.h> 58*1c42de6dSgd78059 #include <sys/sunddi.h> 59*1c42de6dSgd78059 #include <sys/stream.h> 60*1c42de6dSgd78059 #include <sys/strlog.h> 61*1c42de6dSgd78059 #include <sys/log.h> 62*1c42de6dSgd78059 #include <sys/utsname.h> 63*1c42de6dSgd78059 #include <sys/callb.h> 64*1c42de6dSgd78059 #include <sys/sysevent.h> 65*1c42de6dSgd78059 #include <sys/nvpair.h> 66*1c42de6dSgd78059 #include <sys/sysevent/eventdefs.h> 67*1c42de6dSgd78059 #include <sys/sysevent/domain.h> 68*1c42de6dSgd78059 #include <sys/sysevent/env.h> 69*1c42de6dSgd78059 #include <sys/sysevent/dr.h> 70*1c42de6dSgd78059 71*1c42de6dSgd78059 #include <sys/lom_io.h> 72*1c42de6dSgd78059 #include <sys/bscbus.h> 73*1c42de6dSgd78059 #include <sys/bscv_impl.h> 74*1c42de6dSgd78059 75*1c42de6dSgd78059 /* 76*1c42de6dSgd78059 * Variables defined here and visible internally only 77*1c42de6dSgd78059 */ 78*1c42de6dSgd78059 79*1c42de6dSgd78059 static void *bscv_statep = NULL; 80*1c42de6dSgd78059 81*1c42de6dSgd78059 /* 82*1c42de6dSgd78059 * Forward declarations 83*1c42de6dSgd78059 */ 84*1c42de6dSgd78059 85*1c42de6dSgd78059 static int bscv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 86*1c42de6dSgd78059 static int bscv_attach(dev_info_t *, ddi_attach_cmd_t); 87*1c42de6dSgd78059 static int bscv_detach(dev_info_t *, ddi_detach_cmd_t); 88*1c42de6dSgd78059 static int bscv_reset(dev_info_t *, ddi_reset_cmd_t); 89*1c42de6dSgd78059 static int bscv_map_regs(bscv_soft_state_t *); 90*1c42de6dSgd78059 static void bscv_unmap_regs(bscv_soft_state_t *); 91*1c42de6dSgd78059 static void bscv_map_chan_logical_physical(bscv_soft_state_t *); 92*1c42de6dSgd78059 93*1c42de6dSgd78059 static int bscv_open(dev_t *, int, int, cred_t *); 94*1c42de6dSgd78059 static int bscv_close(dev_t, int, int, cred_t *); 95*1c42de6dSgd78059 static void bscv_full_stop(bscv_soft_state_t *); 96*1c42de6dSgd78059 97*1c42de6dSgd78059 static void bscv_enter(bscv_soft_state_t *); 98*1c42de6dSgd78059 static void bscv_exit(bscv_soft_state_t *); 99*1c42de6dSgd78059 #ifdef DEBUG 100*1c42de6dSgd78059 static int bscv_held(bscv_soft_state_t *); 101*1c42de6dSgd78059 #endif /* DEBUG */ 102*1c42de6dSgd78059 103*1c42de6dSgd78059 static void bscv_put8(bscv_soft_state_t *, int, bscv_addr_t, uint8_t); 104*1c42de6dSgd78059 static void bscv_put16(bscv_soft_state_t *, int, bscv_addr_t, uint16_t); 105*1c42de6dSgd78059 static void bscv_put32(bscv_soft_state_t *, int, bscv_addr_t, uint32_t); 106*1c42de6dSgd78059 static uint8_t bscv_get8(bscv_soft_state_t *, int, bscv_addr_t); 107*1c42de6dSgd78059 static uint16_t bscv_get16(bscv_soft_state_t *, int, bscv_addr_t); 108*1c42de6dSgd78059 static uint32_t bscv_get32(bscv_soft_state_t *, int, bscv_addr_t); 109*1c42de6dSgd78059 static void bscv_setclear8(bscv_soft_state_t *, int, 110*1c42de6dSgd78059 bscv_addr_t, uint8_t, uint8_t); 111*1c42de6dSgd78059 static void bscv_setclear8_volatile(bscv_soft_state_t *, int, 112*1c42de6dSgd78059 bscv_addr_t, uint8_t, uint8_t); 113*1c42de6dSgd78059 static void bscv_rep_rw8(bscv_soft_state_t *, int, 114*1c42de6dSgd78059 uint8_t *, bscv_addr_t, size_t, uint_t, boolean_t); 115*1c42de6dSgd78059 static uint8_t bscv_get8_cached(bscv_soft_state_t *, bscv_addr_t); 116*1c42de6dSgd78059 117*1c42de6dSgd78059 static uint8_t bscv_get8_locked(bscv_soft_state_t *, int, bscv_addr_t, int *); 118*1c42de6dSgd78059 static void bscv_rep_get8_locked(bscv_soft_state_t *, int, 119*1c42de6dSgd78059 uint8_t *, bscv_addr_t, size_t, uint_t, int *); 120*1c42de6dSgd78059 121*1c42de6dSgd78059 static boolean_t bscv_faulty(bscv_soft_state_t *); 122*1c42de6dSgd78059 static void bscv_clear_fault(bscv_soft_state_t *); 123*1c42de6dSgd78059 static void bscv_set_fault(bscv_soft_state_t *); 124*1c42de6dSgd78059 static boolean_t bscv_session_error(bscv_soft_state_t *); 125*1c42de6dSgd78059 static int bscv_retcode(bscv_soft_state_t *); 126*1c42de6dSgd78059 static int bscv_should_retry(bscv_soft_state_t *); 127*1c42de6dSgd78059 static void bscv_locked_result(bscv_soft_state_t *, int *); 128*1c42de6dSgd78059 129*1c42de6dSgd78059 static void bscv_put8_once(bscv_soft_state_t *, int, bscv_addr_t, uint8_t); 130*1c42de6dSgd78059 static uint8_t bscv_get8_once(bscv_soft_state_t *, int, bscv_addr_t); 131*1c42de6dSgd78059 static uint32_t bscv_probe(bscv_soft_state_t *, int, uint32_t *); 132*1c42de6dSgd78059 static void bscv_resync_comms(bscv_soft_state_t *, int); 133*1c42de6dSgd78059 134*1c42de6dSgd78059 static boolean_t bscv_window_setup(bscv_soft_state_t *); 135*1c42de6dSgd78059 static int bscv_eerw(bscv_soft_state_t *, uint32_t, uint8_t *, 136*1c42de6dSgd78059 unsigned, boolean_t); 137*1c42de6dSgd78059 138*1c42de6dSgd78059 static int bscv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 139*1c42de6dSgd78059 static int bscv_ioc_dogstate(bscv_soft_state_t *, intptr_t, int); 140*1c42de6dSgd78059 static int bscv_ioc_psustate(bscv_soft_state_t *, intptr_t, int); 141*1c42de6dSgd78059 static int bscv_ioc_fanstate(bscv_soft_state_t *, intptr_t, int); 142*1c42de6dSgd78059 static int bscv_ioc_fledstate(bscv_soft_state_t *, intptr_t, int); 143*1c42de6dSgd78059 static int bscv_ioc_ledstate(bscv_soft_state_t *, intptr_t, int); 144*1c42de6dSgd78059 static int bscv_ioc_info(bscv_soft_state_t *, intptr_t, int); 145*1c42de6dSgd78059 static int bscv_ioc_mread(bscv_soft_state_t *, intptr_t, int); 146*1c42de6dSgd78059 static int bscv_ioc_volts(bscv_soft_state_t *, intptr_t, int); 147*1c42de6dSgd78059 static int bscv_ioc_stats(bscv_soft_state_t *, intptr_t, int); 148*1c42de6dSgd78059 static int bscv_ioc_temp(bscv_soft_state_t *, intptr_t, int); 149*1c42de6dSgd78059 static int bscv_ioc_cons(bscv_soft_state_t *, intptr_t, int); 150*1c42de6dSgd78059 static int bscv_ioc_eventlog2(bscv_soft_state_t *, intptr_t, int); 151*1c42de6dSgd78059 static int bscv_ioc_info2(bscv_soft_state_t *, intptr_t, int); 152*1c42de6dSgd78059 static int bscv_ioc_test(bscv_soft_state_t *, intptr_t, int); 153*1c42de6dSgd78059 static int bscv_ioc_mprog2(bscv_soft_state_t *, intptr_t, int); 154*1c42de6dSgd78059 static int bscv_ioc_mread2(bscv_soft_state_t *, intptr_t, int); 155*1c42de6dSgd78059 156*1c42de6dSgd78059 static void bscv_event_daemon(void *); 157*1c42de6dSgd78059 static void bscv_start_event_daemon(bscv_soft_state_t *); 158*1c42de6dSgd78059 static int bscv_stop_event_daemon(bscv_soft_state_t *); 159*1c42de6dSgd78059 static int bscv_pause_event_daemon(bscv_soft_state_t *); 160*1c42de6dSgd78059 static void bscv_resume_event_daemon(bscv_soft_state_t *); 161*1c42de6dSgd78059 static void bscv_event_process(bscv_soft_state_t *ssp, boolean_t); 162*1c42de6dSgd78059 static int bscv_event_validate(bscv_soft_state_t *, uint32_t, uint8_t); 163*1c42de6dSgd78059 static void bscv_event_process_one(bscv_soft_state_t *, lom_event_t *); 164*1c42de6dSgd78059 static void bscv_build_eventstring(bscv_soft_state_t *, 165*1c42de6dSgd78059 lom_event_t *, char *, char *); 166*1c42de6dSgd78059 static int bscv_level_of_event(lom_event_t *); 167*1c42de6dSgd78059 static void bscv_status(bscv_soft_state_t *, uint8_t, uint8_t); 168*1c42de6dSgd78059 char *bscv_get_label(char [][MAX_LOM2_NAME_STR], int, int); 169*1c42de6dSgd78059 static void bscv_generic_sysevent(bscv_soft_state_t *, char *, char *, char *, 170*1c42de6dSgd78059 char *, int32_t, char *); 171*1c42de6dSgd78059 static void bscv_sysevent(bscv_soft_state_t *, lom_event_t *); 172*1c42de6dSgd78059 173*1c42de6dSgd78059 static int bscv_prog(bscv_soft_state_t *, intptr_t, int); 174*1c42de6dSgd78059 static int bscv_prog_image(bscv_soft_state_t *, boolean_t, 175*1c42de6dSgd78059 uint8_t *, int, uint32_t); 176*1c42de6dSgd78059 static int bscv_prog_receive_image(bscv_soft_state_t *, lom_prog_t *, 177*1c42de6dSgd78059 uint8_t *, int); 178*1c42de6dSgd78059 static void bscv_leave_programming_mode(bscv_soft_state_t *, boolean_t); 179*1c42de6dSgd78059 static int bscv_prog_stop_lom(bscv_soft_state_t *); 180*1c42de6dSgd78059 static int bscv_prog_start_lom(bscv_soft_state_t *); 181*1c42de6dSgd78059 182*1c42de6dSgd78059 static int bscv_attach_common(bscv_soft_state_t *); 183*1c42de6dSgd78059 static int bscv_cleanup(bscv_soft_state_t *); 184*1c42de6dSgd78059 static void bscv_setup_capability(bscv_soft_state_t *); 185*1c42de6dSgd78059 static int bscv_probe_check(bscv_soft_state_t *); 186*1c42de6dSgd78059 static void bscv_setup_hostname(bscv_soft_state_t *); 187*1c42de6dSgd78059 static void bscv_read_hostname(bscv_soft_state_t *, char *); 188*1c42de6dSgd78059 static void bscv_write_hostname(bscv_soft_state_t *, char *, uint8_t); 189*1c42de6dSgd78059 static void bscv_setup_static_info(bscv_soft_state_t *); 190*1c42de6dSgd78059 static uint8_t bscv_read_env_name(bscv_soft_state_t *, uint8_t, 191*1c42de6dSgd78059 uint8_t, uint8_t, char [][MAX_LOM2_NAME_STR], int); 192*1c42de6dSgd78059 static void bscv_setup_events(bscv_soft_state_t *); 193*1c42de6dSgd78059 194*1c42de6dSgd78059 static void bscv_trace(bscv_soft_state_t *, char, const char *, 195*1c42de6dSgd78059 const char *, ...); 196*1c42de6dSgd78059 197*1c42de6dSgd78059 #ifdef __sparc 198*1c42de6dSgd78059 static void bscv_idi_init(); 199*1c42de6dSgd78059 static void bscv_idi_fini(); 200*1c42de6dSgd78059 static void bscv_idi_new_instance(dev_info_t *dip); 201*1c42de6dSgd78059 static void bscv_idi_clear_err(); 202*1c42de6dSgd78059 void bscv_idi_set(struct bscv_idi_info info); 203*1c42de6dSgd78059 static boolean_t bscv_idi_err(); 204*1c42de6dSgd78059 static boolean_t bscv_nodename_set(struct bscv_idi_info info); 205*1c42de6dSgd78059 static boolean_t bscv_sig_set(struct bscv_idi_info info); 206*1c42de6dSgd78059 static boolean_t bscv_wdog_pat(struct bscv_idi_info info); 207*1c42de6dSgd78059 static boolean_t bscv_wdog_cfg(struct bscv_idi_info info); 208*1c42de6dSgd78059 static void bscv_write_sig(bscv_soft_state_t *ssp, bscv_sig_t s); 209*1c42de6dSgd78059 #endif /* __sparc */ 210*1c42de6dSgd78059 211*1c42de6dSgd78059 static void bscv_setup_watchdog(bscv_soft_state_t *ssp); 212*1c42de6dSgd78059 static void bscv_write_wdog_cfg(bscv_soft_state_t *, 213*1c42de6dSgd78059 uint_t, boolean_t, uint8_t); 214*1c42de6dSgd78059 215*1c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 216*1c42de6dSgd78059 static void bscv_inform_bsc(bscv_soft_state_t *, uint32_t); 217*1c42de6dSgd78059 static void bscv_watchdog_pat_request(void *); 218*1c42de6dSgd78059 static void bscv_watchdog_cfg_request(bscv_soft_state_t *, uint8_t); 219*1c42de6dSgd78059 static uint_t bscv_set_watchdog_timer(bscv_soft_state_t *, uint_t); 220*1c42de6dSgd78059 static void bscv_clear_watchdog_timer(bscv_soft_state_t *); 221*1c42de6dSgd78059 222*1c42de6dSgd78059 static boolean_t bscv_panic_callback(void *, int); 223*1c42de6dSgd78059 static void bscv_watchdog_cyclic_add(bscv_soft_state_t *); 224*1c42de6dSgd78059 static void bscv_watchdog_cyclic_remove(bscv_soft_state_t *); 225*1c42de6dSgd78059 226*1c42de6dSgd78059 extern kmutex_t cpu_lock; /* needed for cyclics */ 227*1c42de6dSgd78059 static uint8_t wdog_reset_on_timeout = 1; 228*1c42de6dSgd78059 229*1c42de6dSgd78059 #define WDOG_ON 1 230*1c42de6dSgd78059 #define WDOG_OFF 0 231*1c42de6dSgd78059 #define CLK_WATCHDOG_DEFAULT 10 /* 10 seconds */ 232*1c42de6dSgd78059 #define WATCHDOG_PAT_INTERVAL 1000000000 /* 1 second */ 233*1c42de6dSgd78059 234*1c42de6dSgd78059 static int bscv_watchdog_enable; 235*1c42de6dSgd78059 static int bscv_watchdog_available; 236*1c42de6dSgd78059 static int watchdog_activated; 237*1c42de6dSgd78059 static uint_t bscv_watchdog_timeout_seconds; 238*1c42de6dSgd78059 #endif /* __i386 || __amd64 */ 239*1c42de6dSgd78059 240*1c42de6dSgd78059 #ifdef __sparc 241*1c42de6dSgd78059 struct bscv_idi_callout bscv_idi_callout_table[] = { 242*1c42de6dSgd78059 {BSCV_IDI_NODENAME, &bscv_nodename_set }, 243*1c42de6dSgd78059 {BSCV_IDI_SIG, &bscv_sig_set }, 244*1c42de6dSgd78059 {BSCV_IDI_WDOG_PAT, &bscv_wdog_pat }, 245*1c42de6dSgd78059 {BSCV_IDI_WDOG_CFG, &bscv_wdog_cfg }, 246*1c42de6dSgd78059 {BSCV_IDI_NULL, NULL } 247*1c42de6dSgd78059 }; 248*1c42de6dSgd78059 249*1c42de6dSgd78059 static struct bscv_idi_callout_mgr bscv_idi_mgr; 250*1c42de6dSgd78059 #endif /* __sparc */ 251*1c42de6dSgd78059 252*1c42de6dSgd78059 /* 253*1c42de6dSgd78059 * Local Definitions 254*1c42de6dSgd78059 */ 255*1c42de6dSgd78059 #define STATUS_READ_LIMIT 8 /* Read up to 8 status changes at a time */ 256*1c42de6dSgd78059 #define MYNAME "bscv" 257*1c42de6dSgd78059 #define BSCV_INST_TO_MINOR(i) (i) 258*1c42de6dSgd78059 #define BSCV_MINOR_TO_INST(m) (m) 259*1c42de6dSgd78059 #define ddi_driver_major(dip) ddi_name_to_major(ddi_binding_name(dip)) 260*1c42de6dSgd78059 261*1c42de6dSgd78059 /* 262*1c42de6dSgd78059 * Strings for daemon event reporting 263*1c42de6dSgd78059 */ 264*1c42de6dSgd78059 265*1c42de6dSgd78059 static char *eventSubsysStrings[] = 266*1c42de6dSgd78059 { "", /* 00 */ 267*1c42de6dSgd78059 "Alarm ", /* 01 */ 268*1c42de6dSgd78059 "temperature sensor ", /* 02 */ 269*1c42de6dSgd78059 "overheat sensor ", /* 03 */ 270*1c42de6dSgd78059 "Fan ", /* 04 */ 271*1c42de6dSgd78059 "supply rail ", /* 05 */ 272*1c42de6dSgd78059 "circuit breaker ", /* 06 */ 273*1c42de6dSgd78059 "PSU ", /* 07 */ 274*1c42de6dSgd78059 "user ", /* 08 */ 275*1c42de6dSgd78059 "phonehome ", /* 09; unutilized */ 276*1c42de6dSgd78059 "LOM ", /* 0a */ 277*1c42de6dSgd78059 "host ", /* 0b */ 278*1c42de6dSgd78059 "event log ", /* 0c */ 279*1c42de6dSgd78059 "", /* 0d; EVENT_SUBSYS_EXTRA unutilized */ 280*1c42de6dSgd78059 "LED ", /* 0e */ 281*1c42de6dSgd78059 }; 282*1c42de6dSgd78059 283*1c42de6dSgd78059 static char *eventTypeStrings[] = 284*1c42de6dSgd78059 { 285*1c42de6dSgd78059 "[null event]", /* 00 */ 286*1c42de6dSgd78059 "ON", /* 01 */ 287*1c42de6dSgd78059 "OFF", /* 02 */ 288*1c42de6dSgd78059 "state change", /* 03 */ 289*1c42de6dSgd78059 "power on", /* 04 */ 290*1c42de6dSgd78059 "power off", /* 05 */ 291*1c42de6dSgd78059 "powered off unexpectedly", /* 06 */ 292*1c42de6dSgd78059 "reset unexpectedly", /* 07 */ 293*1c42de6dSgd78059 "booted", /* 08 */ 294*1c42de6dSgd78059 "watchdog enabled", /* 09 */ 295*1c42de6dSgd78059 "watchdog disabled", /* 0a */ 296*1c42de6dSgd78059 "watchdog triggered", /* 0b */ 297*1c42de6dSgd78059 "failed", /* 0c */ 298*1c42de6dSgd78059 "recovered", /* 0d */ 299*1c42de6dSgd78059 "reset", /* 0e */ 300*1c42de6dSgd78059 "XIR reset", /* 0f */ 301*1c42de6dSgd78059 "console selected", /* 10 */ 302*1c42de6dSgd78059 "time reference", /* 11 */ 303*1c42de6dSgd78059 "script failure", /* 12 */ 304*1c42de6dSgd78059 "modem access failure", /* 13 */ 305*1c42de6dSgd78059 "modem dialing failure", /* 14 */ 306*1c42de6dSgd78059 "bad checksum", /* 15 */ 307*1c42de6dSgd78059 "added", /* 16 */ 308*1c42de6dSgd78059 "removed", /* 17 */ 309*1c42de6dSgd78059 "changed", /* 18 */ 310*1c42de6dSgd78059 "login", /* 19 */ 311*1c42de6dSgd78059 "password changed", /* 1a */ 312*1c42de6dSgd78059 "login failed", /* 1b */ 313*1c42de6dSgd78059 "logout", /* 1c */ 314*1c42de6dSgd78059 "flash download", /* 1d */ 315*1c42de6dSgd78059 "data lost", /* 1e */ 316*1c42de6dSgd78059 "device busy", /* 1f */ 317*1c42de6dSgd78059 "fault led state", /* 20 */ 318*1c42de6dSgd78059 "overheat", /* 21 */ 319*1c42de6dSgd78059 "severe overheat", /* 22 */ 320*1c42de6dSgd78059 "no overheat", /* 23 */ 321*1c42de6dSgd78059 "SCC", /* 24 */ 322*1c42de6dSgd78059 "device inaccessible", /* 25 */ 323*1c42de6dSgd78059 "Hostname change", /* 26 */ 324*1c42de6dSgd78059 "CPU signature timeout", /* 27 */ 325*1c42de6dSgd78059 "Bootmode change", /* 28 */ 326*1c42de6dSgd78059 "Watchdog change policy", /* 29 */ 327*1c42de6dSgd78059 "Watchdog change timeout", /* 2a */ 328*1c42de6dSgd78059 }; 329*1c42de6dSgd78059 330*1c42de6dSgd78059 /* 331*1c42de6dSgd78059 * These store to mapping between the logical service, e.g. chan_prog for 332*1c42de6dSgd78059 * programming, and the actual Xbus channel which carries that traffic. 333*1c42de6dSgd78059 * Any services can be shared on the same channel apart from chan_wdogpat. 334*1c42de6dSgd78059 */ 335*1c42de6dSgd78059 static int chan_general; /* General Traffic */ 336*1c42de6dSgd78059 static int chan_wdogpat; /* Watchdog Patting */ 337*1c42de6dSgd78059 static int chan_cpusig; /* CPU signatures */ 338*1c42de6dSgd78059 static int chan_eeprom; /* EEPROM I/O */ 339*1c42de6dSgd78059 static int chan_prog; /* Programming */ 340*1c42de6dSgd78059 341*1c42de6dSgd78059 /* 342*1c42de6dSgd78059 * cb_ops structure defining the driver entry points 343*1c42de6dSgd78059 */ 344*1c42de6dSgd78059 345*1c42de6dSgd78059 static struct cb_ops bscv_cb_ops = { 346*1c42de6dSgd78059 bscv_open, /* open */ 347*1c42de6dSgd78059 bscv_close, /* close */ 348*1c42de6dSgd78059 nodev, /* strategy */ 349*1c42de6dSgd78059 nodev, /* print */ 350*1c42de6dSgd78059 nodev, /* dump */ 351*1c42de6dSgd78059 nodev, /* read */ 352*1c42de6dSgd78059 nodev, /* write */ 353*1c42de6dSgd78059 bscv_ioctl, /* ioctl */ 354*1c42de6dSgd78059 nodev, /* devmap */ 355*1c42de6dSgd78059 nodev, /* mmap */ 356*1c42de6dSgd78059 nodev, /* segmap */ 357*1c42de6dSgd78059 nochpoll, /* poll */ 358*1c42de6dSgd78059 ddi_prop_op, /* prop op */ 359*1c42de6dSgd78059 NULL, /* ! STREAMS */ 360*1c42de6dSgd78059 D_NEW | D_MP /* MT/MP Safe */ 361*1c42de6dSgd78059 }; 362*1c42de6dSgd78059 363*1c42de6dSgd78059 /* 364*1c42de6dSgd78059 * dev_ops structure defining autoconfiguration driver autoconfiguration 365*1c42de6dSgd78059 * routines 366*1c42de6dSgd78059 */ 367*1c42de6dSgd78059 368*1c42de6dSgd78059 static struct dev_ops bscv_dev_ops = { 369*1c42de6dSgd78059 DEVO_REV, /* devo_rev */ 370*1c42de6dSgd78059 0, /* devo_refcnt */ 371*1c42de6dSgd78059 bscv_getinfo, /* devo_getinfo */ 372*1c42de6dSgd78059 nulldev, /* devo_identify */ 373*1c42de6dSgd78059 nulldev, /* devo_probe */ 374*1c42de6dSgd78059 bscv_attach, /* devo_attach */ 375*1c42de6dSgd78059 bscv_detach, /* devo_detach */ 376*1c42de6dSgd78059 bscv_reset, /* devo_reset */ 377*1c42de6dSgd78059 &bscv_cb_ops, /* devo_cb_ops */ 378*1c42de6dSgd78059 (struct bus_ops *)0 /* devo_bus_ops */ 379*1c42de6dSgd78059 }; 380*1c42de6dSgd78059 381*1c42de6dSgd78059 /* 382*1c42de6dSgd78059 * module configuration section 383*1c42de6dSgd78059 */ 384*1c42de6dSgd78059 385*1c42de6dSgd78059 #ifdef DEBUG 386*1c42de6dSgd78059 #define BSCV_VERSION_STRING "bscv driver - Debug v%I%" 387*1c42de6dSgd78059 #else /* DEBUG */ 388*1c42de6dSgd78059 #define BSCV_VERSION_STRING "bscv driver v%I%" 389*1c42de6dSgd78059 #endif /* DEBUG */ 390*1c42de6dSgd78059 391*1c42de6dSgd78059 static struct modldrv modldrv = { 392*1c42de6dSgd78059 &mod_driverops, 393*1c42de6dSgd78059 BSCV_VERSION_STRING, 394*1c42de6dSgd78059 &bscv_dev_ops, 395*1c42de6dSgd78059 }; 396*1c42de6dSgd78059 397*1c42de6dSgd78059 static struct modlinkage modlinkage = { 398*1c42de6dSgd78059 MODREV_1, 399*1c42de6dSgd78059 &modldrv, 400*1c42de6dSgd78059 NULL 401*1c42de6dSgd78059 }; 402*1c42de6dSgd78059 403*1c42de6dSgd78059 /* 404*1c42de6dSgd78059 * kernel accessible routines. These routines are necessarily global so the 405*1c42de6dSgd78059 * driver can be loaded, and unloaded successfully 406*1c42de6dSgd78059 */ 407*1c42de6dSgd78059 408*1c42de6dSgd78059 /* 409*1c42de6dSgd78059 * function - _init 410*1c42de6dSgd78059 * description - initializes the driver state structure and installs the 411*1c42de6dSgd78059 * driver module into the kernel 412*1c42de6dSgd78059 * inputs - none 413*1c42de6dSgd78059 * outputs - success or failure of module installation 414*1c42de6dSgd78059 */ 415*1c42de6dSgd78059 416*1c42de6dSgd78059 int 417*1c42de6dSgd78059 _init(void) 418*1c42de6dSgd78059 { 419*1c42de6dSgd78059 register int e; 420*1c42de6dSgd78059 421*1c42de6dSgd78059 if ((e = ddi_soft_state_init(&bscv_statep, 422*1c42de6dSgd78059 sizeof (bscv_soft_state_t), 1)) != 0) { 423*1c42de6dSgd78059 return (e); 424*1c42de6dSgd78059 } 425*1c42de6dSgd78059 426*1c42de6dSgd78059 if ((e = mod_install(&modlinkage)) != 0) { 427*1c42de6dSgd78059 ddi_soft_state_fini(&bscv_statep); 428*1c42de6dSgd78059 } 429*1c42de6dSgd78059 430*1c42de6dSgd78059 #ifdef __sparc 431*1c42de6dSgd78059 if (e == 0) bscv_idi_init(); 432*1c42de6dSgd78059 #endif /* __sparc */ 433*1c42de6dSgd78059 return (e); 434*1c42de6dSgd78059 } 435*1c42de6dSgd78059 436*1c42de6dSgd78059 /* 437*1c42de6dSgd78059 * function - _info 438*1c42de6dSgd78059 * description - provide information about a kernel loaded module 439*1c42de6dSgd78059 * inputs - module infomation 440*1c42de6dSgd78059 * outputs - success or failure of information request 441*1c42de6dSgd78059 */ 442*1c42de6dSgd78059 443*1c42de6dSgd78059 int 444*1c42de6dSgd78059 _info(struct modinfo *modinfop) 445*1c42de6dSgd78059 { 446*1c42de6dSgd78059 return (mod_info(&modlinkage, modinfop)); 447*1c42de6dSgd78059 } 448*1c42de6dSgd78059 449*1c42de6dSgd78059 /* 450*1c42de6dSgd78059 * function - _fini 451*1c42de6dSgd78059 * description - removes a module from the kernel and frees the driver soft 452*1c42de6dSgd78059 * state memory 453*1c42de6dSgd78059 * inputs - none 454*1c42de6dSgd78059 * outputs - success or failure of module removal 455*1c42de6dSgd78059 */ 456*1c42de6dSgd78059 457*1c42de6dSgd78059 int 458*1c42de6dSgd78059 _fini(void) 459*1c42de6dSgd78059 { 460*1c42de6dSgd78059 register int e; 461*1c42de6dSgd78059 462*1c42de6dSgd78059 if ((e = mod_remove(&modlinkage)) != 0) { 463*1c42de6dSgd78059 return (e); 464*1c42de6dSgd78059 } 465*1c42de6dSgd78059 466*1c42de6dSgd78059 #ifdef __sparc 467*1c42de6dSgd78059 bscv_idi_fini(); 468*1c42de6dSgd78059 #endif /* __sparc */ 469*1c42de6dSgd78059 ddi_soft_state_fini(&bscv_statep); 470*1c42de6dSgd78059 471*1c42de6dSgd78059 return (e); 472*1c42de6dSgd78059 } 473*1c42de6dSgd78059 474*1c42de6dSgd78059 /* 475*1c42de6dSgd78059 * function - bscv_getinfo 476*1c42de6dSgd78059 * description - routine used to provide information on the driver 477*1c42de6dSgd78059 * inputs - device information structure, command, command arg, storage 478*1c42de6dSgd78059 * area for the result 479*1c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 480*1c42de6dSgd78059 */ 481*1c42de6dSgd78059 482*1c42de6dSgd78059 /*ARGSUSED*/ 483*1c42de6dSgd78059 static int 484*1c42de6dSgd78059 bscv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 485*1c42de6dSgd78059 { 486*1c42de6dSgd78059 bscv_soft_state_t *ssp; 487*1c42de6dSgd78059 dev_t dev = (dev_t)arg; 488*1c42de6dSgd78059 int instance; 489*1c42de6dSgd78059 int error; 490*1c42de6dSgd78059 491*1c42de6dSgd78059 instance = DEVICETOINSTANCE(dev); 492*1c42de6dSgd78059 493*1c42de6dSgd78059 switch (cmd) { 494*1c42de6dSgd78059 case DDI_INFO_DEVT2INSTANCE: 495*1c42de6dSgd78059 *result = (void *)(uintptr_t)instance; 496*1c42de6dSgd78059 error = DDI_SUCCESS; 497*1c42de6dSgd78059 break; 498*1c42de6dSgd78059 499*1c42de6dSgd78059 case DDI_INFO_DEVT2DEVINFO: 500*1c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, instance); 501*1c42de6dSgd78059 if (ssp == NULL) 502*1c42de6dSgd78059 return (DDI_FAILURE); 503*1c42de6dSgd78059 *result = (void *) ssp->dip; 504*1c42de6dSgd78059 error = DDI_SUCCESS; 505*1c42de6dSgd78059 break; 506*1c42de6dSgd78059 507*1c42de6dSgd78059 default: 508*1c42de6dSgd78059 error = DDI_FAILURE; 509*1c42de6dSgd78059 break; 510*1c42de6dSgd78059 } 511*1c42de6dSgd78059 512*1c42de6dSgd78059 return (error); 513*1c42de6dSgd78059 } 514*1c42de6dSgd78059 515*1c42de6dSgd78059 #ifdef __sparc 516*1c42de6dSgd78059 void 517*1c42de6dSgd78059 bscv_idi_init() 518*1c42de6dSgd78059 { 519*1c42de6dSgd78059 bscv_idi_mgr.valid_inst = (uint32_t)~0; /* No valid instances */ 520*1c42de6dSgd78059 bscv_idi_mgr.tbl = bscv_idi_callout_table; 521*1c42de6dSgd78059 bscv_idi_mgr.errs = 0; 522*1c42de6dSgd78059 523*1c42de6dSgd78059 /* 524*1c42de6dSgd78059 * Now that all fields are initialized, set the magic flag. This is 525*1c42de6dSgd78059 * a kind of integrity check for the data structure. 526*1c42de6dSgd78059 */ 527*1c42de6dSgd78059 bscv_idi_mgr.magic = BSCV_IDI_CALLOUT_MAGIC; 528*1c42de6dSgd78059 } 529*1c42de6dSgd78059 530*1c42de6dSgd78059 static void 531*1c42de6dSgd78059 bscv_idi_clear_err() 532*1c42de6dSgd78059 { 533*1c42de6dSgd78059 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC); 534*1c42de6dSgd78059 535*1c42de6dSgd78059 bscv_idi_mgr.errs = 0; 536*1c42de6dSgd78059 } 537*1c42de6dSgd78059 538*1c42de6dSgd78059 /* 539*1c42de6dSgd78059 * function - bscv_idi_err 540*1c42de6dSgd78059 * description - error messaging service which throttles the number of error 541*1c42de6dSgd78059 * messages to avoid overflowing storage 542*1c42de6dSgd78059 * inputs - none 543*1c42de6dSgd78059 * returns - boolean to indicate whether a message should be reported 544*1c42de6dSgd78059 * side-effects - updates the error number counter 545*1c42de6dSgd78059 */ 546*1c42de6dSgd78059 static boolean_t 547*1c42de6dSgd78059 bscv_idi_err() 548*1c42de6dSgd78059 { 549*1c42de6dSgd78059 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC); 550*1c42de6dSgd78059 551*1c42de6dSgd78059 bscv_idi_mgr.errs++; 552*1c42de6dSgd78059 553*1c42de6dSgd78059 if (bscv_idi_mgr.errs++ < BSCV_IDI_ERR_MSG_THRESHOLD) 554*1c42de6dSgd78059 return (B_TRUE); 555*1c42de6dSgd78059 556*1c42de6dSgd78059 return (B_FALSE); 557*1c42de6dSgd78059 } 558*1c42de6dSgd78059 559*1c42de6dSgd78059 void 560*1c42de6dSgd78059 bscv_idi_new_instance(dev_info_t *dip) 561*1c42de6dSgd78059 { 562*1c42de6dSgd78059 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC); 563*1c42de6dSgd78059 564*1c42de6dSgd78059 /* 565*1c42de6dSgd78059 * We don't care how many instances we have, or their value, so long 566*1c42de6dSgd78059 * as we have at least one valid value. This is so service routines 567*1c42de6dSgd78059 * can get any required locks via a soft state pointer. 568*1c42de6dSgd78059 */ 569*1c42de6dSgd78059 if (bscv_idi_mgr.valid_inst == (uint32_t)~0) { 570*1c42de6dSgd78059 bscv_idi_mgr.valid_inst = ddi_get_instance(dip); 571*1c42de6dSgd78059 } 572*1c42de6dSgd78059 } 573*1c42de6dSgd78059 574*1c42de6dSgd78059 void 575*1c42de6dSgd78059 bscv_idi_fini() 576*1c42de6dSgd78059 { 577*1c42de6dSgd78059 bscv_idi_mgr.valid_inst = (uint32_t)~0; /* No valid instances */ 578*1c42de6dSgd78059 bscv_idi_mgr.tbl = NULL; 579*1c42de6dSgd78059 } 580*1c42de6dSgd78059 #endif /* __sparc */ 581*1c42de6dSgd78059 582*1c42de6dSgd78059 /* 583*1c42de6dSgd78059 * function - bscv_attach 584*1c42de6dSgd78059 * description - this routine is responsible for setting aside memory for the 585*1c42de6dSgd78059 * driver data structures, initialising the mutexes and creating 586*1c42de6dSgd78059 * the device minor nodes. Additionally, this routine calls the 587*1c42de6dSgd78059 * the callback routine. 588*1c42de6dSgd78059 * inputs - device information structure, DDI_ATTACH command 589*1c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 590*1c42de6dSgd78059 */ 591*1c42de6dSgd78059 592*1c42de6dSgd78059 int 593*1c42de6dSgd78059 bscv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 594*1c42de6dSgd78059 { 595*1c42de6dSgd78059 bscv_soft_state_t *ssp; 596*1c42de6dSgd78059 int instance; 597*1c42de6dSgd78059 598*1c42de6dSgd78059 switch (cmd) { 599*1c42de6dSgd78059 case DDI_ATTACH: 600*1c42de6dSgd78059 601*1c42de6dSgd78059 instance = ddi_get_instance(dip); 602*1c42de6dSgd78059 603*1c42de6dSgd78059 if (ddi_soft_state_zalloc(bscv_statep, instance) != 604*1c42de6dSgd78059 DDI_SUCCESS) { 605*1c42de6dSgd78059 return (DDI_FAILURE); 606*1c42de6dSgd78059 } 607*1c42de6dSgd78059 608*1c42de6dSgd78059 609*1c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, instance); 610*1c42de6dSgd78059 611*1c42de6dSgd78059 ssp->progress = 0; 612*1c42de6dSgd78059 613*1c42de6dSgd78059 ssp->dip = dip; 614*1c42de6dSgd78059 ssp->instance = instance; 615*1c42de6dSgd78059 ssp->event_waiting = B_FALSE; 616*1c42de6dSgd78059 ssp->status_change = B_FALSE; 617*1c42de6dSgd78059 ssp->nodename_change = B_FALSE; 618*1c42de6dSgd78059 ssp->cap0 = 0; 619*1c42de6dSgd78059 ssp->cap1 = 0; 620*1c42de6dSgd78059 ssp->cap2 = 0; 621*1c42de6dSgd78059 ssp->prog_mode_only = B_FALSE; 622*1c42de6dSgd78059 ssp->programming = B_FALSE; 623*1c42de6dSgd78059 ssp->cssp_prog = B_FALSE; 624*1c42de6dSgd78059 ssp->task_flags = 0; 625*1c42de6dSgd78059 ssp->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 626*1c42de6dSgd78059 DDI_PROP_DONTPASS, "debug", 0); 627*1c42de6dSgd78059 ssp->majornum = ddi_driver_major(dip); 628*1c42de6dSgd78059 ssp->minornum = BSCV_INST_TO_MINOR(instance); 629*1c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 630*1c42de6dSgd78059 ssp->last_nodename[0] = '\0'; 631*1c42de6dSgd78059 #endif /* __i386 || __amd64 */ 632*1c42de6dSgd78059 633*1c42de6dSgd78059 /* 634*1c42de6dSgd78059 * initialise the mutexes 635*1c42de6dSgd78059 */ 636*1c42de6dSgd78059 637*1c42de6dSgd78059 mutex_init(&ssp->cmd_mutex, NULL, MUTEX_DRIVER, NULL); 638*1c42de6dSgd78059 639*1c42de6dSgd78059 mutex_init(&ssp->task_mu, NULL, MUTEX_DRIVER, NULL); 640*1c42de6dSgd78059 cv_init(&ssp->task_cv, NULL, CV_DRIVER, NULL); 641*1c42de6dSgd78059 cv_init(&ssp->task_evnt_cv, NULL, CV_DRIVER, NULL); 642*1c42de6dSgd78059 mutex_init(&ssp->prog_mu, NULL, MUTEX_DRIVER, NULL); 643*1c42de6dSgd78059 ssp->progress |= BSCV_LOCKS; 644*1c42de6dSgd78059 645*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_attach", 646*1c42de6dSgd78059 "bscv_attach: mutexes and condition vars initialised"); 647*1c42de6dSgd78059 648*1c42de6dSgd78059 /* Map in physical communication channels */ 649*1c42de6dSgd78059 650*1c42de6dSgd78059 if (bscv_map_regs(ssp) != DDI_SUCCESS) { 651*1c42de6dSgd78059 (void) bscv_cleanup(ssp); 652*1c42de6dSgd78059 return (DDI_FAILURE); 653*1c42de6dSgd78059 } 654*1c42de6dSgd78059 ssp->progress |= BSCV_MAPPED_REGS; 655*1c42de6dSgd78059 656*1c42de6dSgd78059 /* Associate logical channels to physical channels */ 657*1c42de6dSgd78059 658*1c42de6dSgd78059 bscv_map_chan_logical_physical(ssp); 659*1c42de6dSgd78059 660*1c42de6dSgd78059 bscv_enter(ssp); 661*1c42de6dSgd78059 662*1c42de6dSgd78059 bscv_leave_programming_mode(ssp, B_FALSE); 663*1c42de6dSgd78059 664*1c42de6dSgd78059 if (bscv_attach_common(ssp) == DDI_FAILURE) { 665*1c42de6dSgd78059 bscv_exit(ssp); 666*1c42de6dSgd78059 (void) bscv_cleanup(ssp); 667*1c42de6dSgd78059 return (DDI_FAILURE); 668*1c42de6dSgd78059 } 669*1c42de6dSgd78059 670*1c42de6dSgd78059 #ifdef __sparc 671*1c42de6dSgd78059 /* 672*1c42de6dSgd78059 * At this point the inter-driver-interface is made available. 673*1c42de6dSgd78059 * The IDI uses the event thread service which 674*1c42de6dSgd78059 * bscv_attach_common() sets up. 675*1c42de6dSgd78059 */ 676*1c42de6dSgd78059 bscv_idi_new_instance(dip); 677*1c42de6dSgd78059 #endif /* __sparc */ 678*1c42de6dSgd78059 679*1c42de6dSgd78059 bscv_exit(ssp); 680*1c42de6dSgd78059 681*1c42de6dSgd78059 /* 682*1c42de6dSgd78059 * now create the minor nodes 683*1c42de6dSgd78059 */ 684*1c42de6dSgd78059 if (ddi_create_minor_node(ssp->dip, "lom", S_IFCHR, 685*1c42de6dSgd78059 BSCV_INST_TO_MINOR(instance), 686*1c42de6dSgd78059 DDI_PSEUDO, 0) != DDI_SUCCESS) { 687*1c42de6dSgd78059 (void) bscv_cleanup(ssp); 688*1c42de6dSgd78059 return (DDI_FAILURE); 689*1c42de6dSgd78059 } 690*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_attach", 691*1c42de6dSgd78059 "bscv_attach: device minor nodes created"); 692*1c42de6dSgd78059 ssp->progress |= BSCV_NODES; 693*1c42de6dSgd78059 694*1c42de6dSgd78059 if (!ssp->prog_mode_only) 695*1c42de6dSgd78059 bscv_start_event_daemon(ssp); 696*1c42de6dSgd78059 697*1c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 698*1c42de6dSgd78059 bscv_watchdog_enable = 1; 699*1c42de6dSgd78059 bscv_watchdog_available = 1; 700*1c42de6dSgd78059 watchdog_activated = 0; 701*1c42de6dSgd78059 bscv_watchdog_timeout_seconds = CLK_WATCHDOG_DEFAULT; 702*1c42de6dSgd78059 703*1c42de6dSgd78059 if (bscv_watchdog_enable && (boothowto & RB_DEBUG)) { 704*1c42de6dSgd78059 bscv_watchdog_available = 0; 705*1c42de6dSgd78059 cmn_err(CE_WARN, "bscv: kernel debugger " 706*1c42de6dSgd78059 "detected: hardware watchdog disabled"); 707*1c42de6dSgd78059 } 708*1c42de6dSgd78059 709*1c42de6dSgd78059 /* 710*1c42de6dSgd78059 * Before we enable the watchdog - register the panic 711*1c42de6dSgd78059 * callback so that we get called to stop the watchdog 712*1c42de6dSgd78059 * in the case of a panic. 713*1c42de6dSgd78059 */ 714*1c42de6dSgd78059 ssp->callb_id = callb_add(bscv_panic_callback, 715*1c42de6dSgd78059 (void *)ssp, CB_CL_PANIC, ""); 716*1c42de6dSgd78059 717*1c42de6dSgd78059 if (bscv_watchdog_available) { 718*1c42de6dSgd78059 (void) bscv_set_watchdog_timer(ssp, 719*1c42de6dSgd78059 CLK_WATCHDOG_DEFAULT); 720*1c42de6dSgd78059 bscv_enter(ssp); 721*1c42de6dSgd78059 bscv_setup_watchdog(ssp); /* starts cyclic callback */ 722*1c42de6dSgd78059 bscv_exit(ssp); 723*1c42de6dSgd78059 } 724*1c42de6dSgd78059 #endif /* __i386 || __amd64 */ 725*1c42de6dSgd78059 ddi_report_dev(dip); 726*1c42de6dSgd78059 return (DDI_SUCCESS); 727*1c42de6dSgd78059 default: 728*1c42de6dSgd78059 return (DDI_FAILURE); 729*1c42de6dSgd78059 } 730*1c42de6dSgd78059 } 731*1c42de6dSgd78059 732*1c42de6dSgd78059 /* 733*1c42de6dSgd78059 * function - bscv_detach 734*1c42de6dSgd78059 * description - routine that prepares a module to be unloaded. It undoes all 735*1c42de6dSgd78059 * the work done by the bscv_attach)() routine. This is 736*1c42de6dSgd78059 * facilitated by the use of the progress indicator 737*1c42de6dSgd78059 * inputs - device information structure, DDI_DETACH command 738*1c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 739*1c42de6dSgd78059 */ 740*1c42de6dSgd78059 741*1c42de6dSgd78059 /*ARGSUSED*/ 742*1c42de6dSgd78059 static int 743*1c42de6dSgd78059 bscv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 744*1c42de6dSgd78059 { 745*1c42de6dSgd78059 return (DDI_FAILURE); 746*1c42de6dSgd78059 } 747*1c42de6dSgd78059 748*1c42de6dSgd78059 /* 749*1c42de6dSgd78059 * function - bscv_reset 750*1c42de6dSgd78059 * description - routine called when system is being stopped - used to disable 751*1c42de6dSgd78059 * the watchdog. 752*1c42de6dSgd78059 * inputs - device information structure, DDI_RESET command 753*1c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 754*1c42de6dSgd78059 */ 755*1c42de6dSgd78059 static int 756*1c42de6dSgd78059 bscv_reset(dev_info_t *dip, ddi_reset_cmd_t cmd) 757*1c42de6dSgd78059 { 758*1c42de6dSgd78059 bscv_soft_state_t *ssp; 759*1c42de6dSgd78059 int instance; 760*1c42de6dSgd78059 761*1c42de6dSgd78059 switch (cmd) { 762*1c42de6dSgd78059 case DDI_RESET_FORCE: 763*1c42de6dSgd78059 764*1c42de6dSgd78059 instance = ddi_get_instance(dip); 765*1c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, instance); 766*1c42de6dSgd78059 if (ssp == NULL) { 767*1c42de6dSgd78059 return (DDI_FAILURE); 768*1c42de6dSgd78059 } 769*1c42de6dSgd78059 bscv_full_stop(ssp); 770*1c42de6dSgd78059 return (DDI_SUCCESS); 771*1c42de6dSgd78059 772*1c42de6dSgd78059 default: 773*1c42de6dSgd78059 return (DDI_FAILURE); 774*1c42de6dSgd78059 } 775*1c42de6dSgd78059 } 776*1c42de6dSgd78059 777*1c42de6dSgd78059 /* 778*1c42de6dSgd78059 * cb_ops routines 779*1c42de6dSgd78059 */ 780*1c42de6dSgd78059 781*1c42de6dSgd78059 /* 782*1c42de6dSgd78059 * function - bscv_open 783*1c42de6dSgd78059 * description - routine to provide association between user fd and device 784*1c42de6dSgd78059 * minor number. This routine is necessarily simple since a 785*1c42de6dSgd78059 * read/write interface is not provided. Additionally, the 786*1c42de6dSgd78059 * driver does not enforce exclusive access (FEXCL) or 787*1c42de6dSgd78059 * non-blocking during an open (FNDELAY). Deferred attach is 788*1c42de6dSgd78059 * supported. 789*1c42de6dSgd78059 * inputs - device number, flag specifying open type, device type, 790*1c42de6dSgd78059 * permissions 791*1c42de6dSgd78059 * outputs - success or failure of operation 792*1c42de6dSgd78059 */ 793*1c42de6dSgd78059 794*1c42de6dSgd78059 /*ARGSUSED*/ 795*1c42de6dSgd78059 static int 796*1c42de6dSgd78059 bscv_open(dev_t *devp, int flag, int otype, cred_t *cred) 797*1c42de6dSgd78059 { 798*1c42de6dSgd78059 bscv_soft_state_t *ssp; 799*1c42de6dSgd78059 int instance; 800*1c42de6dSgd78059 801*1c42de6dSgd78059 instance = DEVICETOINSTANCE(*devp); 802*1c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, instance); 803*1c42de6dSgd78059 if (ssp == NULL) { 804*1c42de6dSgd78059 return (ENXIO); /* not attached yet */ 805*1c42de6dSgd78059 } 806*1c42de6dSgd78059 bscv_trace(ssp, 'O', "bscv_open", "instance 0x%x", instance); 807*1c42de6dSgd78059 808*1c42de6dSgd78059 if (otype != OTYP_CHR) { 809*1c42de6dSgd78059 return (EINVAL); 810*1c42de6dSgd78059 } 811*1c42de6dSgd78059 812*1c42de6dSgd78059 return (0); 813*1c42de6dSgd78059 } 814*1c42de6dSgd78059 815*1c42de6dSgd78059 /* 816*1c42de6dSgd78059 * function - bscv_close 817*1c42de6dSgd78059 * description - routine to perform the final close on the device. As per the 818*1c42de6dSgd78059 * open routine, neither FEXCL or FNDELAY accesses are enforced 819*1c42de6dSgd78059 * by the driver. 820*1c42de6dSgd78059 * inputs - device number,flag specifying open type, device type, 821*1c42de6dSgd78059 * permissions 822*1c42de6dSgd78059 * outputs - success or failure of operation 823*1c42de6dSgd78059 */ 824*1c42de6dSgd78059 825*1c42de6dSgd78059 /*ARGSUSED1*/ 826*1c42de6dSgd78059 static int 827*1c42de6dSgd78059 bscv_close(dev_t dev, int flag, int otype, cred_t *cred) 828*1c42de6dSgd78059 { 829*1c42de6dSgd78059 bscv_soft_state_t *ssp; 830*1c42de6dSgd78059 int instance; 831*1c42de6dSgd78059 832*1c42de6dSgd78059 instance = DEVICETOINSTANCE(dev); 833*1c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, instance); 834*1c42de6dSgd78059 if (ssp == NULL) { 835*1c42de6dSgd78059 return (ENXIO); 836*1c42de6dSgd78059 } 837*1c42de6dSgd78059 bscv_trace(ssp, 'O', "bscv_close", "instance 0x%x", instance); 838*1c42de6dSgd78059 839*1c42de6dSgd78059 return (0); 840*1c42de6dSgd78059 } 841*1c42de6dSgd78059 842*1c42de6dSgd78059 static int 843*1c42de6dSgd78059 bscv_map_regs(bscv_soft_state_t *ssp) 844*1c42de6dSgd78059 { 845*1c42de6dSgd78059 int i; 846*1c42de6dSgd78059 int retval; 847*1c42de6dSgd78059 int *props; 848*1c42de6dSgd78059 unsigned int nelements; 849*1c42de6dSgd78059 850*1c42de6dSgd78059 ASSERT(ssp); 851*1c42de6dSgd78059 852*1c42de6dSgd78059 ssp->nchannels = 0; 853*1c42de6dSgd78059 854*1c42de6dSgd78059 /* 855*1c42de6dSgd78059 * Work out how many channels are available by looking at the number 856*1c42de6dSgd78059 * of elements of the regs property array. 857*1c42de6dSgd78059 */ 858*1c42de6dSgd78059 retval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ssp->dip, 859*1c42de6dSgd78059 DDI_PROP_DONTPASS, "reg", &props, &nelements); 860*1c42de6dSgd78059 861*1c42de6dSgd78059 /* We don't need props anymore. Free memory if it was allocated */ 862*1c42de6dSgd78059 if (retval == DDI_PROP_SUCCESS) 863*1c42de6dSgd78059 ddi_prop_free(props); 864*1c42de6dSgd78059 865*1c42de6dSgd78059 /* Check for sanity of nelements */ 866*1c42de6dSgd78059 if (retval != DDI_PROP_SUCCESS) { 867*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_map_regs", "lookup reg returned" 868*1c42de6dSgd78059 " 0x%x", retval); 869*1c42de6dSgd78059 goto cleanup_exit; 870*1c42de6dSgd78059 } else if (nelements % LOMBUS_REGSPEC_SIZE != 0) { 871*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_map_regs", "nelements %d not" 872*1c42de6dSgd78059 " a multiple of %d", nelements, LOMBUS_REGSPEC_SIZE); 873*1c42de6dSgd78059 goto cleanup_exit; 874*1c42de6dSgd78059 } else if (nelements > BSCV_MAXCHANNELS * LOMBUS_REGSPEC_SIZE) { 875*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_map_regs", "nelements %d too large" 876*1c42de6dSgd78059 ", probably a misconfiguration", nelements); 877*1c42de6dSgd78059 goto cleanup_exit; 878*1c42de6dSgd78059 } else if (nelements < BSCV_MINCHANNELS * LOMBUS_REGSPEC_SIZE) { 879*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_map_regs", "nelements %d too small" 880*1c42de6dSgd78059 ", need to have at least a general and a wdog channel", 881*1c42de6dSgd78059 nelements); 882*1c42de6dSgd78059 goto cleanup_exit; 883*1c42de6dSgd78059 } 884*1c42de6dSgd78059 885*1c42de6dSgd78059 ssp->nchannels = nelements / LOMBUS_REGSPEC_SIZE; 886*1c42de6dSgd78059 887*1c42de6dSgd78059 ssp->attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 888*1c42de6dSgd78059 ssp->attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 889*1c42de6dSgd78059 ssp->attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 890*1c42de6dSgd78059 891*1c42de6dSgd78059 for (i = 0; i < ssp->nchannels; i++) { 892*1c42de6dSgd78059 retval = ddi_regs_map_setup(ssp->dip, i, 893*1c42de6dSgd78059 (caddr_t *)&ssp->channel[i].regs, 894*1c42de6dSgd78059 0, 0, &ssp->attr, &ssp->channel[i].handle); 895*1c42de6dSgd78059 if (retval != DDI_SUCCESS) { 896*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_map_regs", "map failure" 897*1c42de6dSgd78059 " 0x%x on space %d", retval, i); 898*1c42de6dSgd78059 899*1c42de6dSgd78059 /* Rewind all current mappings - avoiding failed one */ 900*1c42de6dSgd78059 i--; 901*1c42de6dSgd78059 for (; i >= 0; i--) { 902*1c42de6dSgd78059 ddi_regs_map_free(&ssp->channel[i].handle); 903*1c42de6dSgd78059 } 904*1c42de6dSgd78059 905*1c42de6dSgd78059 goto cleanup_exit; 906*1c42de6dSgd78059 } 907*1c42de6dSgd78059 } 908*1c42de6dSgd78059 909*1c42de6dSgd78059 return (DDI_SUCCESS); 910*1c42de6dSgd78059 911*1c42de6dSgd78059 cleanup_exit: 912*1c42de6dSgd78059 /* 913*1c42de6dSgd78059 * It is important to set nchannels to 0 even if, say, only one of 914*1c42de6dSgd78059 * the two required handles was mapped. If we cannot achieve our 915*1c42de6dSgd78059 * minimum config its not safe to do any IO; this keeps our failure 916*1c42de6dSgd78059 * mode handling simpler. 917*1c42de6dSgd78059 */ 918*1c42de6dSgd78059 ssp->nchannels = 0; 919*1c42de6dSgd78059 return (DDI_FAILURE); 920*1c42de6dSgd78059 } 921*1c42de6dSgd78059 922*1c42de6dSgd78059 static void 923*1c42de6dSgd78059 bscv_unmap_regs(bscv_soft_state_t *ssp) 924*1c42de6dSgd78059 { 925*1c42de6dSgd78059 int i; 926*1c42de6dSgd78059 927*1c42de6dSgd78059 ASSERT(ssp); 928*1c42de6dSgd78059 929*1c42de6dSgd78059 for (i = 0; i < ssp->nchannels; i++) { 930*1c42de6dSgd78059 ddi_regs_map_free(&ssp->channel[i].handle); 931*1c42de6dSgd78059 } 932*1c42de6dSgd78059 } 933*1c42de6dSgd78059 934*1c42de6dSgd78059 /* 935*1c42de6dSgd78059 * Map logical services onto physical XBus channels. 936*1c42de6dSgd78059 */ 937*1c42de6dSgd78059 static void 938*1c42de6dSgd78059 bscv_map_chan_logical_physical(bscv_soft_state_t *ssp) 939*1c42de6dSgd78059 { 940*1c42de6dSgd78059 ASSERT(ssp); 941*1c42de6dSgd78059 942*1c42de6dSgd78059 /* 943*1c42de6dSgd78059 * We can assert that there will always be at least two channels, 944*1c42de6dSgd78059 * to allow watchdog pats to be segregated from all other traffic. 945*1c42de6dSgd78059 */ 946*1c42de6dSgd78059 chan_general = 0; 947*1c42de6dSgd78059 chan_wdogpat = 1; 948*1c42de6dSgd78059 949*1c42de6dSgd78059 /* 950*1c42de6dSgd78059 * By default move all other services onto the generic channel unless 951*1c42de6dSgd78059 * the hardware supports additional channels. 952*1c42de6dSgd78059 */ 953*1c42de6dSgd78059 954*1c42de6dSgd78059 chan_cpusig = chan_eeprom = chan_prog = chan_general; 955*1c42de6dSgd78059 956*1c42de6dSgd78059 if (ssp->nchannels > 2) 957*1c42de6dSgd78059 chan_cpusig = 2; 958*1c42de6dSgd78059 if (ssp->nchannels > 3) 959*1c42de6dSgd78059 chan_eeprom = 3; 960*1c42de6dSgd78059 if (ssp->nchannels > 4) 961*1c42de6dSgd78059 chan_prog = 4; 962*1c42de6dSgd78059 } 963*1c42de6dSgd78059 964*1c42de6dSgd78059 965*1c42de6dSgd78059 /* 966*1c42de6dSgd78059 * function - bscv_full_stop 967*1c42de6dSgd78059 * description - gracefully shut the lom down during panic or reboot. 968*1c42de6dSgd78059 * Disables the watchdog, setup up serial event reporting 969*1c42de6dSgd78059 * and stops the event daemon running. 970*1c42de6dSgd78059 * inputs - soft state pointer 971*1c42de6dSgd78059 * outputs - none 972*1c42de6dSgd78059 */ 973*1c42de6dSgd78059 void 974*1c42de6dSgd78059 bscv_full_stop(bscv_soft_state_t *ssp) 975*1c42de6dSgd78059 { 976*1c42de6dSgd78059 uint8_t bits2set = 0; 977*1c42de6dSgd78059 uint8_t bits2clear = 0; 978*1c42de6dSgd78059 979*1c42de6dSgd78059 bscv_trace(ssp, 'W', "bscv_full_stop", 980*1c42de6dSgd78059 "turning off watchdog"); 981*1c42de6dSgd78059 982*1c42de6dSgd78059 if (!ddi_in_panic()) { 983*1c42de6dSgd78059 /* Stop the event daemon if we are not panicking. */ 984*1c42de6dSgd78059 (void) bscv_pause_event_daemon(ssp); 985*1c42de6dSgd78059 } 986*1c42de6dSgd78059 987*1c42de6dSgd78059 bscv_enter(ssp); 988*1c42de6dSgd78059 989*1c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 990*1c42de6dSgd78059 if (ddi_in_panic()) { 991*1c42de6dSgd78059 bscv_inform_bsc(ssp, BSC_INFORM_PANIC); 992*1c42de6dSgd78059 } else { 993*1c42de6dSgd78059 bscv_inform_bsc(ssp, BSC_INFORM_OFFLINE); 994*1c42de6dSgd78059 } 995*1c42de6dSgd78059 #endif /* __i386 || __amd64 */ 996*1c42de6dSgd78059 997*1c42de6dSgd78059 /* set serial event reporting */ 998*1c42de6dSgd78059 switch (ssp->serial_reporting) { 999*1c42de6dSgd78059 case LOM_SER_EVENTS_ON: 1000*1c42de6dSgd78059 case LOM_SER_EVENTS_DEF: 1001*1c42de6dSgd78059 /* Make sure serial event reporting is on */ 1002*1c42de6dSgd78059 bits2clear = EBUS_ALARM_NOEVENTS; 1003*1c42de6dSgd78059 break; 1004*1c42de6dSgd78059 case LOM_SER_EVENTS_OFF: 1005*1c42de6dSgd78059 /* Make sure serial event reporting is on */ 1006*1c42de6dSgd78059 bits2set = EBUS_ALARM_NOEVENTS; 1007*1c42de6dSgd78059 break; 1008*1c42de6dSgd78059 default: 1009*1c42de6dSgd78059 break; 1010*1c42de6dSgd78059 } 1011*1c42de6dSgd78059 bscv_setclear8_volatile(ssp, chan_general, 1012*1c42de6dSgd78059 EBUS_IDX_ALARM, bits2set, bits2clear); 1013*1c42de6dSgd78059 1014*1c42de6dSgd78059 bscv_exit(ssp); 1015*1c42de6dSgd78059 } 1016*1c42de6dSgd78059 1017*1c42de6dSgd78059 /* 1018*1c42de6dSgd78059 * LOM I/O routines. 1019*1c42de6dSgd78059 * 1020*1c42de6dSgd78059 * locking 1021*1c42de6dSgd78059 * 1022*1c42de6dSgd78059 * Two sets of routines are provided: 1023*1c42de6dSgd78059 * normal - must be called after acquiring an appropriate lock. 1024*1c42de6dSgd78059 * locked - perform all the locking required and return any error 1025*1c42de6dSgd78059 * code in the supplied 'res' argument. If there is no 1026*1c42de6dSgd78059 * error 'res' is not changed. 1027*1c42de6dSgd78059 * The locked routines are designed for use in ioctl commands where 1028*1c42de6dSgd78059 * only a single operation needs to be performed and the overhead of 1029*1c42de6dSgd78059 * locking and result checking adds significantly to code complexity. 1030*1c42de6dSgd78059 * 1031*1c42de6dSgd78059 * locking primitives 1032*1c42de6dSgd78059 * 1033*1c42de6dSgd78059 * bscv_enter() - acquires an I/O lock for the calling thread. 1034*1c42de6dSgd78059 * bscv_exit() - releases an I/O lock acquired by bscv_enter(). 1035*1c42de6dSgd78059 * bscv_held() - used to assert ownership of an I/O lock. 1036*1c42de6dSgd78059 * 1037*1c42de6dSgd78059 * normal I/O routines 1038*1c42de6dSgd78059 * 1039*1c42de6dSgd78059 * Note bscv_{put|get}{16|32} routines are big-endian. This assumes that 1040*1c42de6dSgd78059 * the firmware works that way too. 1041*1c42de6dSgd78059 * 1042*1c42de6dSgd78059 * bscv_put8(), bscv_put16, bscv_put32 - write values to the LOM 1043*1c42de6dSgd78059 * and handle any retries if necessary. 1044*1c42de6dSgd78059 * 16 and 32 bit values are big-endian. 1045*1c42de6dSgd78059 * bscv_get8(), bscv_get16, bscv_get32 - read values from the LOM 1046*1c42de6dSgd78059 * and handle any retries if necessary. 1047*1c42de6dSgd78059 * 16 and 32 bit values are big-endian. 1048*1c42de6dSgd78059 * bscv_setclear8() - set or clear the specified bits in the register 1049*1c42de6dSgd78059 * at the supplied address. 1050*1c42de6dSgd78059 * bscv_setclear8_volatile() - set or clear the specified bits in the 1051*1c42de6dSgd78059 * register at the supplied address. If the lom reports 1052*1c42de6dSgd78059 * that the registers has changed since the last read 1053*1c42de6dSgd78059 * re-read and apply the set or clear to the new bits. 1054*1c42de6dSgd78059 * bscv_get8_cached() - Return a cached register value (addr < 0x80). 1055*1c42de6dSgd78059 * Does not access the hardware. A read of the hardware 1056*1c42de6dSgd78059 * automatically updates this cache. 1057*1c42de6dSgd78059 * 1058*1c42de6dSgd78059 * locked I/O routines 1059*1c42de6dSgd78059 * 1060*1c42de6dSgd78059 * bscv_get8_locked(), bscv_rep_get8_locked(). 1061*1c42de6dSgd78059 * 1062*1c42de6dSgd78059 * Call the indicated function from above, but wrapping it with 1063*1c42de6dSgd78059 * bscv_enter()/bscv_exit(). 1064*1c42de6dSgd78059 * 1065*1c42de6dSgd78059 * 1066*1c42de6dSgd78059 * Fault management 1067*1c42de6dSgd78059 * 1068*1c42de6dSgd78059 * LOM communications fault are grouped into three categories: 1069*1c42de6dSgd78059 * 1) Faulty - the LOM is not responding and no attempt to communicate 1070*1c42de6dSgd78059 * with it should be made. 1071*1c42de6dSgd78059 * 2) Transient fault - something which might recover after a retry 1072*1c42de6dSgd78059 * but which doesn't affect our ability to perform other 1073*1c42de6dSgd78059 * commands. 1074*1c42de6dSgd78059 * 3) Command error - an inappropriate command was executed. A retry 1075*1c42de6dSgd78059 * will not fix it but the command failed. 1076*1c42de6dSgd78059 * 1077*1c42de6dSgd78059 * The current implementation of the bscv driver is not very good at 1078*1c42de6dSgd78059 * noticing command errors due to the structure of the original code 1079*1c42de6dSgd78059 * that it is based on. It is possible to extend the driver to do this 1080*1c42de6dSgd78059 * and would probably involve having a concept of a "session error" 1081*1c42de6dSgd78059 * which is less severe than a fault but means that a sequence of 1082*1c42de6dSgd78059 * commands had some fault which cannot be recovered. 1083*1c42de6dSgd78059 * 1084*1c42de6dSgd78059 * 1085*1c42de6dSgd78059 * faults 1086*1c42de6dSgd78059 * 1087*1c42de6dSgd78059 * bscv_faulty() - returns B_TRUE if the LOM (communications) have been 1088*1c42de6dSgd78059 * declared faulty. 1089*1c42de6dSgd78059 * bscv_clear_fault() - marks the LOM as not faulty. 1090*1c42de6dSgd78059 * bscv_set_fault() - marks the LOM as being faulty. 1091*1c42de6dSgd78059 * 1092*1c42de6dSgd78059 * bscv_clear_fault and bscv_set_fault should generally not be called 1093*1c42de6dSgd78059 * directly. 1094*1c42de6dSgd78059 * 1095*1c42de6dSgd78059 * command errors/transient faults 1096*1c42de6dSgd78059 * 1097*1c42de6dSgd78059 * bscv_retcode() - returns the actual error code of the last operation. 1098*1c42de6dSgd78059 * bscv_should_retry() - determines if last operation may suceed if 1099*1c42de6dSgd78059 * retried. 1100*1c42de6dSgd78059 * bscv_locked_result() - Set the result of a locked register access. 1101*1c42de6dSgd78059 * 1102*1c42de6dSgd78059 * low level I/O primitives 1103*1c42de6dSgd78059 * 1104*1c42de6dSgd78059 * These are generally not called directly. These perform a single 1105*1c42de6dSgd78059 * access to the LOM device. They do not handle retries. 1106*1c42de6dSgd78059 * 1107*1c42de6dSgd78059 * bscv_put8_once() 1108*1c42de6dSgd78059 * bscv_get8_once() 1109*1c42de6dSgd78059 * bscv_probe() - perform a probe (NOP) operation to check out lom comms. 1110*1c42de6dSgd78059 * bscv_resync_comms() - resynchronise communications after a transient fault. 1111*1c42de6dSgd78059 */ 1112*1c42de6dSgd78059 1113*1c42de6dSgd78059 static void 1114*1c42de6dSgd78059 bscv_enter(bscv_soft_state_t *ssp) 1115*1c42de6dSgd78059 { 1116*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_enter", ""); 1117*1c42de6dSgd78059 mutex_enter(&ssp->cmd_mutex); 1118*1c42de6dSgd78059 ssp->had_session_error = B_FALSE; 1119*1c42de6dSgd78059 } 1120*1c42de6dSgd78059 1121*1c42de6dSgd78059 static void 1122*1c42de6dSgd78059 bscv_exit(bscv_soft_state_t *ssp) 1123*1c42de6dSgd78059 { 1124*1c42de6dSgd78059 mutex_exit(&ssp->cmd_mutex); 1125*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_exit", ""); 1126*1c42de6dSgd78059 } 1127*1c42de6dSgd78059 1128*1c42de6dSgd78059 #ifdef DEBUG 1129*1c42de6dSgd78059 static int 1130*1c42de6dSgd78059 bscv_held(bscv_soft_state_t *ssp) 1131*1c42de6dSgd78059 { 1132*1c42de6dSgd78059 return (mutex_owned(&ssp->cmd_mutex)); 1133*1c42de6dSgd78059 } 1134*1c42de6dSgd78059 #endif /* DEBUG */ 1135*1c42de6dSgd78059 1136*1c42de6dSgd78059 static void 1137*1c42de6dSgd78059 bscv_put8(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint8_t val) 1138*1c42de6dSgd78059 { 1139*1c42de6dSgd78059 boolean_t needretry; 1140*1c42de6dSgd78059 int num_failures; 1141*1c42de6dSgd78059 1142*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1143*1c42de6dSgd78059 1144*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 1145*1c42de6dSgd78059 return; 1146*1c42de6dSgd78059 } 1147*1c42de6dSgd78059 1148*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_put8", 1149*1c42de6dSgd78059 "addr 0x%x.%02x <= 0x%02x", addr >> 8, addr & 0xff, val); 1150*1c42de6dSgd78059 1151*1c42de6dSgd78059 for (num_failures = 0; 1152*1c42de6dSgd78059 num_failures < BSC_FAILURE_RETRY_LIMIT; 1153*1c42de6dSgd78059 num_failures++) { 1154*1c42de6dSgd78059 bscv_put8_once(ssp, chan, addr, val); 1155*1c42de6dSgd78059 needretry = bscv_should_retry(ssp); 1156*1c42de6dSgd78059 if (!needretry) { 1157*1c42de6dSgd78059 break; 1158*1c42de6dSgd78059 } 1159*1c42de6dSgd78059 } 1160*1c42de6dSgd78059 if (ssp->command_error != 0) { 1161*1c42de6dSgd78059 ssp->had_session_error = B_TRUE; 1162*1c42de6dSgd78059 } 1163*1c42de6dSgd78059 1164*1c42de6dSgd78059 if (needretry) { 1165*1c42de6dSgd78059 /* Failure - we ran out of retries */ 1166*1c42de6dSgd78059 cmn_err(CE_WARN, "bscv_put8: addr 0x%x.%02x retried " 1167*1c42de6dSgd78059 "write %d times, giving up", 1168*1c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 1169*1c42de6dSgd78059 bscv_set_fault(ssp); 1170*1c42de6dSgd78059 } else if (num_failures > 0) { 1171*1c42de6dSgd78059 bscv_trace(ssp, 'R', "bscv_put8", 1172*1c42de6dSgd78059 "addr 0x%x.%02x retried write %d times, succeeded", 1173*1c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 1174*1c42de6dSgd78059 } 1175*1c42de6dSgd78059 } 1176*1c42de6dSgd78059 1177*1c42de6dSgd78059 static void 1178*1c42de6dSgd78059 bscv_put16(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint16_t val) 1179*1c42de6dSgd78059 { 1180*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1181*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_put16", 1182*1c42de6dSgd78059 "addr 0x%x.%02x <= %04x", addr >> 8, addr & 0xff, val); 1183*1c42de6dSgd78059 bscv_put8(ssp, chan, addr, val >> 8); 1184*1c42de6dSgd78059 bscv_put8(ssp, chan, addr + 1, val & 0xff); 1185*1c42de6dSgd78059 } 1186*1c42de6dSgd78059 1187*1c42de6dSgd78059 static void 1188*1c42de6dSgd78059 bscv_put32(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint32_t val) 1189*1c42de6dSgd78059 { 1190*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1191*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_put32", 1192*1c42de6dSgd78059 "addr 0x%x.%02x <= %08x", addr >> 8, addr & 0xff, val); 1193*1c42de6dSgd78059 bscv_put8(ssp, chan, addr, (val >> 24) & 0xff); 1194*1c42de6dSgd78059 bscv_put8(ssp, chan, addr + 1, (val >> 16) & 0xff); 1195*1c42de6dSgd78059 bscv_put8(ssp, chan, addr + 2, (val >> 8) & 0xff); 1196*1c42de6dSgd78059 bscv_put8(ssp, chan, addr + 3, val & 0xff); 1197*1c42de6dSgd78059 } 1198*1c42de6dSgd78059 1199*1c42de6dSgd78059 static uint8_t 1200*1c42de6dSgd78059 bscv_get8(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr) 1201*1c42de6dSgd78059 { 1202*1c42de6dSgd78059 uint8_t retval; 1203*1c42de6dSgd78059 boolean_t needretry; 1204*1c42de6dSgd78059 int num_failures; 1205*1c42de6dSgd78059 1206*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1207*1c42de6dSgd78059 1208*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 1209*1c42de6dSgd78059 return (0); 1210*1c42de6dSgd78059 } 1211*1c42de6dSgd78059 1212*1c42de6dSgd78059 for (num_failures = 0; 1213*1c42de6dSgd78059 num_failures < BSC_FAILURE_RETRY_LIMIT; 1214*1c42de6dSgd78059 num_failures++) { 1215*1c42de6dSgd78059 retval = bscv_get8_once(ssp, chan, addr); 1216*1c42de6dSgd78059 needretry = bscv_should_retry(ssp); 1217*1c42de6dSgd78059 if (!needretry) { 1218*1c42de6dSgd78059 break; 1219*1c42de6dSgd78059 } 1220*1c42de6dSgd78059 } 1221*1c42de6dSgd78059 if (ssp->command_error != 0) { 1222*1c42de6dSgd78059 ssp->had_session_error = B_TRUE; 1223*1c42de6dSgd78059 } 1224*1c42de6dSgd78059 1225*1c42de6dSgd78059 if (needretry) { 1226*1c42de6dSgd78059 /* Failure */ 1227*1c42de6dSgd78059 cmn_err(CE_WARN, "bscv_get8: addr 0x%x.%02x retried " 1228*1c42de6dSgd78059 "read %d times, giving up", 1229*1c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 1230*1c42de6dSgd78059 bscv_set_fault(ssp); 1231*1c42de6dSgd78059 } else if (num_failures > 0) { 1232*1c42de6dSgd78059 bscv_trace(ssp, 'R', "bscv_get8", 1233*1c42de6dSgd78059 "addr 0x%x.%02x retried read %d times, succeeded", 1234*1c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 1235*1c42de6dSgd78059 } 1236*1c42de6dSgd78059 1237*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_get8", 1238*1c42de6dSgd78059 "addr 0x%x.%02x => %02x", addr >> 8, addr & 0xff, retval); 1239*1c42de6dSgd78059 return (retval); 1240*1c42de6dSgd78059 } 1241*1c42de6dSgd78059 1242*1c42de6dSgd78059 static uint16_t 1243*1c42de6dSgd78059 bscv_get16(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr) 1244*1c42de6dSgd78059 { 1245*1c42de6dSgd78059 uint16_t retval; 1246*1c42de6dSgd78059 1247*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1248*1c42de6dSgd78059 1249*1c42de6dSgd78059 retval = bscv_get8(ssp, chan, addr) << 8; 1250*1c42de6dSgd78059 retval |= bscv_get8(ssp, chan, addr + 1); 1251*1c42de6dSgd78059 1252*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_get16", 1253*1c42de6dSgd78059 "addr 0x%x.%02x => %04x", addr >> 8, addr & 0xff, retval); 1254*1c42de6dSgd78059 return (retval); 1255*1c42de6dSgd78059 } 1256*1c42de6dSgd78059 1257*1c42de6dSgd78059 static uint32_t 1258*1c42de6dSgd78059 bscv_get32(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr) 1259*1c42de6dSgd78059 { 1260*1c42de6dSgd78059 uint32_t retval; 1261*1c42de6dSgd78059 1262*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1263*1c42de6dSgd78059 1264*1c42de6dSgd78059 retval = bscv_get8(ssp, chan, addr) << 24; 1265*1c42de6dSgd78059 retval |= bscv_get8(ssp, chan, addr + 1) << 16; 1266*1c42de6dSgd78059 retval |= bscv_get8(ssp, chan, addr + 2) << 8; 1267*1c42de6dSgd78059 retval |= bscv_get8(ssp, chan, addr + 3); 1268*1c42de6dSgd78059 1269*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_get32", 1270*1c42de6dSgd78059 "addr 0x%x.%02x => %08x", addr >> 8, addr & 0xff, retval); 1271*1c42de6dSgd78059 return (retval); 1272*1c42de6dSgd78059 } 1273*1c42de6dSgd78059 1274*1c42de6dSgd78059 static void 1275*1c42de6dSgd78059 bscv_setclear8(bscv_soft_state_t *ssp, int chan, 1276*1c42de6dSgd78059 bscv_addr_t addr, uint8_t set, uint8_t clear) 1277*1c42de6dSgd78059 { 1278*1c42de6dSgd78059 uint8_t val; 1279*1c42de6dSgd78059 1280*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1281*1c42de6dSgd78059 ASSERT(addr < BSC_ADDR_CACHE_LIMIT); 1282*1c42de6dSgd78059 1283*1c42de6dSgd78059 val = ssp->lom_regs[addr] | set; 1284*1c42de6dSgd78059 val &= ~clear; 1285*1c42de6dSgd78059 1286*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_setclear8", 1287*1c42de6dSgd78059 "addr 0x%x.%02x, set %02x, clear %02x => %02x", 1288*1c42de6dSgd78059 addr >> 8, addr & 0xff, 1289*1c42de6dSgd78059 set, clear, val); 1290*1c42de6dSgd78059 1291*1c42de6dSgd78059 bscv_put8(ssp, chan, addr, val); 1292*1c42de6dSgd78059 } 1293*1c42de6dSgd78059 1294*1c42de6dSgd78059 static void 1295*1c42de6dSgd78059 bscv_setclear8_volatile(bscv_soft_state_t *ssp, int chan, 1296*1c42de6dSgd78059 bscv_addr_t addr, uint8_t set, uint8_t clear) 1297*1c42de6dSgd78059 { 1298*1c42de6dSgd78059 uint8_t val; 1299*1c42de6dSgd78059 boolean_t needretry; 1300*1c42de6dSgd78059 int num_failures; 1301*1c42de6dSgd78059 1302*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1303*1c42de6dSgd78059 ASSERT(addr < BSC_ADDR_CACHE_LIMIT); 1304*1c42de6dSgd78059 1305*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 1306*1c42de6dSgd78059 return; 1307*1c42de6dSgd78059 } 1308*1c42de6dSgd78059 1309*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_setclear8_volatile", 1310*1c42de6dSgd78059 "addr 0x%x.%02x => set %02x clear %02x", 1311*1c42de6dSgd78059 addr >> 8, addr & 0xff, set, clear); 1312*1c42de6dSgd78059 1313*1c42de6dSgd78059 val = bscv_get8_cached(ssp, addr); 1314*1c42de6dSgd78059 for (num_failures = 0; 1315*1c42de6dSgd78059 num_failures < BSC_FAILURE_RETRY_LIMIT; 1316*1c42de6dSgd78059 num_failures++) { 1317*1c42de6dSgd78059 val |= set; 1318*1c42de6dSgd78059 val &= ~clear; 1319*1c42de6dSgd78059 bscv_put8_once(ssp, chan, addr, val); 1320*1c42de6dSgd78059 if (ssp->command_error == EBUS_ERROR_STALEDATA) { 1321*1c42de6dSgd78059 /* Re-read the stale register from the lom */ 1322*1c42de6dSgd78059 val = bscv_get8_once(ssp, chan, addr); 1323*1c42de6dSgd78059 needretry = 1; 1324*1c42de6dSgd78059 } else { 1325*1c42de6dSgd78059 needretry = bscv_should_retry(ssp); 1326*1c42de6dSgd78059 if (!needretry) { 1327*1c42de6dSgd78059 break; 1328*1c42de6dSgd78059 } 1329*1c42de6dSgd78059 } 1330*1c42de6dSgd78059 } 1331*1c42de6dSgd78059 if (ssp->command_error != 0) { 1332*1c42de6dSgd78059 ssp->had_session_error = B_TRUE; 1333*1c42de6dSgd78059 } 1334*1c42de6dSgd78059 1335*1c42de6dSgd78059 if (needretry) { 1336*1c42de6dSgd78059 /* Failure */ 1337*1c42de6dSgd78059 cmn_err(CE_WARN, "bscv_setclear8_volatile: addr 0x%x.%02x " 1338*1c42de6dSgd78059 "retried write %d times, giving up", 1339*1c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 1340*1c42de6dSgd78059 if (ssp->command_error != EBUS_ERROR_STALEDATA) { 1341*1c42de6dSgd78059 bscv_set_fault(ssp); 1342*1c42de6dSgd78059 } 1343*1c42de6dSgd78059 } else if (num_failures > 0) { 1344*1c42de6dSgd78059 bscv_trace(ssp, 'R', "bscv_setclear8_volatile", 1345*1c42de6dSgd78059 "addr 0x%x.%02x retried write %d times, succeeded", 1346*1c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 1347*1c42de6dSgd78059 } 1348*1c42de6dSgd78059 } 1349*1c42de6dSgd78059 1350*1c42de6dSgd78059 static void 1351*1c42de6dSgd78059 bscv_rep_rw8(bscv_soft_state_t *ssp, int chan, uint8_t *host_addr, 1352*1c42de6dSgd78059 bscv_addr_t dev_addr, size_t repcount, uint_t flags, 1353*1c42de6dSgd78059 boolean_t is_write) 1354*1c42de6dSgd78059 { 1355*1c42de6dSgd78059 size_t inc; 1356*1c42de6dSgd78059 1357*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1358*1c42de6dSgd78059 1359*1c42de6dSgd78059 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 1360*1c42de6dSgd78059 for (; repcount--; dev_addr += inc) { 1361*1c42de6dSgd78059 if (flags & DDI_DEV_AUTOINCR) { 1362*1c42de6dSgd78059 if (is_write) { 1363*1c42de6dSgd78059 bscv_put8(ssp, chan, dev_addr, *host_addr++); 1364*1c42de6dSgd78059 } else { 1365*1c42de6dSgd78059 *host_addr++ = bscv_get8(ssp, chan, dev_addr); 1366*1c42de6dSgd78059 } 1367*1c42de6dSgd78059 } else { 1368*1c42de6dSgd78059 if (is_write) { 1369*1c42de6dSgd78059 bscv_put8_once(ssp, chan, 1370*1c42de6dSgd78059 dev_addr, *host_addr++); 1371*1c42de6dSgd78059 } else { 1372*1c42de6dSgd78059 *host_addr++ = bscv_get8_once(ssp, chan, 1373*1c42de6dSgd78059 dev_addr); 1374*1c42de6dSgd78059 } 1375*1c42de6dSgd78059 /* We need this because _once routines don't do it */ 1376*1c42de6dSgd78059 if (ssp->command_error != 0) { 1377*1c42de6dSgd78059 ssp->had_session_error = B_TRUE; 1378*1c42de6dSgd78059 } 1379*1c42de6dSgd78059 } 1380*1c42de6dSgd78059 if (bscv_faulty(ssp) || bscv_session_error(ssp)) { 1381*1c42de6dSgd78059 /* 1382*1c42de6dSgd78059 * No retry here. If we were AUTOINCR then get/put 1383*1c42de6dSgd78059 * will have retried. For NO_AUTOINCR we cannot retry 1384*1c42de6dSgd78059 * because the data would be corrupted. 1385*1c42de6dSgd78059 */ 1386*1c42de6dSgd78059 break; 1387*1c42de6dSgd78059 } 1388*1c42de6dSgd78059 } 1389*1c42de6dSgd78059 } 1390*1c42de6dSgd78059 1391*1c42de6dSgd78059 static uint8_t 1392*1c42de6dSgd78059 bscv_get8_cached(bscv_soft_state_t *ssp, bscv_addr_t addr) 1393*1c42de6dSgd78059 { 1394*1c42de6dSgd78059 ASSERT(addr < BSC_ADDR_CACHE_LIMIT); 1395*1c42de6dSgd78059 /* Can be called with or without the lock held */ 1396*1c42de6dSgd78059 1397*1c42de6dSgd78059 return (ssp->lom_regs[addr]); 1398*1c42de6dSgd78059 } 1399*1c42de6dSgd78059 1400*1c42de6dSgd78059 static uint8_t 1401*1c42de6dSgd78059 bscv_get8_locked(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, int *res) 1402*1c42de6dSgd78059 { 1403*1c42de6dSgd78059 uint8_t retval; 1404*1c42de6dSgd78059 1405*1c42de6dSgd78059 ASSERT(addr < BSC_ADDR_CACHE_LIMIT); 1406*1c42de6dSgd78059 bscv_enter(ssp); 1407*1c42de6dSgd78059 retval = bscv_get8(ssp, chan, addr); 1408*1c42de6dSgd78059 bscv_locked_result(ssp, res); 1409*1c42de6dSgd78059 bscv_exit(ssp); 1410*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_get8_locked", 1411*1c42de6dSgd78059 "addr 0x%x.%02x => %02x", addr >> 8, addr & 0xff, retval); 1412*1c42de6dSgd78059 return (retval); 1413*1c42de6dSgd78059 } 1414*1c42de6dSgd78059 1415*1c42de6dSgd78059 static void 1416*1c42de6dSgd78059 bscv_rep_get8_locked(bscv_soft_state_t *ssp, int chan, uint8_t *host_addr, 1417*1c42de6dSgd78059 bscv_addr_t dev_addr, size_t repcount, uint_t flags, int *res) 1418*1c42de6dSgd78059 { 1419*1c42de6dSgd78059 bscv_enter(ssp); 1420*1c42de6dSgd78059 bscv_rep_rw8(ssp, chan, host_addr, dev_addr, repcount, 1421*1c42de6dSgd78059 flags, B_FALSE /* read */); 1422*1c42de6dSgd78059 bscv_locked_result(ssp, res); 1423*1c42de6dSgd78059 bscv_exit(ssp); 1424*1c42de6dSgd78059 } 1425*1c42de6dSgd78059 1426*1c42de6dSgd78059 static boolean_t 1427*1c42de6dSgd78059 bscv_faulty(bscv_soft_state_t *ssp) 1428*1c42de6dSgd78059 { 1429*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1430*1c42de6dSgd78059 return (ssp->had_fault); 1431*1c42de6dSgd78059 } 1432*1c42de6dSgd78059 1433*1c42de6dSgd78059 static void 1434*1c42de6dSgd78059 bscv_clear_fault(bscv_soft_state_t *ssp) 1435*1c42de6dSgd78059 { 1436*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1437*1c42de6dSgd78059 bscv_trace(ssp, 'J', "bscv_clear_fault", "clearing fault flag"); 1438*1c42de6dSgd78059 ssp->had_fault = B_FALSE; 1439*1c42de6dSgd78059 ssp->had_session_error = B_FALSE; 1440*1c42de6dSgd78059 } 1441*1c42de6dSgd78059 1442*1c42de6dSgd78059 static void 1443*1c42de6dSgd78059 bscv_set_fault(bscv_soft_state_t *ssp) 1444*1c42de6dSgd78059 { 1445*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1446*1c42de6dSgd78059 bscv_trace(ssp, 'J', "bscv_set_fault", "setting fault flag"); 1447*1c42de6dSgd78059 ssp->had_fault = B_TRUE; 1448*1c42de6dSgd78059 } 1449*1c42de6dSgd78059 1450*1c42de6dSgd78059 static boolean_t 1451*1c42de6dSgd78059 bscv_session_error(bscv_soft_state_t *ssp) 1452*1c42de6dSgd78059 { 1453*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1454*1c42de6dSgd78059 return (ssp->had_session_error); 1455*1c42de6dSgd78059 } 1456*1c42de6dSgd78059 1457*1c42de6dSgd78059 static int 1458*1c42de6dSgd78059 bscv_retcode(bscv_soft_state_t *ssp) 1459*1c42de6dSgd78059 { 1460*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_retcode", 1461*1c42de6dSgd78059 "code 0x%x", ssp->command_error); 1462*1c42de6dSgd78059 return (ssp->command_error); 1463*1c42de6dSgd78059 } 1464*1c42de6dSgd78059 1465*1c42de6dSgd78059 static int 1466*1c42de6dSgd78059 bscv_should_retry(bscv_soft_state_t *ssp) 1467*1c42de6dSgd78059 { 1468*1c42de6dSgd78059 if ((ssp->command_error == EBUS_ERROR_DEVICEFAIL) || 1469*1c42de6dSgd78059 (ssp->command_error >= LOMBUS_ERR_BASE)) { 1470*1c42de6dSgd78059 /* This command is due to an I/O fault - retry might fix */ 1471*1c42de6dSgd78059 return (1); 1472*1c42de6dSgd78059 } else { 1473*1c42de6dSgd78059 /* 1474*1c42de6dSgd78059 * The command itself was bad - there is no point in fixing 1475*1c42de6dSgd78059 * Note. Whatever happens we should know that if we were 1476*1c42de6dSgd78059 * doing EBUS_IDX_SELFTEST0..EBUS_IDX_SELFTEST7 and we 1477*1c42de6dSgd78059 * had 0x80 set then this is a test error not a retry 1478*1c42de6dSgd78059 * error. 1479*1c42de6dSgd78059 */ 1480*1c42de6dSgd78059 return (0); 1481*1c42de6dSgd78059 } 1482*1c42de6dSgd78059 } 1483*1c42de6dSgd78059 1484*1c42de6dSgd78059 static void 1485*1c42de6dSgd78059 bscv_locked_result(bscv_soft_state_t *ssp, int *res) 1486*1c42de6dSgd78059 { 1487*1c42de6dSgd78059 if (bscv_faulty(ssp) || (bscv_retcode(ssp) != 0)) { 1488*1c42de6dSgd78059 *res = EIO; 1489*1c42de6dSgd78059 } 1490*1c42de6dSgd78059 } 1491*1c42de6dSgd78059 1492*1c42de6dSgd78059 static void 1493*1c42de6dSgd78059 bscv_put8_once(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint8_t val) 1494*1c42de6dSgd78059 { 1495*1c42de6dSgd78059 uint32_t fault; 1496*1c42de6dSgd78059 1497*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1498*1c42de6dSgd78059 1499*1c42de6dSgd78059 ssp->command_error = 0; 1500*1c42de6dSgd78059 1501*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 1502*1c42de6dSgd78059 /* Bail out things are not working */ 1503*1c42de6dSgd78059 return; 1504*1c42de6dSgd78059 } else if (ssp->nchannels == 0) { 1505*1c42de6dSgd78059 /* Didn't manage to map handles so ddi_{get,put}* broken */ 1506*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_put8_once", 1507*1c42de6dSgd78059 "nchannels is 0x0 so cannot do IO"); 1508*1c42de6dSgd78059 return; 1509*1c42de6dSgd78059 } 1510*1c42de6dSgd78059 1511*1c42de6dSgd78059 /* Clear any pending fault */ 1512*1c42de6dSgd78059 ddi_put32(ssp->channel[chan].handle, 1513*1c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0); 1514*1c42de6dSgd78059 1515*1c42de6dSgd78059 /* Do the access and get fault code - may take a long time */ 1516*1c42de6dSgd78059 ddi_put8(ssp->channel[chan].handle, 1517*1c42de6dSgd78059 &ssp->channel[chan].regs[addr], val); 1518*1c42de6dSgd78059 fault = ddi_get32(ssp->channel[chan].handle, 1519*1c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG)); 1520*1c42de6dSgd78059 1521*1c42de6dSgd78059 ssp->command_error = fault; 1522*1c42de6dSgd78059 1523*1c42de6dSgd78059 if (fault == 0) { 1524*1c42de6dSgd78059 /* Things were ok - update cache entry */ 1525*1c42de6dSgd78059 if (addr < BSC_ADDR_CACHE_LIMIT) { 1526*1c42de6dSgd78059 /* Store cacheable entries */ 1527*1c42de6dSgd78059 ssp->lom_regs[addr] = val; 1528*1c42de6dSgd78059 } 1529*1c42de6dSgd78059 } else if (fault >= LOMBUS_ERR_BASE) { 1530*1c42de6dSgd78059 /* lombus problem - do a resync session */ 1531*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_put8_once: Had comms fault " 1532*1c42de6dSgd78059 "for address 0x%x.%02x - data 0x%x, fault 0x%x", 1533*1c42de6dSgd78059 addr >> 8, addr & 0xff, val, fault); 1534*1c42de6dSgd78059 /* Attempt to resync with the lom */ 1535*1c42de6dSgd78059 bscv_resync_comms(ssp, chan); 1536*1c42de6dSgd78059 /* 1537*1c42de6dSgd78059 * Note: we do not set fault status here. That 1538*1c42de6dSgd78059 * is done if our caller decides to give up talking to 1539*1c42de6dSgd78059 * the lom. The observant might notice that this means 1540*1c42de6dSgd78059 * that if we mend things on the last attempt we still 1541*1c42de6dSgd78059 * get the fault set - we just live with that! 1542*1c42de6dSgd78059 */ 1543*1c42de6dSgd78059 } 1544*1c42de6dSgd78059 1545*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_put8_once", 1546*1c42de6dSgd78059 "addr 0x%x.%02x <= 0x%02x", addr >> 8, addr & 0xff, val); 1547*1c42de6dSgd78059 } 1548*1c42de6dSgd78059 1549*1c42de6dSgd78059 static uint8_t 1550*1c42de6dSgd78059 bscv_get8_once(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr) 1551*1c42de6dSgd78059 { 1552*1c42de6dSgd78059 uint8_t val; 1553*1c42de6dSgd78059 uint32_t fault; 1554*1c42de6dSgd78059 1555*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1556*1c42de6dSgd78059 1557*1c42de6dSgd78059 ssp->command_error = 0; 1558*1c42de6dSgd78059 1559*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 1560*1c42de6dSgd78059 /* Bail out things are not working */ 1561*1c42de6dSgd78059 return (0xff); 1562*1c42de6dSgd78059 } else if (ssp->nchannels == 0) { 1563*1c42de6dSgd78059 /* Didn't manage to map handles so ddi_{get,put}* broken */ 1564*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_get8_once", 1565*1c42de6dSgd78059 "nchannels is 0x0 so cannot do IO"); 1566*1c42de6dSgd78059 return (0xff); 1567*1c42de6dSgd78059 } 1568*1c42de6dSgd78059 1569*1c42de6dSgd78059 /* Clear any pending fault */ 1570*1c42de6dSgd78059 ddi_put32(ssp->channel[chan].handle, 1571*1c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0); 1572*1c42de6dSgd78059 1573*1c42de6dSgd78059 /* Do the access and get fault code - may take a long time */ 1574*1c42de6dSgd78059 val = ddi_get8(ssp->channel[chan].handle, 1575*1c42de6dSgd78059 &ssp->channel[chan].regs[addr]); 1576*1c42de6dSgd78059 fault = ddi_get32(ssp->channel[chan].handle, 1577*1c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG)); 1578*1c42de6dSgd78059 ssp->command_error = fault; 1579*1c42de6dSgd78059 1580*1c42de6dSgd78059 if (fault >= LOMBUS_ERR_BASE) { 1581*1c42de6dSgd78059 /* lombus problem - do a resync session */ 1582*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_get8_once: Had comms fault " 1583*1c42de6dSgd78059 "for address 0x%x.%02x - data 0x%x, fault 0x%x", 1584*1c42de6dSgd78059 addr >> 8, addr & 0xff, val, fault); 1585*1c42de6dSgd78059 /* Attempt to resync with the lom */ 1586*1c42de6dSgd78059 bscv_resync_comms(ssp, chan); 1587*1c42de6dSgd78059 /* 1588*1c42de6dSgd78059 * Note: we do not set fault status here. That 1589*1c42de6dSgd78059 * is done if our caller decides to give up talking to 1590*1c42de6dSgd78059 * the lom. The observant might notice that this means 1591*1c42de6dSgd78059 * that if we mend things on the last attempt we still 1592*1c42de6dSgd78059 * get the fault set - we just live with that! 1593*1c42de6dSgd78059 */ 1594*1c42de6dSgd78059 } 1595*1c42de6dSgd78059 /* 1596*1c42de6dSgd78059 * FIXME - should report error if you get 1597*1c42de6dSgd78059 * EBUS_ERROR_DEVICEFAIL reported from the BSC. That gets 1598*1c42de6dSgd78059 * logged as a failure in bscv_should_retry and may contribute 1599*1c42de6dSgd78059 * to a permanent failure. Reference issues seen by Mitac. 1600*1c42de6dSgd78059 */ 1601*1c42de6dSgd78059 1602*1c42de6dSgd78059 if (!bscv_faulty(ssp)) { 1603*1c42de6dSgd78059 if (addr < BSC_ADDR_CACHE_LIMIT) { 1604*1c42de6dSgd78059 /* Store cacheable entries */ 1605*1c42de6dSgd78059 ssp->lom_regs[addr] = val; 1606*1c42de6dSgd78059 } 1607*1c42de6dSgd78059 } 1608*1c42de6dSgd78059 1609*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_get8_once", 1610*1c42de6dSgd78059 "addr 0x%x.%02x => 0x%02x", addr >> 8, addr & 0xff, val); 1611*1c42de6dSgd78059 return (val); 1612*1c42de6dSgd78059 } 1613*1c42de6dSgd78059 1614*1c42de6dSgd78059 static uint32_t 1615*1c42de6dSgd78059 bscv_probe(bscv_soft_state_t *ssp, int chan, uint32_t *fault) 1616*1c42de6dSgd78059 { 1617*1c42de6dSgd78059 uint32_t async_reg; 1618*1c42de6dSgd78059 1619*1c42de6dSgd78059 if (ssp->nchannels == 0) { 1620*1c42de6dSgd78059 /* 1621*1c42de6dSgd78059 * Failed to map handles, so cannot do any IO. Set the 1622*1c42de6dSgd78059 * fault indicator and return a dummy value. 1623*1c42de6dSgd78059 */ 1624*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_probe", 1625*1c42de6dSgd78059 "nchannels is 0x0 so cannot do any IO"); 1626*1c42de6dSgd78059 *fault = LOMBUS_ERR_REG_NUM; 1627*1c42de6dSgd78059 return ((~(int8_t)0)); 1628*1c42de6dSgd78059 } 1629*1c42de6dSgd78059 1630*1c42de6dSgd78059 /* Clear faults */ 1631*1c42de6dSgd78059 ddi_put32(ssp->channel[chan].handle, 1632*1c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0); 1633*1c42de6dSgd78059 /* Probe and Check faults */ 1634*1c42de6dSgd78059 *fault = ddi_get32(ssp->channel[chan].handle, 1635*1c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_PROBE_REG)); 1636*1c42de6dSgd78059 /* Read status */ 1637*1c42de6dSgd78059 async_reg = ddi_get32(ssp->channel[chan].handle, 1638*1c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_ASYNC_REG)); 1639*1c42de6dSgd78059 1640*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_probe", 1641*1c42de6dSgd78059 "async status 0x%x, fault 0x%x", async_reg, *fault); 1642*1c42de6dSgd78059 return (async_reg); 1643*1c42de6dSgd78059 } 1644*1c42de6dSgd78059 1645*1c42de6dSgd78059 static void 1646*1c42de6dSgd78059 bscv_resync_comms(bscv_soft_state_t *ssp, int chan) 1647*1c42de6dSgd78059 { 1648*1c42de6dSgd78059 int try; 1649*1c42de6dSgd78059 uint32_t command_error = ssp->command_error; 1650*1c42de6dSgd78059 uint32_t fault = 0; 1651*1c42de6dSgd78059 1652*1c42de6dSgd78059 if (ssp->nchannels == 0) { 1653*1c42de6dSgd78059 /* 1654*1c42de6dSgd78059 * Didn't manage to map handles so ddi_{get,put}* broken. 1655*1c42de6dSgd78059 * Therefore, there is no way to resync comms. 1656*1c42de6dSgd78059 */ 1657*1c42de6dSgd78059 bscv_trace(ssp, '@', "bscv_resync_comms", 1658*1c42de6dSgd78059 "nchannels is 0x0 so not possible to resync comms"); 1659*1c42de6dSgd78059 return; 1660*1c42de6dSgd78059 } 1661*1c42de6dSgd78059 if (command_error >= LOMBUS_ERR_BASE && 1662*1c42de6dSgd78059 command_error != LOMBUS_ERR_REG_NUM && 1663*1c42de6dSgd78059 command_error != LOMBUS_ERR_REG_SIZE && 1664*1c42de6dSgd78059 command_error != LOMBUS_ERR_TIMEOUT) { 1665*1c42de6dSgd78059 /* Resync here to make sure that the lom is talking */ 1666*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_resync_comms: " 1667*1c42de6dSgd78059 "Attempting comms resync after comms fault 0x%x", 1668*1c42de6dSgd78059 command_error); 1669*1c42de6dSgd78059 for (try = 1; try <= 8; try++) { 1670*1c42de6dSgd78059 /* Probe */ 1671*1c42de6dSgd78059 fault = ddi_get32(ssp->channel[chan].handle, 1672*1c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, 1673*1c42de6dSgd78059 LOMBUS_PROBE_REG)); 1674*1c42de6dSgd78059 1675*1c42de6dSgd78059 if (fault == 0) { 1676*1c42de6dSgd78059 break; 1677*1c42de6dSgd78059 } else { 1678*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_resync_comms: " 1679*1c42de6dSgd78059 "comms resync (probing) - try 0x%x " 1680*1c42de6dSgd78059 "had fault 0x%x", try, fault); 1681*1c42de6dSgd78059 } 1682*1c42de6dSgd78059 } 1683*1c42de6dSgd78059 if (fault != 0) { 1684*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_resync_comms: " 1685*1c42de6dSgd78059 "Failed to resync comms - giving up"); 1686*1c42de6dSgd78059 ssp->bad_resync++; 1687*1c42de6dSgd78059 } else { 1688*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_resync_comms: " 1689*1c42de6dSgd78059 "resync comms after 0x%x tries", try); 1690*1c42de6dSgd78059 ssp->bad_resync = 0; 1691*1c42de6dSgd78059 } 1692*1c42de6dSgd78059 } 1693*1c42de6dSgd78059 1694*1c42de6dSgd78059 } 1695*1c42de6dSgd78059 1696*1c42de6dSgd78059 1697*1c42de6dSgd78059 /* 1698*1c42de6dSgd78059 * LOMLite configuration/event eeprom access routines 1699*1c42de6dSgd78059 * 1700*1c42de6dSgd78059 * bscv_window_setup() - Read/Sanity check the eeprom parameters. 1701*1c42de6dSgd78059 * This must be called prior to calling bscv_eerw(). 1702*1c42de6dSgd78059 * bscv_eerw() - Read/write data from/to the eeprom. 1703*1c42de6dSgd78059 */ 1704*1c42de6dSgd78059 1705*1c42de6dSgd78059 /* 1706*1c42de6dSgd78059 * function - bscv_window_setup 1707*1c42de6dSgd78059 * description - this routine reads the eeprom parameters and sanity 1708*1c42de6dSgd78059 * checks them to ensure that the lom is talking sense. 1709*1c42de6dSgd78059 * inputs - soft state ptr 1710*1c42de6dSgd78059 * outputs - B_TRUE if the eeprom is ok, B_FALSE if the eeprom is not OK. 1711*1c42de6dSgd78059 */ 1712*1c42de6dSgd78059 static boolean_t 1713*1c42de6dSgd78059 bscv_window_setup(bscv_soft_state_t *ssp) 1714*1c42de6dSgd78059 { 1715*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1716*1c42de6dSgd78059 1717*1c42de6dSgd78059 if (ssp->eeinfo_valid) { 1718*1c42de6dSgd78059 /* Already have good cached values */ 1719*1c42de6dSgd78059 return (ssp->eeinfo_valid); 1720*1c42de6dSgd78059 } 1721*1c42de6dSgd78059 ssp->eeprom_size = 1722*1c42de6dSgd78059 bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) * 1024; 1723*1c42de6dSgd78059 ssp->eventlog_start = bscv_get16(ssp, chan_general, 1724*1c42de6dSgd78059 EBUS_IDX_LOG_START_HI); 1725*1c42de6dSgd78059 1726*1c42de6dSgd78059 /* 1727*1c42de6dSgd78059 * The log does not run to the end of the EEPROM because it is a 1728*1c42de6dSgd78059 * logical partition. The last 8K partition is reserved for FRUID 1729*1c42de6dSgd78059 * usage. 1730*1c42de6dSgd78059 */ 1731*1c42de6dSgd78059 ssp->eventlog_size = EBUS_LOG_END - ssp->eventlog_start; 1732*1c42de6dSgd78059 1733*1c42de6dSgd78059 bscv_trace(ssp, 'I', "bscv_window_setup", "eeprom size 0x%x log_start" 1734*1c42de6dSgd78059 " 0x%x log_size 0x%x", ssp->eeprom_size, ssp->eventlog_start, 1735*1c42de6dSgd78059 ssp->eventlog_size); 1736*1c42de6dSgd78059 1737*1c42de6dSgd78059 if (bscv_faulty(ssp) || bscv_session_error(ssp)) { 1738*1c42de6dSgd78059 ssp->eeinfo_valid = B_FALSE; 1739*1c42de6dSgd78059 } else if ((ssp->eeprom_size == 0) || 1740*1c42de6dSgd78059 (ssp->eventlog_start >= ssp->eeprom_size)) { 1741*1c42de6dSgd78059 /* Sanity check values */ 1742*1c42de6dSgd78059 cmn_err(CE_WARN, 1743*1c42de6dSgd78059 "!bscv_window_setup: read invalid eeprom parameters"); 1744*1c42de6dSgd78059 ssp->eeinfo_valid = B_FALSE; 1745*1c42de6dSgd78059 } else { 1746*1c42de6dSgd78059 ssp->eeinfo_valid = B_TRUE; 1747*1c42de6dSgd78059 } 1748*1c42de6dSgd78059 1749*1c42de6dSgd78059 bscv_trace(ssp, 'I', "bscv_window_setup", "returning eeinfo_valid %s", 1750*1c42de6dSgd78059 ssp->eeinfo_valid ? "true" : "false"); 1751*1c42de6dSgd78059 return (ssp->eeinfo_valid); 1752*1c42de6dSgd78059 } 1753*1c42de6dSgd78059 1754*1c42de6dSgd78059 /* 1755*1c42de6dSgd78059 * function - bscv_eerw 1756*1c42de6dSgd78059 * description - this routine reads/write data from/to the eeprom. 1757*1c42de6dSgd78059 * It takes care of setting the window on the eeprom correctly. 1758*1c42de6dSgd78059 * inputs - soft state ptr, eeprom offset, data buffer, size, read/write 1759*1c42de6dSgd78059 * outputs - B_TRUE if the eeprom is ok, B_FALSE if the eeprom is not OK. 1760*1c42de6dSgd78059 */ 1761*1c42de6dSgd78059 static int 1762*1c42de6dSgd78059 bscv_eerw(bscv_soft_state_t *ssp, uint32_t eeoffset, uint8_t *buf, 1763*1c42de6dSgd78059 unsigned size, boolean_t is_write) 1764*1c42de6dSgd78059 { 1765*1c42de6dSgd78059 uint32_t blk_addr = eeoffset; 1766*1c42de6dSgd78059 unsigned remaining = size; 1767*1c42de6dSgd78059 uint8_t page_idx; 1768*1c42de6dSgd78059 uint8_t this_page; 1769*1c42de6dSgd78059 uint8_t blk_size; 1770*1c42de6dSgd78059 int res = 0; 1771*1c42de6dSgd78059 1772*1c42de6dSgd78059 while (remaining > 0) { 1773*1c42de6dSgd78059 page_idx = blk_addr & 0xff; 1774*1c42de6dSgd78059 if ((page_idx + remaining) > 0x100) { 1775*1c42de6dSgd78059 blk_size = 0x100 - page_idx; 1776*1c42de6dSgd78059 } else { 1777*1c42de6dSgd78059 blk_size = remaining; 1778*1c42de6dSgd78059 } 1779*1c42de6dSgd78059 1780*1c42de6dSgd78059 /* Select correct eeprom page */ 1781*1c42de6dSgd78059 this_page = blk_addr >> 8; 1782*1c42de6dSgd78059 bscv_put8(ssp, chan_eeprom, EBUS_IDX_EEPROM_PAGESEL, this_page); 1783*1c42de6dSgd78059 1784*1c42de6dSgd78059 bscv_trace(ssp, 'M', "lom_eerw", 1785*1c42de6dSgd78059 "%s data @0x%x.%02x, size 0x%x, 0x%x bytes remaining", 1786*1c42de6dSgd78059 is_write ? "writing" : "reading", 1787*1c42de6dSgd78059 this_page, page_idx, blk_size, remaining - blk_size); 1788*1c42de6dSgd78059 1789*1c42de6dSgd78059 bscv_rep_rw8(ssp, chan_eeprom, 1790*1c42de6dSgd78059 buf, BSCVA(EBUS_CMD_SPACE_EEPROM, page_idx), 1791*1c42de6dSgd78059 blk_size, DDI_DEV_AUTOINCR, is_write); 1792*1c42de6dSgd78059 1793*1c42de6dSgd78059 if (bscv_faulty(ssp) || bscv_session_error(ssp)) { 1794*1c42de6dSgd78059 res = EIO; 1795*1c42de6dSgd78059 break; 1796*1c42de6dSgd78059 } 1797*1c42de6dSgd78059 1798*1c42de6dSgd78059 remaining -= blk_size; 1799*1c42de6dSgd78059 blk_addr += blk_size; 1800*1c42de6dSgd78059 buf += blk_size; 1801*1c42de6dSgd78059 } 1802*1c42de6dSgd78059 1803*1c42de6dSgd78059 return (res); 1804*1c42de6dSgd78059 } 1805*1c42de6dSgd78059 1806*1c42de6dSgd78059 static boolean_t 1807*1c42de6dSgd78059 bscv_is_null_event(bscv_soft_state_t *ssp, lom_event_t *e) 1808*1c42de6dSgd78059 { 1809*1c42de6dSgd78059 ASSERT(e != NULL); 1810*1c42de6dSgd78059 1811*1c42de6dSgd78059 if (EVENT_DECODE_SUBSYS(e->ev_subsys) == EVENT_SUBSYS_NONE && 1812*1c42de6dSgd78059 e->ev_event == EVENT_NONE) { 1813*1c42de6dSgd78059 /* 1814*1c42de6dSgd78059 * This marks a NULL event. 1815*1c42de6dSgd78059 */ 1816*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_is_null_event", 1817*1c42de6dSgd78059 "EVENT_SUBSYS_NONE/EVENT_NONE null event"); 1818*1c42de6dSgd78059 return (B_TRUE); 1819*1c42de6dSgd78059 } else if (e->ev_subsys == 0xff && e->ev_event == 0xff) { 1820*1c42de6dSgd78059 /* 1821*1c42de6dSgd78059 * Under some circumstances, we've seen all 1s to represent 1822*1c42de6dSgd78059 * a manually cleared event log at the BSC prompt. Only 1823*1c42de6dSgd78059 * a test/diagnosis environment is likely to show this. 1824*1c42de6dSgd78059 */ 1825*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_is_null_event", "0xffff null event"); 1826*1c42de6dSgd78059 return (B_TRUE); 1827*1c42de6dSgd78059 } else { 1828*1c42de6dSgd78059 /* 1829*1c42de6dSgd78059 * Not a NULL event. 1830*1c42de6dSgd78059 */ 1831*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_is_null_event", "returning False"); 1832*1c42de6dSgd78059 return (B_FALSE); 1833*1c42de6dSgd78059 } 1834*1c42de6dSgd78059 } 1835*1c42de6dSgd78059 1836*1c42de6dSgd78059 /* 1837*1c42de6dSgd78059 * ********************************************************************* 1838*1c42de6dSgd78059 * IOCTL Processing 1839*1c42de6dSgd78059 * ********************************************************************* 1840*1c42de6dSgd78059 */ 1841*1c42de6dSgd78059 1842*1c42de6dSgd78059 /* 1843*1c42de6dSgd78059 * function - bscv_ioctl 1844*1c42de6dSgd78059 * description - routine that acts as a high level manager for ioctls. It 1845*1c42de6dSgd78059 * calls the appropriate handler for ioctls on the alarm:mon and 1846*1c42de6dSgd78059 * alarm:ctl minor nodes respectively 1847*1c42de6dSgd78059 * 1848*1c42de6dSgd78059 * Unsupported ioctls (now deprecated) 1849*1c42de6dSgd78059 * LOMIOCALCTL 1850*1c42de6dSgd78059 * LOMIOCALSTATE 1851*1c42de6dSgd78059 * LOMIOCCLEARLOG 1852*1c42de6dSgd78059 * LOMIOCCTL 1853*1c42de6dSgd78059 * LOMIOCCTL2 1854*1c42de6dSgd78059 * LOMIOCDAEMON 1855*1c42de6dSgd78059 * LOMIOCDMON 1856*1c42de6dSgd78059 * LOMIOCDOGCTL, TSIOCDOGCTL 1857*1c42de6dSgd78059 * LOMIOCDOGPAT, TSIOCDOGPAT 1858*1c42de6dSgd78059 * LOMIOCDOGTIME, TSIOCDOGTIME 1859*1c42de6dSgd78059 * LOMIOCEVENTLOG 1860*1c42de6dSgd78059 * LOMIOCEVNT 1861*1c42de6dSgd78059 * LOMIOCGETMASK 1862*1c42de6dSgd78059 * LOMIOCMPROG 1863*1c42de6dSgd78059 * LOMIOCNBMON, TSIOCNBMON 1864*1c42de6dSgd78059 * LOMIOCSLEEP 1865*1c42de6dSgd78059 * LOMIOCUNLOCK, TSIOCUNLOCK 1866*1c42de6dSgd78059 * LOMIOCWTMON, TSIOCWTMON 1867*1c42de6dSgd78059 * 1868*1c42de6dSgd78059 * Supported ioctls 1869*1c42de6dSgd78059 * LOMIOCDOGSTATE, TSIOCDOGSTATE 1870*1c42de6dSgd78059 * LOMIOCPROG 1871*1c42de6dSgd78059 * LOMIOCPSUSTATE 1872*1c42de6dSgd78059 * LOMIOCFANSTATE 1873*1c42de6dSgd78059 * LOMIOCFLEDSTATE 1874*1c42de6dSgd78059 * LOMIOCINFO 1875*1c42de6dSgd78059 * LOMIOCMREAD 1876*1c42de6dSgd78059 * LOMIOCVOLTS 1877*1c42de6dSgd78059 * LOMIOCSTATS 1878*1c42de6dSgd78059 * LOMIOCTEMP 1879*1c42de6dSgd78059 * LOMIOCCONS 1880*1c42de6dSgd78059 * LOMIOCEVENTLOG2 1881*1c42de6dSgd78059 * LOMIOCINFO2 1882*1c42de6dSgd78059 * LOMIOCTEST 1883*1c42de6dSgd78059 * LOMIOCMPROG2 1884*1c42de6dSgd78059 * LOMIOCMREAD2 1885*1c42de6dSgd78059 * 1886*1c42de6dSgd78059 * inputs - device number, command, user space arg, filemode, user 1887*1c42de6dSgd78059 * credentials, return value 1888*1c42de6dSgd78059 * outputs - the return value propagated back by the lower level routines. 1889*1c42de6dSgd78059 */ 1890*1c42de6dSgd78059 1891*1c42de6dSgd78059 /*ARGSUSED*/ 1892*1c42de6dSgd78059 static int 1893*1c42de6dSgd78059 bscv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp) 1894*1c42de6dSgd78059 { 1895*1c42de6dSgd78059 bscv_soft_state_t *ssp; 1896*1c42de6dSgd78059 int instance; 1897*1c42de6dSgd78059 int res = 0; 1898*1c42de6dSgd78059 1899*1c42de6dSgd78059 instance = DEVICETOINSTANCE(dev); 1900*1c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, instance); 1901*1c42de6dSgd78059 if (ssp == NULL) { 1902*1c42de6dSgd78059 return (ENXIO); 1903*1c42de6dSgd78059 } 1904*1c42de6dSgd78059 1905*1c42de6dSgd78059 /* 1906*1c42de6dSgd78059 * The Combined Switch and Service Processor takes care of configuration 1907*1c42de6dSgd78059 * and control. The CSSP tells the BSC chip about it; therefore the 1908*1c42de6dSgd78059 * bscv driver doesn't send such configuration and control to the BSC. 1909*1c42de6dSgd78059 * Additionally Watchdog configuration is no longer done from userland 1910*1c42de6dSgd78059 * lom. 1911*1c42de6dSgd78059 */ 1912*1c42de6dSgd78059 switch (cmd) { 1913*1c42de6dSgd78059 case LOMIOCALCTL: 1914*1c42de6dSgd78059 case LOMIOCALSTATE: 1915*1c42de6dSgd78059 case LOMIOCCLEARLOG: 1916*1c42de6dSgd78059 case LOMIOCCTL: 1917*1c42de6dSgd78059 case LOMIOCCTL2: 1918*1c42de6dSgd78059 case LOMIOCDAEMON: 1919*1c42de6dSgd78059 case LOMIOCDMON: 1920*1c42de6dSgd78059 case LOMIOCDOGCTL: 1921*1c42de6dSgd78059 case LOMIOCDOGPAT: 1922*1c42de6dSgd78059 case LOMIOCDOGTIME: 1923*1c42de6dSgd78059 case LOMIOCEVENTLOG: 1924*1c42de6dSgd78059 case LOMIOCEVNT: 1925*1c42de6dSgd78059 case LOMIOCGETMASK: 1926*1c42de6dSgd78059 case LOMIOCMPROG: 1927*1c42de6dSgd78059 case LOMIOCNBMON: 1928*1c42de6dSgd78059 case LOMIOCSLEEP: 1929*1c42de6dSgd78059 case LOMIOCUNLOCK: 1930*1c42de6dSgd78059 case LOMIOCWTMON: 1931*1c42de6dSgd78059 return (ENOTSUP); 1932*1c42de6dSgd78059 } 1933*1c42de6dSgd78059 1934*1c42de6dSgd78059 /* 1935*1c42de6dSgd78059 * set the default result. 1936*1c42de6dSgd78059 */ 1937*1c42de6dSgd78059 1938*1c42de6dSgd78059 *rvalp = 0; 1939*1c42de6dSgd78059 1940*1c42de6dSgd78059 if (ssp->cssp_prog) { 1941*1c42de6dSgd78059 return (ENXIO); 1942*1c42de6dSgd78059 } else if ((ssp->prog_mode_only || ssp->programming) && 1943*1c42de6dSgd78059 cmd != LOMIOCPROG) { 1944*1c42de6dSgd78059 return (ENXIO); 1945*1c42de6dSgd78059 } 1946*1c42de6dSgd78059 1947*1c42de6dSgd78059 /* 1948*1c42de6dSgd78059 * Check that the caller has appropriate access permissions 1949*1c42de6dSgd78059 * (FWRITE set in mode) for those ioctls which change lom 1950*1c42de6dSgd78059 * state 1951*1c42de6dSgd78059 */ 1952*1c42de6dSgd78059 if (!(mode & FWRITE)) { 1953*1c42de6dSgd78059 switch (cmd) { 1954*1c42de6dSgd78059 case LOMIOCMPROG2: 1955*1c42de6dSgd78059 case LOMIOCMREAD2: 1956*1c42de6dSgd78059 case LOMIOCPROG: 1957*1c42de6dSgd78059 case LOMIOCTEST: 1958*1c42de6dSgd78059 return (EACCES); 1959*1c42de6dSgd78059 /* NOTREACHED */ 1960*1c42de6dSgd78059 default: 1961*1c42de6dSgd78059 /* Does not require write access */ 1962*1c42de6dSgd78059 break; 1963*1c42de6dSgd78059 } 1964*1c42de6dSgd78059 } 1965*1c42de6dSgd78059 1966*1c42de6dSgd78059 switch (cmd) { 1967*1c42de6dSgd78059 1968*1c42de6dSgd78059 case LOMIOCDOGSTATE: 1969*1c42de6dSgd78059 res = bscv_ioc_dogstate(ssp, arg, mode); 1970*1c42de6dSgd78059 break; 1971*1c42de6dSgd78059 1972*1c42de6dSgd78059 case LOMIOCPROG: 1973*1c42de6dSgd78059 res = bscv_prog(ssp, arg, mode); 1974*1c42de6dSgd78059 break; 1975*1c42de6dSgd78059 1976*1c42de6dSgd78059 case LOMIOCPSUSTATE: 1977*1c42de6dSgd78059 res = bscv_ioc_psustate(ssp, arg, mode); 1978*1c42de6dSgd78059 break; 1979*1c42de6dSgd78059 1980*1c42de6dSgd78059 case LOMIOCFANSTATE: 1981*1c42de6dSgd78059 res = bscv_ioc_fanstate(ssp, arg, mode); 1982*1c42de6dSgd78059 break; 1983*1c42de6dSgd78059 1984*1c42de6dSgd78059 case LOMIOCFLEDSTATE: 1985*1c42de6dSgd78059 res = bscv_ioc_fledstate(ssp, arg, mode); 1986*1c42de6dSgd78059 break; 1987*1c42de6dSgd78059 1988*1c42de6dSgd78059 case LOMIOCLEDSTATE: 1989*1c42de6dSgd78059 res = bscv_ioc_ledstate(ssp, arg, mode); 1990*1c42de6dSgd78059 break; 1991*1c42de6dSgd78059 1992*1c42de6dSgd78059 case LOMIOCINFO: 1993*1c42de6dSgd78059 res = bscv_ioc_info(ssp, arg, mode); 1994*1c42de6dSgd78059 break; 1995*1c42de6dSgd78059 1996*1c42de6dSgd78059 case LOMIOCMREAD: 1997*1c42de6dSgd78059 res = bscv_ioc_mread(ssp, arg, mode); 1998*1c42de6dSgd78059 break; 1999*1c42de6dSgd78059 2000*1c42de6dSgd78059 case LOMIOCVOLTS: 2001*1c42de6dSgd78059 res = bscv_ioc_volts(ssp, arg, mode); 2002*1c42de6dSgd78059 break; 2003*1c42de6dSgd78059 2004*1c42de6dSgd78059 case LOMIOCSTATS: 2005*1c42de6dSgd78059 res = bscv_ioc_stats(ssp, arg, mode); 2006*1c42de6dSgd78059 break; 2007*1c42de6dSgd78059 2008*1c42de6dSgd78059 case LOMIOCTEMP: 2009*1c42de6dSgd78059 res = bscv_ioc_temp(ssp, arg, mode); 2010*1c42de6dSgd78059 break; 2011*1c42de6dSgd78059 2012*1c42de6dSgd78059 case LOMIOCCONS: 2013*1c42de6dSgd78059 res = bscv_ioc_cons(ssp, arg, mode); 2014*1c42de6dSgd78059 break; 2015*1c42de6dSgd78059 2016*1c42de6dSgd78059 case LOMIOCEVENTLOG2: 2017*1c42de6dSgd78059 res = bscv_ioc_eventlog2(ssp, arg, mode); 2018*1c42de6dSgd78059 break; 2019*1c42de6dSgd78059 2020*1c42de6dSgd78059 case LOMIOCINFO2: 2021*1c42de6dSgd78059 res = bscv_ioc_info2(ssp, arg, mode); 2022*1c42de6dSgd78059 break; 2023*1c42de6dSgd78059 2024*1c42de6dSgd78059 case LOMIOCTEST: 2025*1c42de6dSgd78059 res = bscv_ioc_test(ssp, arg, mode); 2026*1c42de6dSgd78059 break; 2027*1c42de6dSgd78059 2028*1c42de6dSgd78059 case LOMIOCMPROG2: 2029*1c42de6dSgd78059 res = bscv_ioc_mprog2(ssp, arg, mode); 2030*1c42de6dSgd78059 break; 2031*1c42de6dSgd78059 2032*1c42de6dSgd78059 case LOMIOCMREAD2: 2033*1c42de6dSgd78059 res = bscv_ioc_mread2(ssp, arg, mode); 2034*1c42de6dSgd78059 break; 2035*1c42de6dSgd78059 2036*1c42de6dSgd78059 default: 2037*1c42de6dSgd78059 bscv_trace(ssp, 'I', "bscv_ioctl", "Invalid IOCTL 0x%x", cmd); 2038*1c42de6dSgd78059 res = EINVAL; 2039*1c42de6dSgd78059 } 2040*1c42de6dSgd78059 return (res); 2041*1c42de6dSgd78059 } 2042*1c42de6dSgd78059 2043*1c42de6dSgd78059 /* 2044*1c42de6dSgd78059 * LOMIOCDOGSTATE 2045*1c42de6dSgd78059 * TSIOCDOGSTATE - indicate whether the alarm watchdog and reset 2046*1c42de6dSgd78059 * circuitry is enabled or not. 2047*1c42de6dSgd78059 */ 2048*1c42de6dSgd78059 static int 2049*1c42de6dSgd78059 bscv_ioc_dogstate(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2050*1c42de6dSgd78059 { 2051*1c42de6dSgd78059 lom_dogstate_t dogstate; 2052*1c42de6dSgd78059 uint8_t dogval; 2053*1c42de6dSgd78059 int res = 0; 2054*1c42de6dSgd78059 2055*1c42de6dSgd78059 dogval = bscv_get8_locked(ssp, chan_general, EBUS_IDX_WDOG_CTRL, &res); 2056*1c42de6dSgd78059 dogstate.dog_enable = (dogval & EBUS_WDOG_ENABLE) ? 1 : 0; 2057*1c42de6dSgd78059 dogstate.reset_enable = (dogval & EBUS_WDOG_RST) ? 1 : 0; 2058*1c42de6dSgd78059 dogstate.dog_timeout = bscv_get8_locked(ssp, chan_general, 2059*1c42de6dSgd78059 EBUS_IDX_WDOG_TIME, &res); 2060*1c42de6dSgd78059 2061*1c42de6dSgd78059 if ((res == 0) && 2062*1c42de6dSgd78059 (ddi_copyout((caddr_t)&dogstate, 2063*1c42de6dSgd78059 (caddr_t)arg, sizeof (dogstate), mode) < 0)) { 2064*1c42de6dSgd78059 res = EFAULT; 2065*1c42de6dSgd78059 } 2066*1c42de6dSgd78059 return (res); 2067*1c42de6dSgd78059 } 2068*1c42de6dSgd78059 2069*1c42de6dSgd78059 /* 2070*1c42de6dSgd78059 * LOMIOCPSUSTATE - returns full information for 4 PSUs. All this 2071*1c42de6dSgd78059 * information is available from two bytes of LOMlite RAM, but if 2072*1c42de6dSgd78059 * on the first read it is noticed that two or more of the PSUs are 2073*1c42de6dSgd78059 * not present only 1 byte will be read subsequently. 2074*1c42de6dSgd78059 */ 2075*1c42de6dSgd78059 static int 2076*1c42de6dSgd78059 bscv_ioc_psustate(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2077*1c42de6dSgd78059 { 2078*1c42de6dSgd78059 lom_psudata_t psudata; 2079*1c42de6dSgd78059 uint8_t psustat; 2080*1c42de6dSgd78059 int i; 2081*1c42de6dSgd78059 int res = 0; 2082*1c42de6dSgd78059 2083*1c42de6dSgd78059 for (i = 0; i < MAX_PSUS; i++) { 2084*1c42de6dSgd78059 psustat = bscv_get8_locked(ssp, chan_general, 2085*1c42de6dSgd78059 EBUS_IDX_PSU1_STAT + i, &res); 2086*1c42de6dSgd78059 psudata.fitted[i] = psustat & EBUS_PSU_PRESENT; 2087*1c42de6dSgd78059 psudata.output[i] = psustat & EBUS_PSU_OUTPUT; 2088*1c42de6dSgd78059 psudata.supplyb[i] = psustat & EBUS_PSU_INPUTB; 2089*1c42de6dSgd78059 psudata.supplya[i] = psustat & EBUS_PSU_INPUTA; 2090*1c42de6dSgd78059 psudata.standby[i] = psustat & EBUS_PSU_STANDBY; 2091*1c42de6dSgd78059 } 2092*1c42de6dSgd78059 2093*1c42de6dSgd78059 if (ddi_copyout((caddr_t)&psudata, (caddr_t)arg, sizeof (psudata), 2094*1c42de6dSgd78059 mode) < 0) { 2095*1c42de6dSgd78059 res = EFAULT; 2096*1c42de6dSgd78059 } 2097*1c42de6dSgd78059 return (res); 2098*1c42de6dSgd78059 } 2099*1c42de6dSgd78059 2100*1c42de6dSgd78059 /* 2101*1c42de6dSgd78059 * LOMIOCFANSTATE - returns full information including speed for 4 2102*1c42de6dSgd78059 * fans and the minimum and maximum operating speeds for each fan as 2103*1c42de6dSgd78059 * stored in the READ ONLY EEPROM data. As this EEPROM data is set 2104*1c42de6dSgd78059 * at manufacture time, this data should only be read by the driver 2105*1c42de6dSgd78059 * once and stored locally. 2106*1c42de6dSgd78059 */ 2107*1c42de6dSgd78059 static int 2108*1c42de6dSgd78059 bscv_ioc_fanstate(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2109*1c42de6dSgd78059 { 2110*1c42de6dSgd78059 lom_fandata_t fandata; 2111*1c42de6dSgd78059 int numfans; 2112*1c42de6dSgd78059 int i; 2113*1c42de6dSgd78059 int res = 0; 2114*1c42de6dSgd78059 2115*1c42de6dSgd78059 bzero(&fandata, sizeof (lom_fandata_t)); 2116*1c42de6dSgd78059 numfans = EBUS_CONFIG_NFAN_DEC(bscv_get8_locked(ssp, 2117*1c42de6dSgd78059 chan_general, EBUS_IDX_CONFIG, &res)); 2118*1c42de6dSgd78059 for (i = 0; (i < numfans) && (res == 0); i++) { 2119*1c42de6dSgd78059 if (ssp->fanspeed[i] != LOM_FAN_NOT_PRESENT) { 2120*1c42de6dSgd78059 fandata.fitted[i] = 1; 2121*1c42de6dSgd78059 fandata.speed[i] = ssp->fanspeed[i]; 2122*1c42de6dSgd78059 fandata.minspeed[i] = bscv_get8_cached(ssp, 2123*1c42de6dSgd78059 EBUS_IDX_FAN1_LOW + i); 2124*1c42de6dSgd78059 } 2125*1c42de6dSgd78059 } 2126*1c42de6dSgd78059 2127*1c42de6dSgd78059 if ((res == 0) && 2128*1c42de6dSgd78059 (ddi_copyout((caddr_t)&fandata, (caddr_t)arg, sizeof (fandata), 2129*1c42de6dSgd78059 mode) < 0)) { 2130*1c42de6dSgd78059 res = EFAULT; 2131*1c42de6dSgd78059 } 2132*1c42de6dSgd78059 return (res); 2133*1c42de6dSgd78059 } 2134*1c42de6dSgd78059 2135*1c42de6dSgd78059 /* 2136*1c42de6dSgd78059 * LOMIOCFLEDSTATE - returns the state of the fault LED 2137*1c42de6dSgd78059 */ 2138*1c42de6dSgd78059 static int 2139*1c42de6dSgd78059 bscv_ioc_fledstate(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2140*1c42de6dSgd78059 { 2141*1c42de6dSgd78059 lom_fled_info_t fled_info; 2142*1c42de6dSgd78059 uint8_t fledstate; 2143*1c42de6dSgd78059 int res = 0; 2144*1c42de6dSgd78059 2145*1c42de6dSgd78059 fledstate = bscv_get8_locked(ssp, chan_general, EBUS_IDX_ALARM, &res); 2146*1c42de6dSgd78059 2147*1c42de6dSgd78059 /* Decode of 0x0F is off and 0x00-0x07 is on. */ 2148*1c42de6dSgd78059 if (EBUS_ALARM_LED_DEC(fledstate) == 0x0F) { 2149*1c42de6dSgd78059 fled_info.on = 0; 2150*1c42de6dSgd78059 } else { 2151*1c42de6dSgd78059 /* has +1 here - not 2 as in the info ioctl */ 2152*1c42de6dSgd78059 fled_info.on = EBUS_ALARM_LED_DEC(fledstate) + 1; 2153*1c42de6dSgd78059 } 2154*1c42de6dSgd78059 if ((res == 0) && 2155*1c42de6dSgd78059 (ddi_copyout((caddr_t)&fled_info, (caddr_t)arg, 2156*1c42de6dSgd78059 sizeof (fled_info), mode) < 0)) { 2157*1c42de6dSgd78059 res = EFAULT; 2158*1c42de6dSgd78059 } 2159*1c42de6dSgd78059 return (res); 2160*1c42de6dSgd78059 } 2161*1c42de6dSgd78059 2162*1c42de6dSgd78059 /* 2163*1c42de6dSgd78059 * LOMIOCLEDSTATE - returns the state of the requested LED 2164*1c42de6dSgd78059 */ 2165*1c42de6dSgd78059 static int 2166*1c42de6dSgd78059 bscv_ioc_ledstate(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2167*1c42de6dSgd78059 { 2168*1c42de6dSgd78059 lom_led_state_t led_state; 2169*1c42de6dSgd78059 int fw_led_state; 2170*1c42de6dSgd78059 int res = 0; 2171*1c42de6dSgd78059 2172*1c42de6dSgd78059 /* copy in arguments supplied */ 2173*1c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)&led_state, 2174*1c42de6dSgd78059 sizeof (lom_led_state_t), mode) < 0) { 2175*1c42de6dSgd78059 return (EFAULT); 2176*1c42de6dSgd78059 } 2177*1c42de6dSgd78059 2178*1c42de6dSgd78059 /* 2179*1c42de6dSgd78059 * check if led index is -1, if so set it to max value for 2180*1c42de6dSgd78059 * this implementation. 2181*1c42de6dSgd78059 */ 2182*1c42de6dSgd78059 if (led_state.index == -1) { 2183*1c42de6dSgd78059 led_state.index = MAX_LED_ID; 2184*1c42de6dSgd78059 } 2185*1c42de6dSgd78059 2186*1c42de6dSgd78059 /* is the index in a valid range */ 2187*1c42de6dSgd78059 if ((led_state.index > MAX_LED_ID) || (led_state.index < 0)) { 2188*1c42de6dSgd78059 led_state.state = LOM_LED_OUTOFRANGE; 2189*1c42de6dSgd78059 } else { 2190*1c42de6dSgd78059 /* read the relevant led info */ 2191*1c42de6dSgd78059 fw_led_state = bscv_get8_locked(ssp, chan_general, 2192*1c42de6dSgd78059 EBUS_IDX_LED1_STATUS + led_state.index, &res); 2193*1c42de6dSgd78059 2194*1c42de6dSgd78059 /* set the state values accordingly */ 2195*1c42de6dSgd78059 switch (fw_led_state) { 2196*1c42de6dSgd78059 case LOM_LED_STATE_OFF: 2197*1c42de6dSgd78059 led_state.state = LOM_LED_OFF; 2198*1c42de6dSgd78059 led_state.colour = LOM_LED_COLOUR_ANY; 2199*1c42de6dSgd78059 break; 2200*1c42de6dSgd78059 case LOM_LED_STATE_ON_STEADY: 2201*1c42de6dSgd78059 led_state.state = LOM_LED_ON; 2202*1c42de6dSgd78059 led_state.colour = LOM_LED_COLOUR_ANY; 2203*1c42de6dSgd78059 break; 2204*1c42de6dSgd78059 case LOM_LED_STATE_ON_FLASHING: 2205*1c42de6dSgd78059 case LOM_LED_STATE_ON_SLOWFLASH: 2206*1c42de6dSgd78059 led_state.state = LOM_LED_BLINKING; 2207*1c42de6dSgd78059 led_state.colour = LOM_LED_COLOUR_ANY; 2208*1c42de6dSgd78059 break; 2209*1c42de6dSgd78059 case LOM_LED_STATE_NOT_PRESENT: 2210*1c42de6dSgd78059 led_state.state = LOM_LED_NOT_IMPLEMENTED; 2211*1c42de6dSgd78059 led_state.colour = LOM_LED_COLOUR_NONE; 2212*1c42de6dSgd78059 break; 2213*1c42de6dSgd78059 case LOM_LED_STATE_INACCESSIBLE: 2214*1c42de6dSgd78059 case LOM_LED_STATE_STANDBY: 2215*1c42de6dSgd78059 default: 2216*1c42de6dSgd78059 led_state.state = LOM_LED_ACCESS_ERROR; 2217*1c42de6dSgd78059 led_state.colour = LOM_LED_COLOUR_NONE; 2218*1c42de6dSgd78059 break; 2219*1c42de6dSgd78059 } 2220*1c42de6dSgd78059 2221*1c42de6dSgd78059 /* set the label info */ 2222*1c42de6dSgd78059 (void) strcpy(led_state.label, 2223*1c42de6dSgd78059 ssp->led_names[led_state.index]); 2224*1c42de6dSgd78059 } 2225*1c42de6dSgd78059 2226*1c42de6dSgd78059 /* copy out lom_state */ 2227*1c42de6dSgd78059 if ((res == 0) && 2228*1c42de6dSgd78059 (ddi_copyout((caddr_t)&led_state, (caddr_t)arg, 2229*1c42de6dSgd78059 sizeof (lom_led_state_t), mode) < 0)) { 2230*1c42de6dSgd78059 res = EFAULT; 2231*1c42de6dSgd78059 } 2232*1c42de6dSgd78059 return (res); 2233*1c42de6dSgd78059 } 2234*1c42de6dSgd78059 2235*1c42de6dSgd78059 /* 2236*1c42de6dSgd78059 * LOMIOCINFO - returns with a structure containing any information 2237*1c42de6dSgd78059 * stored on the LOMlite which a user should not need to access but 2238*1c42de6dSgd78059 * may be useful for diagnostic problems. The structure contains: the 2239*1c42de6dSgd78059 * serial escape character, alarm3 mode, version and checksum read from 2240*1c42de6dSgd78059 * RAM and the Product revision and ID read from EEPROM. 2241*1c42de6dSgd78059 */ 2242*1c42de6dSgd78059 static int 2243*1c42de6dSgd78059 bscv_ioc_info(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2244*1c42de6dSgd78059 { 2245*1c42de6dSgd78059 lom_info_t info; 2246*1c42de6dSgd78059 int i; 2247*1c42de6dSgd78059 uint16_t csum; 2248*1c42de6dSgd78059 int res = 0; 2249*1c42de6dSgd78059 2250*1c42de6dSgd78059 info.ser_char = bscv_get8_locked(ssp, chan_general, EBUS_IDX_ESCAPE, 2251*1c42de6dSgd78059 &res); 2252*1c42de6dSgd78059 info.a3mode = WATCHDOG; 2253*1c42de6dSgd78059 info.fver = bscv_get8_locked(ssp, chan_general, EBUS_IDX_FW_REV, &res); 2254*1c42de6dSgd78059 csum = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_HI, &res) 2255*1c42de6dSgd78059 << 8; 2256*1c42de6dSgd78059 csum |= bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_LO, &res); 2257*1c42de6dSgd78059 info.fchksum = csum; 2258*1c42de6dSgd78059 info.prod_rev = bscv_get8_locked(ssp, chan_general, EBUS_IDX_MODEL_REV, 2259*1c42de6dSgd78059 &res); 2260*1c42de6dSgd78059 for (i = 0; i < sizeof (info.prod_id); i++) { 2261*1c42de6dSgd78059 info.prod_id[i] = bscv_get8_locked(ssp, 2262*1c42de6dSgd78059 chan_general, EBUS_IDX_MODEL_ID1 + i, &res); 2263*1c42de6dSgd78059 } 2264*1c42de6dSgd78059 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_ALARM, &res) & 2265*1c42de6dSgd78059 EBUS_ALARM_NOEVENTS) { 2266*1c42de6dSgd78059 info.events = OFF; 2267*1c42de6dSgd78059 } else { 2268*1c42de6dSgd78059 info.events = ON; 2269*1c42de6dSgd78059 } 2270*1c42de6dSgd78059 2271*1c42de6dSgd78059 if ((res == 0) && 2272*1c42de6dSgd78059 (ddi_copyout((caddr_t)&info, (caddr_t)arg, sizeof (info), 2273*1c42de6dSgd78059 mode) < 0)) { 2274*1c42de6dSgd78059 res = EFAULT; 2275*1c42de6dSgd78059 } 2276*1c42de6dSgd78059 return (res); 2277*1c42de6dSgd78059 } 2278*1c42de6dSgd78059 2279*1c42de6dSgd78059 /* 2280*1c42de6dSgd78059 * LOMIOCMREAD - used to query the LOMlite configuration parameters 2281*1c42de6dSgd78059 */ 2282*1c42de6dSgd78059 static int 2283*1c42de6dSgd78059 bscv_ioc_mread(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2284*1c42de6dSgd78059 { 2285*1c42de6dSgd78059 lom_mprog_t mprog; 2286*1c42de6dSgd78059 int i; 2287*1c42de6dSgd78059 int fanz; 2288*1c42de6dSgd78059 int res = 0; 2289*1c42de6dSgd78059 2290*1c42de6dSgd78059 for (i = 0; i < sizeof (mprog.mod_id); i++) { 2291*1c42de6dSgd78059 mprog.mod_id[i] = bscv_get8_locked(ssp, chan_general, 2292*1c42de6dSgd78059 EBUS_IDX_MODEL_ID1 + i, &res); 2293*1c42de6dSgd78059 } 2294*1c42de6dSgd78059 mprog.mod_rev = bscv_get8_locked(ssp, chan_general, EBUS_IDX_MODEL_REV, 2295*1c42de6dSgd78059 &res); 2296*1c42de6dSgd78059 mprog.config = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG, 2297*1c42de6dSgd78059 &res); 2298*1c42de6dSgd78059 2299*1c42de6dSgd78059 /* Read the fan calibration values */ 2300*1c42de6dSgd78059 fanz = sizeof (mprog.fanhz) / sizeof (mprog.fanhz[0]); 2301*1c42de6dSgd78059 for (i = 0; i < fanz; i++) { 2302*1c42de6dSgd78059 mprog.fanhz[i] = bscv_get8_cached(ssp, 2303*1c42de6dSgd78059 EBUS_IDX_FAN1_CAL + i); 2304*1c42de6dSgd78059 mprog.fanmin[i] = bscv_get8_cached(ssp, 2305*1c42de6dSgd78059 EBUS_IDX_FAN1_LOW + i); 2306*1c42de6dSgd78059 } 2307*1c42de6dSgd78059 2308*1c42de6dSgd78059 if ((res == 0) && 2309*1c42de6dSgd78059 (ddi_copyout((caddr_t)&mprog, (caddr_t)arg, sizeof (mprog), 2310*1c42de6dSgd78059 mode) < 0)) { 2311*1c42de6dSgd78059 res = EFAULT; 2312*1c42de6dSgd78059 } 2313*1c42de6dSgd78059 return (res); 2314*1c42de6dSgd78059 } 2315*1c42de6dSgd78059 2316*1c42de6dSgd78059 /* 2317*1c42de6dSgd78059 * LOMIOCVOLTS 2318*1c42de6dSgd78059 */ 2319*1c42de6dSgd78059 static int 2320*1c42de6dSgd78059 bscv_ioc_volts(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2321*1c42de6dSgd78059 { 2322*1c42de6dSgd78059 int i; 2323*1c42de6dSgd78059 uint16_t supply; 2324*1c42de6dSgd78059 int res = 0; 2325*1c42de6dSgd78059 2326*1c42de6dSgd78059 supply = (bscv_get8_locked(ssp, chan_general, EBUS_IDX_SUPPLY_HI, &res) 2327*1c42de6dSgd78059 << 8) | bscv_get8_locked(ssp, chan_general, EBUS_IDX_SUPPLY_LO, 2328*1c42de6dSgd78059 &res); 2329*1c42de6dSgd78059 2330*1c42de6dSgd78059 for (i = 0; i < ssp->volts.num; i++) { 2331*1c42de6dSgd78059 ssp->volts.status[i] = (supply >> i) & 1; 2332*1c42de6dSgd78059 } 2333*1c42de6dSgd78059 2334*1c42de6dSgd78059 if ((res == 0) && 2335*1c42de6dSgd78059 (ddi_copyout((caddr_t)&ssp->volts, (caddr_t)arg, 2336*1c42de6dSgd78059 sizeof (ssp->volts), mode) < 0)) { 2337*1c42de6dSgd78059 res = EFAULT; 2338*1c42de6dSgd78059 } 2339*1c42de6dSgd78059 return (res); 2340*1c42de6dSgd78059 } 2341*1c42de6dSgd78059 2342*1c42de6dSgd78059 /* 2343*1c42de6dSgd78059 * LOMIOCSTATS 2344*1c42de6dSgd78059 */ 2345*1c42de6dSgd78059 static int 2346*1c42de6dSgd78059 bscv_ioc_stats(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2347*1c42de6dSgd78059 { 2348*1c42de6dSgd78059 int i; 2349*1c42de6dSgd78059 uint8_t status; 2350*1c42de6dSgd78059 int res = 0; 2351*1c42de6dSgd78059 2352*1c42de6dSgd78059 status = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CBREAK_STATUS, 2353*1c42de6dSgd78059 &res); 2354*1c42de6dSgd78059 for (i = 0; i < ssp->sflags.num; i++) { 2355*1c42de6dSgd78059 ssp->sflags.status[i] = (int)((status >> i) & 1); 2356*1c42de6dSgd78059 } 2357*1c42de6dSgd78059 2358*1c42de6dSgd78059 if ((res == 0) && 2359*1c42de6dSgd78059 (ddi_copyout((caddr_t)&ssp->sflags, (caddr_t)arg, 2360*1c42de6dSgd78059 sizeof (ssp->sflags), mode) < 0)) { 2361*1c42de6dSgd78059 res = EFAULT; 2362*1c42de6dSgd78059 } 2363*1c42de6dSgd78059 return (res); 2364*1c42de6dSgd78059 } 2365*1c42de6dSgd78059 2366*1c42de6dSgd78059 /* 2367*1c42de6dSgd78059 * LOMIOCTEMP 2368*1c42de6dSgd78059 */ 2369*1c42de6dSgd78059 static int 2370*1c42de6dSgd78059 bscv_ioc_temp(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2371*1c42de6dSgd78059 { 2372*1c42de6dSgd78059 int i; 2373*1c42de6dSgd78059 int idx; 2374*1c42de6dSgd78059 uint8_t status_ov; 2375*1c42de6dSgd78059 lom_temp_t temps; 2376*1c42de6dSgd78059 int res = 0; 2377*1c42de6dSgd78059 2378*1c42de6dSgd78059 bzero(&temps, sizeof (temps)); 2379*1c42de6dSgd78059 idx = 0; 2380*1c42de6dSgd78059 for (i = 0; i < ssp->temps.num; i++) { 2381*1c42de6dSgd78059 if (ssp->temps.temp[i] != LOM_TEMP_STATE_NOT_PRESENT) { 2382*1c42de6dSgd78059 temps.temp[idx] = ssp->temps.temp[i]; 2383*1c42de6dSgd78059 bcopy(ssp->temps.name[i], temps.name[idx], 2384*1c42de6dSgd78059 sizeof (temps.name[idx])); 2385*1c42de6dSgd78059 temps.warning[idx] = ssp->temps.warning[i]; 2386*1c42de6dSgd78059 temps.shutdown[idx] = ssp->temps.shutdown[i]; 2387*1c42de6dSgd78059 idx++; 2388*1c42de6dSgd78059 } 2389*1c42de6dSgd78059 } 2390*1c42de6dSgd78059 temps.num = idx; 2391*1c42de6dSgd78059 2392*1c42de6dSgd78059 bcopy(ssp->temps.name_ov, temps.name_ov, sizeof (temps.name_ov)); 2393*1c42de6dSgd78059 temps.num_ov = ssp->temps.num_ov; 2394*1c42de6dSgd78059 status_ov = bscv_get8_locked(ssp, chan_general, EBUS_IDX_OTEMP_STATUS, 2395*1c42de6dSgd78059 &res); 2396*1c42de6dSgd78059 for (i = 0; i < ssp->temps.num_ov; i++) { 2397*1c42de6dSgd78059 ssp->temps.status_ov[i] = (status_ov >> i) & 1; 2398*1c42de6dSgd78059 } 2399*1c42de6dSgd78059 2400*1c42de6dSgd78059 if ((res == 0) && 2401*1c42de6dSgd78059 (ddi_copyout((caddr_t)&temps, (caddr_t)arg, sizeof (temps), 2402*1c42de6dSgd78059 mode) < 0)) { 2403*1c42de6dSgd78059 res = EFAULT; 2404*1c42de6dSgd78059 } 2405*1c42de6dSgd78059 return (res); 2406*1c42de6dSgd78059 } 2407*1c42de6dSgd78059 2408*1c42de6dSgd78059 /* 2409*1c42de6dSgd78059 * LOMIOCCONS 2410*1c42de6dSgd78059 */ 2411*1c42de6dSgd78059 static int 2412*1c42de6dSgd78059 bscv_ioc_cons(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2413*1c42de6dSgd78059 { 2414*1c42de6dSgd78059 lom_cbuf_t cbuf; 2415*1c42de6dSgd78059 int datasize; 2416*1c42de6dSgd78059 int res = 0; 2417*1c42de6dSgd78059 2418*1c42de6dSgd78059 bzero(&cbuf, sizeof (cbuf)); 2419*1c42de6dSgd78059 datasize = EBUS_IDX1_CONS_BUF_END - EBUS_IDX1_CONS_BUF_START + 1; 2420*1c42de6dSgd78059 /* Ensure that we do not overfill cbuf and that it is NUL terminated */ 2421*1c42de6dSgd78059 if (datasize > (sizeof (cbuf) - 1)) { 2422*1c42de6dSgd78059 datasize = sizeof (cbuf) - 1; 2423*1c42de6dSgd78059 } 2424*1c42de6dSgd78059 bscv_rep_get8_locked(ssp, chan_general, (uint8_t *)cbuf.lrbuf, 2425*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE1, (EBUS_IDX1_CONS_BUF_END - datasize + 1)), 2426*1c42de6dSgd78059 datasize, DDI_DEV_AUTOINCR, &res); 2427*1c42de6dSgd78059 /* This is always within the array due to the checks above */ 2428*1c42de6dSgd78059 cbuf.lrbuf[datasize] = '\0'; 2429*1c42de6dSgd78059 2430*1c42de6dSgd78059 if ((res == 0) && 2431*1c42de6dSgd78059 (ddi_copyout((caddr_t)&cbuf, (caddr_t)arg, sizeof (cbuf), 2432*1c42de6dSgd78059 mode) < 0)) { 2433*1c42de6dSgd78059 res = EFAULT; 2434*1c42de6dSgd78059 } 2435*1c42de6dSgd78059 return (res); 2436*1c42de6dSgd78059 } 2437*1c42de6dSgd78059 2438*1c42de6dSgd78059 /* 2439*1c42de6dSgd78059 * LOMIOCEVENTLOG2 2440*1c42de6dSgd78059 */ 2441*1c42de6dSgd78059 static int 2442*1c42de6dSgd78059 bscv_ioc_eventlog2(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2443*1c42de6dSgd78059 { 2444*1c42de6dSgd78059 lom_eventlog2_t *eventlog2; 2445*1c42de6dSgd78059 int events_recorded; 2446*1c42de6dSgd78059 int level; 2447*1c42de6dSgd78059 uint16_t next_offset; 2448*1c42de6dSgd78059 lom_event_t event; 2449*1c42de6dSgd78059 int res = 0; 2450*1c42de6dSgd78059 2451*1c42de6dSgd78059 eventlog2 = (lom_eventlog2_t *)kmem_zalloc(sizeof (*eventlog2), 2452*1c42de6dSgd78059 KM_SLEEP); 2453*1c42de6dSgd78059 2454*1c42de6dSgd78059 /* 2455*1c42de6dSgd78059 * First get number of events and level requested. 2456*1c42de6dSgd78059 */ 2457*1c42de6dSgd78059 2458*1c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)eventlog2, 2459*1c42de6dSgd78059 sizeof (lom_eventlog2_t), mode) < 0) { 2460*1c42de6dSgd78059 kmem_free((void *)eventlog2, sizeof (*eventlog2)); 2461*1c42de6dSgd78059 return (EFAULT); 2462*1c42de6dSgd78059 } 2463*1c42de6dSgd78059 2464*1c42de6dSgd78059 bscv_enter(ssp); 2465*1c42de6dSgd78059 2466*1c42de6dSgd78059 /* 2467*1c42de6dSgd78059 * OK we have full private access to the LOM now so loop 2468*1c42de6dSgd78059 * over the eventlog addr spaces until we get the required 2469*1c42de6dSgd78059 * number of events. 2470*1c42de6dSgd78059 */ 2471*1c42de6dSgd78059 2472*1c42de6dSgd78059 if (!bscv_window_setup(ssp)) { 2473*1c42de6dSgd78059 res = EIO; 2474*1c42de6dSgd78059 bscv_exit(ssp); 2475*1c42de6dSgd78059 kmem_free((void *)eventlog2, sizeof (*eventlog2)); 2476*1c42de6dSgd78059 return (res); 2477*1c42de6dSgd78059 } 2478*1c42de6dSgd78059 2479*1c42de6dSgd78059 /* 2480*1c42de6dSgd78059 * Read count, next event ptr MSB,LSB. Note a read of count 2481*1c42de6dSgd78059 * is necessary to latch values for the next event ptr 2482*1c42de6dSgd78059 */ 2483*1c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS); 2484*1c42de6dSgd78059 next_offset = bscv_get16(ssp, chan_general, EBUS_IDX_LOG_PTR_HI); 2485*1c42de6dSgd78059 bscv_trace(ssp, 'I', "bscv_ioc_eventlog2", "log_ptr_hi 0x%x", 2486*1c42de6dSgd78059 next_offset); 2487*1c42de6dSgd78059 2488*1c42de6dSgd78059 events_recorded = 0; 2489*1c42de6dSgd78059 2490*1c42de6dSgd78059 while (events_recorded < eventlog2->num) { 2491*1c42de6dSgd78059 /* 2492*1c42de6dSgd78059 * Working backwards - read an event at a time. 2493*1c42de6dSgd78059 * next_offset is one event on from where we want to be! 2494*1c42de6dSgd78059 * Decrement next_offset and maybe wrap to the end of the 2495*1c42de6dSgd78059 * buffer. 2496*1c42de6dSgd78059 * Note the unsigned arithmetic, so check values first! 2497*1c42de6dSgd78059 */ 2498*1c42de6dSgd78059 if (next_offset <= ssp->eventlog_start) { 2499*1c42de6dSgd78059 /* Wrap to the end of the buffer */ 2500*1c42de6dSgd78059 next_offset = ssp->eventlog_start + ssp->eventlog_size; 2501*1c42de6dSgd78059 bscv_trace(ssp, 'I', "bscv_ioc_eventlog2", "wrapping" 2502*1c42de6dSgd78059 " around to end of buffer; next_offset 0x%x", 2503*1c42de6dSgd78059 next_offset); 2504*1c42de6dSgd78059 } 2505*1c42de6dSgd78059 next_offset -= sizeof (event); 2506*1c42de6dSgd78059 2507*1c42de6dSgd78059 if (bscv_eerw(ssp, next_offset, (uint8_t *)&event, 2508*1c42de6dSgd78059 sizeof (event), B_FALSE /* read */) != 0) { 2509*1c42de6dSgd78059 /* Fault reading data - stop */ 2510*1c42de6dSgd78059 bscv_trace(ssp, 'I', "bscv_ioc_eventlog2", "read" 2511*1c42de6dSgd78059 " failure for offset 0x%x", next_offset); 2512*1c42de6dSgd78059 res = EIO; 2513*1c42de6dSgd78059 break; 2514*1c42de6dSgd78059 } 2515*1c42de6dSgd78059 2516*1c42de6dSgd78059 if (bscv_is_null_event(ssp, &event)) { 2517*1c42de6dSgd78059 /* 2518*1c42de6dSgd78059 * No more events in this log so give up. 2519*1c42de6dSgd78059 */ 2520*1c42de6dSgd78059 bscv_trace(ssp, 'I', "bscv_ioc_eventlog2", "no more" 2521*1c42de6dSgd78059 " events left at offset 0x%x", next_offset); 2522*1c42de6dSgd78059 break; 2523*1c42de6dSgd78059 } 2524*1c42de6dSgd78059 2525*1c42de6dSgd78059 /* 2526*1c42de6dSgd78059 * Are we interested in this event 2527*1c42de6dSgd78059 */ 2528*1c42de6dSgd78059 2529*1c42de6dSgd78059 level = bscv_level_of_event(&event); 2530*1c42de6dSgd78059 if (level <= eventlog2->level) { 2531*1c42de6dSgd78059 /* Arggh why the funny byte ordering 3, 2, 0, 1 */ 2532*1c42de6dSgd78059 eventlog2->code[events_recorded] = 2533*1c42de6dSgd78059 ((unsigned)event.ev_event | 2534*1c42de6dSgd78059 ((unsigned)event.ev_subsys << 8) | 2535*1c42de6dSgd78059 ((unsigned)event.ev_resource << 16) | 2536*1c42de6dSgd78059 ((unsigned)event.ev_detail << 24)); 2537*1c42de6dSgd78059 2538*1c42de6dSgd78059 eventlog2->time[events_recorded] = 2539*1c42de6dSgd78059 ((unsigned)event.ev_data[0] | 2540*1c42de6dSgd78059 ((unsigned)event.ev_data[1] << 8) | 2541*1c42de6dSgd78059 ((unsigned)event.ev_data[3] << 16) | 2542*1c42de6dSgd78059 ((unsigned)event.ev_data[2] << 24)); 2543*1c42de6dSgd78059 2544*1c42de6dSgd78059 bscv_build_eventstring(ssp, 2545*1c42de6dSgd78059 &event, eventlog2->string[events_recorded], 2546*1c42de6dSgd78059 eventlog2->string[events_recorded] + 2547*1c42de6dSgd78059 sizeof (eventlog2->string[events_recorded])); 2548*1c42de6dSgd78059 events_recorded++; 2549*1c42de6dSgd78059 } 2550*1c42de6dSgd78059 } 2551*1c42de6dSgd78059 2552*1c42de6dSgd78059 eventlog2->num = events_recorded; 2553*1c42de6dSgd78059 2554*1c42de6dSgd78059 bscv_exit(ssp); 2555*1c42de6dSgd78059 2556*1c42de6dSgd78059 if ((res == 0) && 2557*1c42de6dSgd78059 (ddi_copyout((caddr_t)eventlog2, (caddr_t)arg, 2558*1c42de6dSgd78059 sizeof (lom_eventlog2_t), mode) < 0)) { 2559*1c42de6dSgd78059 res = EFAULT; 2560*1c42de6dSgd78059 } 2561*1c42de6dSgd78059 2562*1c42de6dSgd78059 kmem_free((void *)eventlog2, sizeof (lom_eventlog2_t)); 2563*1c42de6dSgd78059 return (res); 2564*1c42de6dSgd78059 } 2565*1c42de6dSgd78059 2566*1c42de6dSgd78059 /* 2567*1c42de6dSgd78059 * LOMIOCINFO2 2568*1c42de6dSgd78059 */ 2569*1c42de6dSgd78059 static int 2570*1c42de6dSgd78059 bscv_ioc_info2(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2571*1c42de6dSgd78059 { 2572*1c42de6dSgd78059 lom2_info_t info2; 2573*1c42de6dSgd78059 int i; 2574*1c42de6dSgd78059 uint16_t csum; 2575*1c42de6dSgd78059 int res = 0; 2576*1c42de6dSgd78059 2577*1c42de6dSgd78059 bzero(&info2, sizeof (info2)); 2578*1c42de6dSgd78059 2579*1c42de6dSgd78059 (void) strncpy(info2.escape_chars, ssp->escape_chars, 2580*1c42de6dSgd78059 sizeof (info2.escape_chars)); 2581*1c42de6dSgd78059 info2.serial_events = ssp->reporting_level | ssp->serial_reporting; 2582*1c42de6dSgd78059 info2.a3mode = WATCHDOG; 2583*1c42de6dSgd78059 2584*1c42de6dSgd78059 info2.fver = bscv_get8_locked(ssp, chan_general, EBUS_IDX_FW_REV, &res); 2585*1c42de6dSgd78059 csum = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_HI, &res) 2586*1c42de6dSgd78059 << 8; 2587*1c42de6dSgd78059 csum |= bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_LO, &res); 2588*1c42de6dSgd78059 info2.fchksum = csum; 2589*1c42de6dSgd78059 info2.prod_rev = bscv_get8_locked(ssp, chan_general, 2590*1c42de6dSgd78059 EBUS_IDX_MODEL_REV, &res); 2591*1c42de6dSgd78059 for (i = 0; i < sizeof (info2.prod_id); i++) { 2592*1c42de6dSgd78059 info2.prod_id[i] = bscv_get8_locked(ssp, chan_general, 2593*1c42de6dSgd78059 EBUS_IDX_MODEL_ID1 + i, &res); 2594*1c42de6dSgd78059 } 2595*1c42de6dSgd78059 info2.serial_config = bscv_get8_locked(ssp, chan_general, 2596*1c42de6dSgd78059 EBUS_IDX_SER_TIMEOUT, &res); 2597*1c42de6dSgd78059 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG_MISC, &res) & 2598*1c42de6dSgd78059 EBUS_CONFIG_MISC_SECURITY_ENABLED) { 2599*1c42de6dSgd78059 info2.serial_config |= LOM_SER_SECURITY; 2600*1c42de6dSgd78059 } 2601*1c42de6dSgd78059 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG_MISC, &res) & 2602*1c42de6dSgd78059 EBUS_CONFIG_MISC_AUTO_CONSOLE) { 2603*1c42de6dSgd78059 info2.serial_config |= LOM_SER_RETURN; 2604*1c42de6dSgd78059 } 2605*1c42de6dSgd78059 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_WDOG_CTRL, &res) & 2606*1c42de6dSgd78059 EBUS_WDOG_BREAK_DISABLE) { 2607*1c42de6dSgd78059 info2.serial_config |= LOM_DISABLE_WDOG_BREAK; 2608*1c42de6dSgd78059 } 2609*1c42de6dSgd78059 info2.baud_rate = bscv_get8_locked(ssp, chan_general, 2610*1c42de6dSgd78059 EBUS_IDX_SER_BAUD, &res); 2611*1c42de6dSgd78059 info2.serial_hw_config = 2612*1c42de6dSgd78059 ((int)bscv_get8_locked(ssp, chan_general, 2613*1c42de6dSgd78059 EBUS_IDX_SER_CHARMODE, &res) | 2614*1c42de6dSgd78059 ((int)bscv_get8_locked(ssp, chan_general, 2615*1c42de6dSgd78059 EBUS_IDX_SER_FLOWCTL, &res) << 8) | 2616*1c42de6dSgd78059 ((int)bscv_get8_locked(ssp, chan_general, 2617*1c42de6dSgd78059 EBUS_IDX_SER_MODEMTYPE, &res) << 16)); 2618*1c42de6dSgd78059 2619*1c42de6dSgd78059 /* 2620*1c42de6dSgd78059 * There is no phone home support on the blade platform. We hardcode 2621*1c42de6dSgd78059 * FALSE and NUL for config and script respectively. 2622*1c42de6dSgd78059 */ 2623*1c42de6dSgd78059 info2.phone_home_config = B_FALSE; 2624*1c42de6dSgd78059 info2.phone_home_script[0] = '\0'; 2625*1c42de6dSgd78059 2626*1c42de6dSgd78059 for (i = 0; i < ssp->num_fans; i++) { 2627*1c42de6dSgd78059 (void) strcpy(info2.fan_names[i], ssp->fan_names[i]); 2628*1c42de6dSgd78059 } 2629*1c42de6dSgd78059 2630*1c42de6dSgd78059 if ((res == 0) && 2631*1c42de6dSgd78059 (ddi_copyout((caddr_t)&info2, (caddr_t)arg, sizeof (info2), 2632*1c42de6dSgd78059 mode) < 0)) { 2633*1c42de6dSgd78059 res = EFAULT; 2634*1c42de6dSgd78059 } 2635*1c42de6dSgd78059 return (res); 2636*1c42de6dSgd78059 } 2637*1c42de6dSgd78059 2638*1c42de6dSgd78059 /* 2639*1c42de6dSgd78059 * LOMIOCTEST 2640*1c42de6dSgd78059 */ 2641*1c42de6dSgd78059 static int 2642*1c42de6dSgd78059 bscv_ioc_test(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2643*1c42de6dSgd78059 { 2644*1c42de6dSgd78059 uint32_t test; 2645*1c42de6dSgd78059 uint8_t testnum; 2646*1c42de6dSgd78059 uint8_t testarg; 2647*1c42de6dSgd78059 int res = 0; 2648*1c42de6dSgd78059 2649*1c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)&test, sizeof (test), 2650*1c42de6dSgd78059 mode) < 0) { 2651*1c42de6dSgd78059 return (EFAULT); 2652*1c42de6dSgd78059 } 2653*1c42de6dSgd78059 2654*1c42de6dSgd78059 /* 2655*1c42de6dSgd78059 * Extract num iterations. 2656*1c42de6dSgd78059 */ 2657*1c42de6dSgd78059 2658*1c42de6dSgd78059 testarg = (test & 0xff00) >> 8; 2659*1c42de6dSgd78059 testnum = test & 0xff; 2660*1c42de6dSgd78059 2661*1c42de6dSgd78059 bscv_trace(ssp, 'F', "bscv_ioc_test", 2662*1c42de6dSgd78059 "LOMIOCTEST data 0x%x (test 0x%x, arg 0x%x)", 2663*1c42de6dSgd78059 test, (EBUS_IDX_SELFTEST0 + testnum), testarg); 2664*1c42de6dSgd78059 2665*1c42de6dSgd78059 switch (testnum + EBUS_IDX_SELFTEST0) { 2666*1c42de6dSgd78059 default: 2667*1c42de6dSgd78059 /* Invalid test */ 2668*1c42de6dSgd78059 res = EINVAL; 2669*1c42de6dSgd78059 break; 2670*1c42de6dSgd78059 2671*1c42de6dSgd78059 case EBUS_IDX_SELFTEST0: /* power on self-test result */ 2672*1c42de6dSgd78059 case EBUS_IDX_SELFTEST1: /* not used currently */ 2673*1c42de6dSgd78059 case EBUS_IDX_SELFTEST2: /* not used currently */ 2674*1c42de6dSgd78059 case EBUS_IDX_SELFTEST3: /* not used currently */ 2675*1c42de6dSgd78059 case EBUS_IDX_SELFTEST4: /* not used currently */ 2676*1c42de6dSgd78059 case EBUS_IDX_SELFTEST5: /* not used currently */ 2677*1c42de6dSgd78059 case EBUS_IDX_SELFTEST6: /* LED self-test */ 2678*1c42de6dSgd78059 case EBUS_IDX_SELFTEST7: /* platform-specific tests */ 2679*1c42de6dSgd78059 /* Run the test */ 2680*1c42de6dSgd78059 2681*1c42de6dSgd78059 /* Stop other things and then run the test */ 2682*1c42de6dSgd78059 bscv_enter(ssp); 2683*1c42de6dSgd78059 2684*1c42de6dSgd78059 /* 2685*1c42de6dSgd78059 * Then we simply write the argument to the relevant register 2686*1c42de6dSgd78059 * and wait for the return code. 2687*1c42de6dSgd78059 */ 2688*1c42de6dSgd78059 bscv_put8(ssp, chan_general, 2689*1c42de6dSgd78059 EBUS_IDX_SELFTEST0 + testnum, testarg); 2690*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 2691*1c42de6dSgd78059 res = EIO; 2692*1c42de6dSgd78059 } else { 2693*1c42de6dSgd78059 /* Get hold of the SunVTS error code */ 2694*1c42de6dSgd78059 test = bscv_retcode(ssp); 2695*1c42de6dSgd78059 } 2696*1c42de6dSgd78059 2697*1c42de6dSgd78059 bscv_exit(ssp); 2698*1c42de6dSgd78059 break; 2699*1c42de6dSgd78059 } 2700*1c42de6dSgd78059 2701*1c42de6dSgd78059 bscv_trace(ssp, 'F', "bscv_ioc_test", 2702*1c42de6dSgd78059 "LOMIOCTEST status 0x%x, res 0x%x", test, res); 2703*1c42de6dSgd78059 if ((res == 0) && 2704*1c42de6dSgd78059 (ddi_copyout((caddr_t)&test, (caddr_t)arg, sizeof (test), 2705*1c42de6dSgd78059 mode) < 0)) { 2706*1c42de6dSgd78059 res = EFAULT; 2707*1c42de6dSgd78059 } 2708*1c42de6dSgd78059 return (res); 2709*1c42de6dSgd78059 } 2710*1c42de6dSgd78059 2711*1c42de6dSgd78059 /* 2712*1c42de6dSgd78059 * LOMIOCMPROG2 2713*1c42de6dSgd78059 */ 2714*1c42de6dSgd78059 static int 2715*1c42de6dSgd78059 bscv_ioc_mprog2(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2716*1c42de6dSgd78059 { 2717*1c42de6dSgd78059 lom2_mprog_t mprog2; 2718*1c42de6dSgd78059 uint32_t base_addr; 2719*1c42de6dSgd78059 uint32_t data_size; 2720*1c42de6dSgd78059 uint32_t eeprom_size; 2721*1c42de6dSgd78059 int res = 0; 2722*1c42de6dSgd78059 2723*1c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)&mprog2, sizeof (mprog2), 2724*1c42de6dSgd78059 mode) < 0) { 2725*1c42de6dSgd78059 return (EFAULT); 2726*1c42de6dSgd78059 } 2727*1c42de6dSgd78059 2728*1c42de6dSgd78059 /* 2729*1c42de6dSgd78059 * Note that originally this was accessed as 255 byte pages 2730*1c42de6dSgd78059 * in address spaces 240-255. We have to emulate this behaviour. 2731*1c42de6dSgd78059 */ 2732*1c42de6dSgd78059 if ((mprog2.addr_space < 240) || (mprog2.addr_space > 255)) { 2733*1c42de6dSgd78059 return (EINVAL); 2734*1c42de6dSgd78059 } 2735*1c42de6dSgd78059 2736*1c42de6dSgd78059 bscv_enter(ssp); 2737*1c42de6dSgd78059 2738*1c42de6dSgd78059 /* Calculate required data location */ 2739*1c42de6dSgd78059 data_size = 255; 2740*1c42de6dSgd78059 base_addr = (mprog2.addr_space - 240) * data_size; 2741*1c42de6dSgd78059 2742*1c42de6dSgd78059 eeprom_size = bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) * 2743*1c42de6dSgd78059 1024; 2744*1c42de6dSgd78059 2745*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 2746*1c42de6dSgd78059 bscv_exit(ssp); 2747*1c42de6dSgd78059 return (EIO); 2748*1c42de6dSgd78059 } else if ((base_addr + data_size) > eeprom_size) { 2749*1c42de6dSgd78059 bscv_trace(ssp, 'M', "bscv_ioc_mprog2", 2750*1c42de6dSgd78059 "Request extends past end of eeprom"); 2751*1c42de6dSgd78059 bscv_exit(ssp); 2752*1c42de6dSgd78059 return (ENXIO); 2753*1c42de6dSgd78059 } 2754*1c42de6dSgd78059 2755*1c42de6dSgd78059 bscv_put8(ssp, chan_general, EBUS_IDX_CMD_RES, EBUS_CMD_UNLOCK1); 2756*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 2757*1c42de6dSgd78059 bscv_trace(ssp, 'M', "bscv_ioc_mprog2", "ML1 Write failed"); 2758*1c42de6dSgd78059 bscv_exit(ssp); 2759*1c42de6dSgd78059 return (EIO); 2760*1c42de6dSgd78059 } 2761*1c42de6dSgd78059 2762*1c42de6dSgd78059 bscv_put8(ssp, chan_general, EBUS_IDX_CMD_RES, EBUS_CMD_UNLOCK2); 2763*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 2764*1c42de6dSgd78059 bscv_trace(ssp, 'M', "bscv_ioc_mprog2", "ML2 Write failed"); 2765*1c42de6dSgd78059 bscv_exit(ssp); 2766*1c42de6dSgd78059 return (EIO); 2767*1c42de6dSgd78059 } 2768*1c42de6dSgd78059 2769*1c42de6dSgd78059 if (bscv_eerw(ssp, base_addr, &mprog2.data[0], 2770*1c42de6dSgd78059 data_size, B_TRUE /* write */) != 0) { 2771*1c42de6dSgd78059 res = EIO; 2772*1c42de6dSgd78059 } 2773*1c42de6dSgd78059 2774*1c42de6dSgd78059 /* Read a probe key to release the lock. */ 2775*1c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_PROBEAA); 2776*1c42de6dSgd78059 2777*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 2778*1c42de6dSgd78059 res = EIO; 2779*1c42de6dSgd78059 } 2780*1c42de6dSgd78059 bscv_exit(ssp); 2781*1c42de6dSgd78059 2782*1c42de6dSgd78059 return (res); 2783*1c42de6dSgd78059 } 2784*1c42de6dSgd78059 2785*1c42de6dSgd78059 /* 2786*1c42de6dSgd78059 * LOMIOCMREAD2 2787*1c42de6dSgd78059 */ 2788*1c42de6dSgd78059 static int 2789*1c42de6dSgd78059 bscv_ioc_mread2(bscv_soft_state_t *ssp, intptr_t arg, int mode) 2790*1c42de6dSgd78059 { 2791*1c42de6dSgd78059 lom2_mprog_t mprog2; 2792*1c42de6dSgd78059 uint32_t base_addr; 2793*1c42de6dSgd78059 uint32_t data_size; 2794*1c42de6dSgd78059 uint32_t eeprom_size; 2795*1c42de6dSgd78059 int res = 0; 2796*1c42de6dSgd78059 2797*1c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)&mprog2, sizeof (mprog2), 2798*1c42de6dSgd78059 mode) < 0) { 2799*1c42de6dSgd78059 return (EFAULT); 2800*1c42de6dSgd78059 } 2801*1c42de6dSgd78059 2802*1c42de6dSgd78059 /* 2803*1c42de6dSgd78059 * Need to stop the queue and then just read 2804*1c42de6dSgd78059 * the bytes blind to the relevant addresses. 2805*1c42de6dSgd78059 * Note that originally this was accessed as 255 byte pages 2806*1c42de6dSgd78059 * in address spaces 240-255. We have to emulate this behaviour. 2807*1c42de6dSgd78059 */ 2808*1c42de6dSgd78059 if ((mprog2.addr_space < 240) || (mprog2.addr_space > 255)) { 2809*1c42de6dSgd78059 return (EINVAL); 2810*1c42de6dSgd78059 } 2811*1c42de6dSgd78059 2812*1c42de6dSgd78059 bscv_enter(ssp); 2813*1c42de6dSgd78059 2814*1c42de6dSgd78059 /* Calculate required data location */ 2815*1c42de6dSgd78059 data_size = 255; 2816*1c42de6dSgd78059 base_addr = (mprog2.addr_space - 240) * data_size; 2817*1c42de6dSgd78059 eeprom_size = bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) * 2818*1c42de6dSgd78059 1024; 2819*1c42de6dSgd78059 2820*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 2821*1c42de6dSgd78059 bscv_exit(ssp); 2822*1c42de6dSgd78059 return (EIO); 2823*1c42de6dSgd78059 } else if ((base_addr + data_size) > eeprom_size) { 2824*1c42de6dSgd78059 bscv_trace(ssp, 'M', "bscv_ioc_mread2", 2825*1c42de6dSgd78059 "Request extends past end of eeprom"); 2826*1c42de6dSgd78059 bscv_exit(ssp); 2827*1c42de6dSgd78059 return (ENXIO); 2828*1c42de6dSgd78059 } 2829*1c42de6dSgd78059 2830*1c42de6dSgd78059 if (bscv_eerw(ssp, base_addr, &mprog2.data[0], 2831*1c42de6dSgd78059 data_size, B_FALSE /* read */) != 0) { 2832*1c42de6dSgd78059 res = EIO; 2833*1c42de6dSgd78059 } 2834*1c42de6dSgd78059 2835*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 2836*1c42de6dSgd78059 res = EIO; 2837*1c42de6dSgd78059 } 2838*1c42de6dSgd78059 bscv_exit(ssp); 2839*1c42de6dSgd78059 2840*1c42de6dSgd78059 if ((res == 0) && 2841*1c42de6dSgd78059 (ddi_copyout((caddr_t)&mprog2, (caddr_t)arg, sizeof (mprog2), 2842*1c42de6dSgd78059 mode) < 0)) { 2843*1c42de6dSgd78059 res = EFAULT; 2844*1c42de6dSgd78059 } 2845*1c42de6dSgd78059 return (res); 2846*1c42de6dSgd78059 } 2847*1c42de6dSgd78059 2848*1c42de6dSgd78059 static void 2849*1c42de6dSgd78059 bscv_get_state_changes(bscv_soft_state_t *ssp) 2850*1c42de6dSgd78059 { 2851*1c42de6dSgd78059 int i = STATUS_READ_LIMIT; 2852*1c42de6dSgd78059 uint8_t change; 2853*1c42de6dSgd78059 uint8_t detail; 2854*1c42de6dSgd78059 2855*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 2856*1c42de6dSgd78059 2857*1c42de6dSgd78059 while (i-- && !ssp->cssp_prog) { 2858*1c42de6dSgd78059 /* Are there any changes to process? */ 2859*1c42de6dSgd78059 change = bscv_get8(ssp, chan_general, EBUS_IDX_STATE_CHNG); 2860*1c42de6dSgd78059 change &= EBUS_STATE_MASK; 2861*1c42de6dSgd78059 if (!change) 2862*1c42de6dSgd78059 break; 2863*1c42de6dSgd78059 2864*1c42de6dSgd78059 /* Clarify the pending change */ 2865*1c42de6dSgd78059 detail = bscv_get8(ssp, chan_general, EBUS_IDX_EVENT_DETAIL); 2866*1c42de6dSgd78059 2867*1c42de6dSgd78059 bscv_status(ssp, change, detail); 2868*1c42de6dSgd78059 } 2869*1c42de6dSgd78059 2870*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_get_state_changes", 2871*1c42de6dSgd78059 "loop index %d ssp->cssp_prog 0x%x", i, ssp->cssp_prog); 2872*1c42de6dSgd78059 } 2873*1c42de6dSgd78059 2874*1c42de6dSgd78059 /* 2875*1c42de6dSgd78059 * ********************************************************************* 2876*1c42de6dSgd78059 * Event Processing 2877*1c42de6dSgd78059 * ********************************************************************* 2878*1c42de6dSgd78059 */ 2879*1c42de6dSgd78059 2880*1c42de6dSgd78059 /* 2881*1c42de6dSgd78059 * function - bscv_event_daemon 2882*1c42de6dSgd78059 * description - Perform periodic lom tasks in a separate thread. 2883*1c42de6dSgd78059 * inputs - LOM soft state structure pointer 2884*1c42de6dSgd78059 * outputs - none. 2885*1c42de6dSgd78059 */ 2886*1c42de6dSgd78059 static void 2887*1c42de6dSgd78059 bscv_event_daemon(void *arg) 2888*1c42de6dSgd78059 { 2889*1c42de6dSgd78059 bscv_soft_state_t *ssp = (void *)arg; 2890*1c42de6dSgd78059 boolean_t do_events; 2891*1c42de6dSgd78059 boolean_t do_status; 2892*1c42de6dSgd78059 boolean_t do_nodename; 2893*1c42de6dSgd78059 boolean_t do_watchdog; 2894*1c42de6dSgd78059 uint32_t async_reg; 2895*1c42de6dSgd78059 uint32_t fault; 2896*1c42de6dSgd78059 clock_t poll_period = BSC_EVENT_POLL_NORMAL; 2897*1c42de6dSgd78059 int fault_cnt = 0; 2898*1c42de6dSgd78059 2899*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_event_daemon", 2900*1c42de6dSgd78059 "bscv_event_daemon: started"); 2901*1c42de6dSgd78059 2902*1c42de6dSgd78059 /* Acquire task daemon lock. */ 2903*1c42de6dSgd78059 mutex_enter(&ssp->task_mu); 2904*1c42de6dSgd78059 2905*1c42de6dSgd78059 ssp->task_flags |= TASK_ALIVE_FLG; 2906*1c42de6dSgd78059 2907*1c42de6dSgd78059 for (;;) { 2908*1c42de6dSgd78059 if ((ssp->task_flags & TASK_STOP_FLG) != 0) { 2909*1c42de6dSgd78059 /* Stop request seen - terminate */ 2910*1c42de6dSgd78059 break; 2911*1c42de6dSgd78059 } 2912*1c42de6dSgd78059 if ((ssp->task_flags & TASK_PAUSE_FLG) == 0) { 2913*1c42de6dSgd78059 /* Poll for events reported to the nexus */ 2914*1c42de6dSgd78059 mutex_exit(&ssp->task_mu); 2915*1c42de6dSgd78059 /* Probe and Check faults */ 2916*1c42de6dSgd78059 bscv_enter(ssp); 2917*1c42de6dSgd78059 async_reg = bscv_probe(ssp, chan_general, &fault); 2918*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_event_daemon", 2919*1c42de6dSgd78059 "process event: async_reg 0x%x, fault 0x%x", 2920*1c42de6dSgd78059 async_reg, fault); 2921*1c42de6dSgd78059 2922*1c42de6dSgd78059 if (!fault) { 2923*1c42de6dSgd78059 /* Treat non-fault conditions */ 2924*1c42de6dSgd78059 2925*1c42de6dSgd78059 if (ssp->cssp_prog || ssp->prog_mode_only) { 2926*1c42de6dSgd78059 /* 2927*1c42de6dSgd78059 * The BSC has become available again. 2928*1c42de6dSgd78059 */ 2929*1c42de6dSgd78059 fault_cnt = 0; 2930*1c42de6dSgd78059 ssp->cssp_prog = B_FALSE; 2931*1c42de6dSgd78059 ssp->prog_mode_only = B_FALSE; 2932*1c42de6dSgd78059 (void) bscv_attach_common(ssp); 2933*1c42de6dSgd78059 } else if (fault_cnt > 0) { 2934*1c42de6dSgd78059 /* Previous fault has cleared */ 2935*1c42de6dSgd78059 bscv_clear_fault(ssp); 2936*1c42de6dSgd78059 fault_cnt = 0; 2937*1c42de6dSgd78059 cmn_err(CE_WARN, 2938*1c42de6dSgd78059 "!bscv_event_daemon previous fault " 2939*1c42de6dSgd78059 "cleared."); 2940*1c42de6dSgd78059 } else if (bscv_faulty(ssp)) { 2941*1c42de6dSgd78059 /* Previous fault has cleared */ 2942*1c42de6dSgd78059 bscv_clear_fault(ssp); 2943*1c42de6dSgd78059 /* Sleep to avoid busy waiting */ 2944*1c42de6dSgd78059 ssp->event_sleep = B_TRUE; 2945*1c42de6dSgd78059 } 2946*1c42de6dSgd78059 poll_period = BSC_EVENT_POLL_NORMAL; 2947*1c42de6dSgd78059 2948*1c42de6dSgd78059 if (async_reg) { 2949*1c42de6dSgd78059 ssp->status_change = B_TRUE; 2950*1c42de6dSgd78059 ssp->event_waiting = B_TRUE; 2951*1c42de6dSgd78059 } 2952*1c42de6dSgd78059 } else if (ssp->cssp_prog) { 2953*1c42de6dSgd78059 /* 2954*1c42de6dSgd78059 * Expect radio silence or error values 2955*1c42de6dSgd78059 * when the CSSP is upgrading the BSC firmware 2956*1c42de6dSgd78059 * so throw away any fault indication. 2957*1c42de6dSgd78059 */ 2958*1c42de6dSgd78059 fault = B_FALSE; 2959*1c42de6dSgd78059 } else if (fault_cnt == BSC_PROBE_FAULT_LIMIT) { 2960*1c42de6dSgd78059 /* Count previous faults and maybe fail */ 2961*1c42de6dSgd78059 /* Declare the lom broken */ 2962*1c42de6dSgd78059 bscv_set_fault(ssp); 2963*1c42de6dSgd78059 poll_period = BSC_EVENT_POLL_FAULTY; 2964*1c42de6dSgd78059 cmn_err(CE_WARN, 2965*1c42de6dSgd78059 "!bscv_event_daemon had faults probing " 2966*1c42de6dSgd78059 "lom - marking it as faulty."); 2967*1c42de6dSgd78059 /* 2968*1c42de6dSgd78059 * Increment fault_cnt to ensure that 2969*1c42de6dSgd78059 * next time we do not report a message 2970*1c42de6dSgd78059 * i.e. we drop out of the bottom 2971*1c42de6dSgd78059 */ 2972*1c42de6dSgd78059 fault_cnt = BSC_PROBE_FAULT_LIMIT + 1; 2973*1c42de6dSgd78059 ssp->event_sleep = B_TRUE; 2974*1c42de6dSgd78059 } else if (fault_cnt < BSC_PROBE_FAULT_LIMIT) { 2975*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 2976*1c42de6dSgd78059 poll_period = BSC_EVENT_POLL_FAULTY; 2977*1c42de6dSgd78059 /* 2978*1c42de6dSgd78059 * No recovery messages in this case 2979*1c42de6dSgd78059 * because there was never a fault 2980*1c42de6dSgd78059 * message here. 2981*1c42de6dSgd78059 */ 2982*1c42de6dSgd78059 fault_cnt = 0; 2983*1c42de6dSgd78059 } else { 2984*1c42de6dSgd78059 /* Getting ready to explode */ 2985*1c42de6dSgd78059 fault_cnt++; 2986*1c42de6dSgd78059 cmn_err(CE_WARN, 2987*1c42de6dSgd78059 "!bscv_event_daemon had fault 0x%x", 2988*1c42de6dSgd78059 fault); 2989*1c42de6dSgd78059 } 2990*1c42de6dSgd78059 ssp->event_sleep = B_TRUE; 2991*1c42de6dSgd78059 } 2992*1c42de6dSgd78059 bscv_exit(ssp); 2993*1c42de6dSgd78059 mutex_enter(&ssp->task_mu); 2994*1c42de6dSgd78059 } 2995*1c42de6dSgd78059 2996*1c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 2997*1c42de6dSgd78059 /* 2998*1c42de6dSgd78059 * we have no platmod hook on Solaris x86 to report 2999*1c42de6dSgd78059 * a change to the nodename so we keep a copy so 3000*1c42de6dSgd78059 * we can detect a change and request that the bsc 3001*1c42de6dSgd78059 * be updated when appropriate. 3002*1c42de6dSgd78059 */ 3003*1c42de6dSgd78059 if (strcmp(ssp->last_nodename, utsname.nodename) != 0) { 3004*1c42de6dSgd78059 3005*1c42de6dSgd78059 bscv_trace(ssp, 'X', "bscv_event_daemon", 3006*1c42de6dSgd78059 "utsname.nodename='%s' possible change detected", 3007*1c42de6dSgd78059 utsname.nodename); 3008*1c42de6dSgd78059 ssp->nodename_change = B_TRUE; 3009*1c42de6dSgd78059 (void) strncpy(ssp->last_nodename, utsname.nodename, 3010*1c42de6dSgd78059 sizeof (ssp->last_nodename)); 3011*1c42de6dSgd78059 /* enforce null termination */ 3012*1c42de6dSgd78059 ssp->last_nodename[sizeof (ssp->last_nodename) - 1] = 3013*1c42de6dSgd78059 '\0'; 3014*1c42de6dSgd78059 } 3015*1c42de6dSgd78059 #endif /* __i386 || __amd64 */ 3016*1c42de6dSgd78059 3017*1c42de6dSgd78059 if (((ssp->task_flags & TASK_PAUSE_FLG) == 0) && 3018*1c42de6dSgd78059 fault_cnt == 0 && ssp->cssp_prog == B_FALSE && 3019*1c42de6dSgd78059 (ssp->event_waiting || ssp->status_change || 3020*1c42de6dSgd78059 ssp->nodename_change || ssp->watchdog_change)) { 3021*1c42de6dSgd78059 3022*1c42de6dSgd78059 do_events = ssp->event_waiting; 3023*1c42de6dSgd78059 ssp->event_waiting = B_FALSE; 3024*1c42de6dSgd78059 ssp->task_flags |= do_events ? 3025*1c42de6dSgd78059 TASK_EVENT_PENDING_FLG : 0; 3026*1c42de6dSgd78059 do_status = ssp->status_change; 3027*1c42de6dSgd78059 ssp->status_change = B_FALSE; 3028*1c42de6dSgd78059 do_nodename = ssp->nodename_change; 3029*1c42de6dSgd78059 ssp->nodename_change = B_FALSE; 3030*1c42de6dSgd78059 do_watchdog = ssp->watchdog_change; 3031*1c42de6dSgd78059 if (ssp->watchdog_change) { 3032*1c42de6dSgd78059 ssp->watchdog_change = B_FALSE; 3033*1c42de6dSgd78059 } 3034*1c42de6dSgd78059 3035*1c42de6dSgd78059 mutex_exit(&ssp->task_mu); 3036*1c42de6dSgd78059 /* 3037*1c42de6dSgd78059 * We must not hold task_mu whilst processing 3038*1c42de6dSgd78059 * events because this can lead to priority 3039*1c42de6dSgd78059 * inversion and hence our interrupts getting 3040*1c42de6dSgd78059 * locked out. 3041*1c42de6dSgd78059 */ 3042*1c42de6dSgd78059 bscv_enter(ssp); 3043*1c42de6dSgd78059 if (do_events) { 3044*1c42de6dSgd78059 bscv_event_process(ssp, do_events); 3045*1c42de6dSgd78059 } 3046*1c42de6dSgd78059 if (do_nodename) { 3047*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_event_daemon", 3048*1c42de6dSgd78059 "do_nodename task"); 3049*1c42de6dSgd78059 bscv_setup_hostname(ssp); 3050*1c42de6dSgd78059 } 3051*1c42de6dSgd78059 if (do_watchdog) { 3052*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_event_daemon", 3053*1c42de6dSgd78059 "do_watchdog task"); 3054*1c42de6dSgd78059 bscv_setup_watchdog(ssp); 3055*1c42de6dSgd78059 } 3056*1c42de6dSgd78059 /* 3057*1c42de6dSgd78059 * Pending status changes are dealt with last because 3058*1c42de6dSgd78059 * if we see that the BSC is about to be programmed, 3059*1c42de6dSgd78059 * then it will expect us to to quiescent in the 3060*1c42de6dSgd78059 * first second so it can cleanly tear down its comms 3061*1c42de6dSgd78059 * protocols; this takes ~100 ms. 3062*1c42de6dSgd78059 */ 3063*1c42de6dSgd78059 if (do_status) { 3064*1c42de6dSgd78059 bscv_get_state_changes(ssp); 3065*1c42de6dSgd78059 } 3066*1c42de6dSgd78059 if (bscv_session_error(ssp)) { 3067*1c42de6dSgd78059 /* 3068*1c42de6dSgd78059 * Had fault during event session. We always 3069*1c42de6dSgd78059 * sleep after one of these because there 3070*1c42de6dSgd78059 * may be a problem with the lom which stops 3071*1c42de6dSgd78059 * us doing useful work in the event daemon. 3072*1c42de6dSgd78059 * If we don't sleep then we may livelock. 3073*1c42de6dSgd78059 */ 3074*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_event_daemon", 3075*1c42de6dSgd78059 "had session error - sleeping"); 3076*1c42de6dSgd78059 ssp->event_sleep = B_TRUE; 3077*1c42de6dSgd78059 } 3078*1c42de6dSgd78059 bscv_exit(ssp); 3079*1c42de6dSgd78059 3080*1c42de6dSgd78059 mutex_enter(&ssp->task_mu); 3081*1c42de6dSgd78059 3082*1c42de6dSgd78059 if (ssp->task_flags & TASK_EVENT_PENDING_FLG) { 3083*1c42de6dSgd78059 /* 3084*1c42de6dSgd78059 * We have read any events which were 3085*1c42de6dSgd78059 * pending. Let the consumer continue. 3086*1c42de6dSgd78059 * Ignore the race condition with new events 3087*1c42de6dSgd78059 * arriving - just let the consumer have 3088*1c42de6dSgd78059 * whatever was pending when they asked. 3089*1c42de6dSgd78059 */ 3090*1c42de6dSgd78059 ssp->event_active_count++; 3091*1c42de6dSgd78059 ssp->task_flags &= ~(TASK_EVENT_PENDING_FLG | 3092*1c42de6dSgd78059 TASK_EVENT_CONSUMER_FLG); 3093*1c42de6dSgd78059 cv_broadcast(&ssp->task_evnt_cv); 3094*1c42de6dSgd78059 } 3095*1c42de6dSgd78059 } else { 3096*1c42de6dSgd78059 /* There was nothing to do - sleep */ 3097*1c42de6dSgd78059 ssp->event_sleep = B_TRUE; 3098*1c42de6dSgd78059 } 3099*1c42de6dSgd78059 3100*1c42de6dSgd78059 if (ssp->event_sleep) { 3101*1c42de6dSgd78059 ssp->task_flags |= TASK_SLEEPING_FLG; 3102*1c42de6dSgd78059 /* Sleep until there is something to do */ 3103*1c42de6dSgd78059 (void) cv_timedwait(&ssp->task_cv, 3104*1c42de6dSgd78059 &ssp->task_mu, 3105*1c42de6dSgd78059 poll_period + ddi_get_lbolt()); 3106*1c42de6dSgd78059 ssp->task_flags &= ~TASK_SLEEPING_FLG; 3107*1c42de6dSgd78059 ssp->event_sleep = B_FALSE; 3108*1c42de6dSgd78059 } 3109*1c42de6dSgd78059 } 3110*1c42de6dSgd78059 3111*1c42de6dSgd78059 if (ssp->task_flags & TASK_EVENT_CONSUMER_FLG) { 3112*1c42de6dSgd78059 /* 3113*1c42de6dSgd78059 * We are going away so wake up any event consumer. 3114*1c42de6dSgd78059 * Pretend that any pending events have been processed. 3115*1c42de6dSgd78059 */ 3116*1c42de6dSgd78059 ssp->event_active_count += 2; 3117*1c42de6dSgd78059 cv_broadcast(&ssp->task_evnt_cv); 3118*1c42de6dSgd78059 } 3119*1c42de6dSgd78059 3120*1c42de6dSgd78059 ASSERT(!(ssp->task_flags & TASK_EVENT_PENDING_FLG)); 3121*1c42de6dSgd78059 ssp->task_flags &= 3122*1c42de6dSgd78059 ~(TASK_STOP_FLG | TASK_ALIVE_FLG | TASK_EVENT_CONSUMER_FLG); 3123*1c42de6dSgd78059 mutex_exit(&ssp->task_mu); 3124*1c42de6dSgd78059 3125*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_event_daemon", 3126*1c42de6dSgd78059 "exiting."); 3127*1c42de6dSgd78059 } 3128*1c42de6dSgd78059 3129*1c42de6dSgd78059 /* 3130*1c42de6dSgd78059 * function - bscv_start_event_daemon 3131*1c42de6dSgd78059 * description - Create the event daemon thread. 3132*1c42de6dSgd78059 * inputs - LOM soft state structure pointer 3133*1c42de6dSgd78059 * outputs - none 3134*1c42de6dSgd78059 */ 3135*1c42de6dSgd78059 static void 3136*1c42de6dSgd78059 bscv_start_event_daemon(bscv_soft_state_t *ssp) 3137*1c42de6dSgd78059 { 3138*1c42de6dSgd78059 if (ssp->progress & BSCV_THREAD) 3139*1c42de6dSgd78059 return; 3140*1c42de6dSgd78059 3141*1c42de6dSgd78059 /* Start the event thread after the queue has started */ 3142*1c42de6dSgd78059 (void) thread_create(NULL, 0, (void (*)())bscv_event_daemon, ssp, 3143*1c42de6dSgd78059 0, &p0, TS_RUN, minclsyspri); 3144*1c42de6dSgd78059 3145*1c42de6dSgd78059 ssp->progress |= BSCV_THREAD; 3146*1c42de6dSgd78059 } 3147*1c42de6dSgd78059 3148*1c42de6dSgd78059 /* 3149*1c42de6dSgd78059 * function - bscv_stop_event_daemon 3150*1c42de6dSgd78059 * description - Attempt to stop the event daemon thread. 3151*1c42de6dSgd78059 * inputs - LOM soft state structure pointer 3152*1c42de6dSgd78059 * outputs - DDI_SUCCESS OR DDI_FAILURE 3153*1c42de6dSgd78059 */ 3154*1c42de6dSgd78059 static int 3155*1c42de6dSgd78059 bscv_stop_event_daemon(bscv_soft_state_t *ssp) 3156*1c42de6dSgd78059 { 3157*1c42de6dSgd78059 int try; 3158*1c42de6dSgd78059 int res = DDI_SUCCESS; 3159*1c42de6dSgd78059 3160*1c42de6dSgd78059 mutex_enter(&ssp->task_mu); 3161*1c42de6dSgd78059 3162*1c42de6dSgd78059 /* Wait for task daemon to stop running. */ 3163*1c42de6dSgd78059 for (try = 0; 3164*1c42de6dSgd78059 ((ssp->task_flags & TASK_ALIVE_FLG) && try < 10); 3165*1c42de6dSgd78059 try++) { 3166*1c42de6dSgd78059 /* Signal that the task daemon should stop */ 3167*1c42de6dSgd78059 ssp->task_flags |= TASK_STOP_FLG; 3168*1c42de6dSgd78059 cv_signal(&ssp->task_cv); 3169*1c42de6dSgd78059 /* Release task daemon lock. */ 3170*1c42de6dSgd78059 mutex_exit(&ssp->task_mu); 3171*1c42de6dSgd78059 /* 3172*1c42de6dSgd78059 * TODO - when the driver is modified to support 3173*1c42de6dSgd78059 * system suspend or if this routine gets called 3174*1c42de6dSgd78059 * during panic we should use drv_usecwait() rather 3175*1c42de6dSgd78059 * than delay in those circumstances. 3176*1c42de6dSgd78059 */ 3177*1c42de6dSgd78059 delay(drv_usectohz(1000000)); 3178*1c42de6dSgd78059 mutex_enter(&ssp->task_mu); 3179*1c42de6dSgd78059 } 3180*1c42de6dSgd78059 3181*1c42de6dSgd78059 if (ssp->task_flags & TASK_ALIVE_FLG) { 3182*1c42de6dSgd78059 res = DDI_FAILURE; 3183*1c42de6dSgd78059 } 3184*1c42de6dSgd78059 mutex_exit(&ssp->task_mu); 3185*1c42de6dSgd78059 3186*1c42de6dSgd78059 return (res); 3187*1c42de6dSgd78059 } 3188*1c42de6dSgd78059 3189*1c42de6dSgd78059 /* 3190*1c42de6dSgd78059 * function - bscv_pause_event_daemon 3191*1c42de6dSgd78059 * description - Attempt to pause the event daemon thread. 3192*1c42de6dSgd78059 * inputs - LOM soft state structure pointer 3193*1c42de6dSgd78059 * outputs - DDI_SUCCESS OR DDI_FAILURE 3194*1c42de6dSgd78059 */ 3195*1c42de6dSgd78059 static int 3196*1c42de6dSgd78059 bscv_pause_event_daemon(bscv_soft_state_t *ssp) 3197*1c42de6dSgd78059 { 3198*1c42de6dSgd78059 int try; 3199*1c42de6dSgd78059 3200*1c42de6dSgd78059 if (!(ssp->progress & BSCV_THREAD)) { 3201*1c42de6dSgd78059 /* Nothing to do */ 3202*1c42de6dSgd78059 return (BSCV_SUCCESS); 3203*1c42de6dSgd78059 } 3204*1c42de6dSgd78059 3205*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_pause_event_daemon", 3206*1c42de6dSgd78059 "Attempting to pause event daemon"); 3207*1c42de6dSgd78059 3208*1c42de6dSgd78059 mutex_enter(&ssp->task_mu); 3209*1c42de6dSgd78059 /* Signal that the task daemon should pause */ 3210*1c42de6dSgd78059 ssp->task_flags |= TASK_PAUSE_FLG; 3211*1c42de6dSgd78059 3212*1c42de6dSgd78059 /* Wait for task daemon to pause. */ 3213*1c42de6dSgd78059 for (try = 0; 3214*1c42de6dSgd78059 (!(ssp->task_flags & TASK_SLEEPING_FLG) && 3215*1c42de6dSgd78059 (ssp->task_flags & TASK_ALIVE_FLG) && 3216*1c42de6dSgd78059 try < 10); 3217*1c42de6dSgd78059 try++) { 3218*1c42de6dSgd78059 /* Paranoia */ 3219*1c42de6dSgd78059 ssp->task_flags |= TASK_PAUSE_FLG; 3220*1c42de6dSgd78059 cv_signal(&ssp->task_cv); 3221*1c42de6dSgd78059 /* Release task daemon lock. */ 3222*1c42de6dSgd78059 mutex_exit(&ssp->task_mu); 3223*1c42de6dSgd78059 delay(drv_usectohz(1000000)); 3224*1c42de6dSgd78059 mutex_enter(&ssp->task_mu); 3225*1c42de6dSgd78059 } 3226*1c42de6dSgd78059 if ((ssp->task_flags & TASK_SLEEPING_FLG) || 3227*1c42de6dSgd78059 !(ssp->task_flags & TASK_ALIVE_FLG)) { 3228*1c42de6dSgd78059 mutex_exit(&ssp->task_mu); 3229*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_pause_event_daemon", 3230*1c42de6dSgd78059 "Pause event daemon - success"); 3231*1c42de6dSgd78059 return (BSCV_SUCCESS); 3232*1c42de6dSgd78059 } 3233*1c42de6dSgd78059 mutex_exit(&ssp->task_mu); 3234*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_pause_event_daemon", 3235*1c42de6dSgd78059 "Pause event daemon - failed"); 3236*1c42de6dSgd78059 return (BSCV_FAILURE); 3237*1c42de6dSgd78059 } 3238*1c42de6dSgd78059 3239*1c42de6dSgd78059 /* 3240*1c42de6dSgd78059 * function - bscv_resume_event_daemon 3241*1c42de6dSgd78059 * description - Resumethe event daemon thread. 3242*1c42de6dSgd78059 * inputs - LOM soft state structure pointer 3243*1c42de6dSgd78059 * outputs - None. 3244*1c42de6dSgd78059 */ 3245*1c42de6dSgd78059 static void 3246*1c42de6dSgd78059 bscv_resume_event_daemon(bscv_soft_state_t *ssp) 3247*1c42de6dSgd78059 { 3248*1c42de6dSgd78059 if (!(ssp->progress & BSCV_THREAD)) { 3249*1c42de6dSgd78059 /* Nothing to do */ 3250*1c42de6dSgd78059 return; 3251*1c42de6dSgd78059 } 3252*1c42de6dSgd78059 3253*1c42de6dSgd78059 mutex_enter(&ssp->task_mu); 3254*1c42de6dSgd78059 /* Allow the task daemon to resume event processing */ 3255*1c42de6dSgd78059 ssp->task_flags &= ~TASK_PAUSE_FLG; 3256*1c42de6dSgd78059 cv_signal(&ssp->task_cv); 3257*1c42de6dSgd78059 mutex_exit(&ssp->task_mu); 3258*1c42de6dSgd78059 3259*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_pause_event_daemon", 3260*1c42de6dSgd78059 "Event daemon resumed"); 3261*1c42de6dSgd78059 } 3262*1c42de6dSgd78059 3263*1c42de6dSgd78059 /* 3264*1c42de6dSgd78059 * function - bscv_event_process 3265*1c42de6dSgd78059 * description - process (report) events 3266*1c42de6dSgd78059 * inputs - Soft state ptr, process event request 3267*1c42de6dSgd78059 * outputs - none 3268*1c42de6dSgd78059 */ 3269*1c42de6dSgd78059 static void 3270*1c42de6dSgd78059 bscv_event_process(bscv_soft_state_t *ssp, boolean_t do_events) 3271*1c42de6dSgd78059 { 3272*1c42de6dSgd78059 uint32_t currptr; 3273*1c42de6dSgd78059 unsigned int count; 3274*1c42de6dSgd78059 3275*1c42de6dSgd78059 /* Raw values read from the lom */ 3276*1c42de6dSgd78059 uint8_t evcount; 3277*1c42de6dSgd78059 uint16_t logptr; 3278*1c42de6dSgd78059 3279*1c42de6dSgd78059 lom_event_t event; 3280*1c42de6dSgd78059 3281*1c42de6dSgd78059 if (do_events) { 3282*1c42de6dSgd78059 /* 3283*1c42de6dSgd78059 * Read count, next event ptr MSB,LSB. Note a read of count 3284*1c42de6dSgd78059 * latches values for the next event ptr 3285*1c42de6dSgd78059 */ 3286*1c42de6dSgd78059 evcount = bscv_get8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS); 3287*1c42de6dSgd78059 logptr = bscv_get16(ssp, chan_general, EBUS_IDX_LOG_PTR_HI); 3288*1c42de6dSgd78059 3289*1c42de6dSgd78059 /* Sanity check the values from the lom */ 3290*1c42de6dSgd78059 count = bscv_event_validate(ssp, logptr, evcount); 3291*1c42de6dSgd78059 3292*1c42de6dSgd78059 if (count == -1) { 3293*1c42de6dSgd78059 /* 3294*1c42de6dSgd78059 * Nothing to do - or badly configured event log. 3295*1c42de6dSgd78059 * We really do not want to touch the lom in this 3296*1c42de6dSgd78059 * case because any data that we access may be bad! 3297*1c42de6dSgd78059 * This differs from zero because if we have zero 3298*1c42de6dSgd78059 * to read the lom probably things that unread is 3299*1c42de6dSgd78059 * non-zero and we want that to be set to zero! 3300*1c42de6dSgd78059 * Signal event fault to make the thread wait 3301*1c42de6dSgd78059 * before attempting to re-read the log. 3302*1c42de6dSgd78059 */ 3303*1c42de6dSgd78059 ssp->event_sleep = B_TRUE; 3304*1c42de6dSgd78059 3305*1c42de6dSgd78059 goto logdone; 3306*1c42de6dSgd78059 } 3307*1c42de6dSgd78059 if (ssp->event_fault_reported) { 3308*1c42de6dSgd78059 /* Clear down any old status - things are fixed */ 3309*1c42de6dSgd78059 cmn_err(CE_NOTE, "Event pointer fault recovered."); 3310*1c42de6dSgd78059 ssp->event_fault_reported = B_FALSE; 3311*1c42de6dSgd78059 } 3312*1c42de6dSgd78059 3313*1c42de6dSgd78059 /* Compute the first entry that we need to read. */ 3314*1c42de6dSgd78059 currptr = logptr - ssp->eventlog_start; 3315*1c42de6dSgd78059 currptr += ssp->eventlog_size; 3316*1c42de6dSgd78059 currptr -= (count * sizeof (event)); 3317*1c42de6dSgd78059 currptr %= ssp->eventlog_size; 3318*1c42de6dSgd78059 currptr += ssp->eventlog_start; 3319*1c42de6dSgd78059 3320*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_event_process", 3321*1c42de6dSgd78059 "processing %d events from 0x%x in 0x%x:0x%x", 3322*1c42de6dSgd78059 count, currptr, 3323*1c42de6dSgd78059 ssp->eventlog_start, 3324*1c42de6dSgd78059 ssp->eventlog_start + ssp->eventlog_size); 3325*1c42de6dSgd78059 3326*1c42de6dSgd78059 for (; count > 0; count--) { 3327*1c42de6dSgd78059 /* Ensure window is positioned correctly */ 3328*1c42de6dSgd78059 if (bscv_eerw(ssp, currptr, (uint8_t *)&event, 3329*1c42de6dSgd78059 sizeof (event), B_FALSE /* read */) != 0) { 3330*1c42de6dSgd78059 /* Fault reading data - stop */ 3331*1c42de6dSgd78059 break; 3332*1c42de6dSgd78059 } 3333*1c42de6dSgd78059 3334*1c42de6dSgd78059 bscv_event_process_one(ssp, &event); 3335*1c42de6dSgd78059 bscv_sysevent(ssp, &event); 3336*1c42de6dSgd78059 3337*1c42de6dSgd78059 currptr += sizeof (event); 3338*1c42de6dSgd78059 if (currptr >= ssp->eventlog_start + 3339*1c42de6dSgd78059 ssp->eventlog_size) { 3340*1c42de6dSgd78059 currptr = ssp->eventlog_start; 3341*1c42de6dSgd78059 } 3342*1c42de6dSgd78059 } 3343*1c42de6dSgd78059 /* 3344*1c42de6dSgd78059 * Clear event count - write the evcount value to remove that 3345*1c42de6dSgd78059 * many from the unread total. 3346*1c42de6dSgd78059 * Adjust the value to reflect how many we have left to 3347*1c42de6dSgd78059 * read just in case we had a failure reading events. 3348*1c42de6dSgd78059 */ 3349*1c42de6dSgd78059 if (count == 0) { 3350*1c42de6dSgd78059 /*EMPTY*/ 3351*1c42de6dSgd78059 ASSERT(logptr == currptr); 3352*1c42de6dSgd78059 } else if (count > evcount) { 3353*1c42de6dSgd78059 evcount = 0; 3354*1c42de6dSgd78059 } else { 3355*1c42de6dSgd78059 evcount -= count; 3356*1c42de6dSgd78059 } 3357*1c42de6dSgd78059 bscv_put8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS, evcount); 3358*1c42de6dSgd78059 /* Remember where we were for next time */ 3359*1c42de6dSgd78059 ssp->oldeeptr = currptr; 3360*1c42de6dSgd78059 ssp->oldeeptr_valid = B_TRUE; 3361*1c42de6dSgd78059 logdone: 3362*1c42de6dSgd78059 ; 3363*1c42de6dSgd78059 } 3364*1c42de6dSgd78059 } 3365*1c42de6dSgd78059 3366*1c42de6dSgd78059 /* 3367*1c42de6dSgd78059 * function - bscv_event_validate 3368*1c42de6dSgd78059 * description - validate the event data supplied by the lom and determine 3369*1c42de6dSgd78059 * how many (if any) events to read. 3370*1c42de6dSgd78059 * This function performs complex checks to ensure that 3371*1c42de6dSgd78059 * events are not lost due to lom resets or host resets. 3372*1c42de6dSgd78059 * A combination of lom reset and host reset (i.e. power fail) 3373*1c42de6dSgd78059 * may cause some events to not be reported. 3374*1c42de6dSgd78059 * inputs - Soft state ptr, next event pointer, number of unread events. 3375*1c42de6dSgd78059 * outputs - the number of events to read. -1 on error. 3376*1c42de6dSgd78059 * zero is a valid value because it forces the loms unread 3377*1c42de6dSgd78059 * count to be cleared. 3378*1c42de6dSgd78059 */ 3379*1c42de6dSgd78059 static int 3380*1c42de6dSgd78059 bscv_event_validate(bscv_soft_state_t *ssp, uint32_t newptr, uint8_t unread) 3381*1c42de6dSgd78059 { 3382*1c42de6dSgd78059 uint32_t oldptr; 3383*1c42de6dSgd78059 unsigned int count; 3384*1c42de6dSgd78059 3385*1c42de6dSgd78059 if (!bscv_window_setup(ssp)) { 3386*1c42de6dSgd78059 /* Problem with lom eeprom setup we cannot do anything */ 3387*1c42de6dSgd78059 return (-1); 3388*1c42de6dSgd78059 } 3389*1c42de6dSgd78059 3390*1c42de6dSgd78059 /* Sanity check the event pointers */ 3391*1c42de6dSgd78059 if ((newptr < ssp->eventlog_start) || 3392*1c42de6dSgd78059 (newptr >= (ssp->eventlog_start + ssp->eventlog_size))) { 3393*1c42de6dSgd78059 if (!ssp->event_fault_reported) { 3394*1c42de6dSgd78059 cmn_err(CE_WARN, "Event pointer out of range. " 3395*1c42de6dSgd78059 "Cannot read events."); 3396*1c42de6dSgd78059 ssp->event_fault_reported = B_TRUE; 3397*1c42de6dSgd78059 } 3398*1c42de6dSgd78059 return (-1); 3399*1c42de6dSgd78059 } 3400*1c42de6dSgd78059 oldptr = ssp->oldeeptr; 3401*1c42de6dSgd78059 /* Now sanity check log pointer against count */ 3402*1c42de6dSgd78059 if (newptr < oldptr) { 3403*1c42de6dSgd78059 /* 3404*1c42de6dSgd78059 * Must have wrapped add eventlog_size to get the 3405*1c42de6dSgd78059 * correct relative values - this makes the checks 3406*1c42de6dSgd78059 * below work! 3407*1c42de6dSgd78059 */ 3408*1c42de6dSgd78059 newptr += ssp->eventlog_size; 3409*1c42de6dSgd78059 } 3410*1c42de6dSgd78059 if (!ssp->oldeeptr_valid) { 3411*1c42de6dSgd78059 /* We have just started up - we have to trust lom */ 3412*1c42de6dSgd78059 count = unread; 3413*1c42de6dSgd78059 } else if ((unread == 0) && (newptr == oldptr)) { 3414*1c42de6dSgd78059 /* Nothing to do - we were just polling */ 3415*1c42de6dSgd78059 return (-1); 3416*1c42de6dSgd78059 } else if (oldptr + (unread * sizeof (lom_event_t)) == newptr) { 3417*1c42de6dSgd78059 /* Ok - got as many events as we expected */ 3418*1c42de6dSgd78059 count = unread; 3419*1c42de6dSgd78059 } else if (oldptr + (unread * sizeof (lom_event_t)) > newptr) { 3420*1c42de6dSgd78059 /* 3421*1c42de6dSgd78059 * Errrm more messages than there should have been. 3422*1c42de6dSgd78059 * Possible causes: 3423*1c42de6dSgd78059 * 1. the event log has filled - we have been 3424*1c42de6dSgd78059 * away for a long time 3425*1c42de6dSgd78059 * 2. software bug in lom or driver. 3426*1c42de6dSgd78059 * 3. something that I haven't thought of! 3427*1c42de6dSgd78059 * Always warn about this we should really never 3428*1c42de6dSgd78059 * see it! 3429*1c42de6dSgd78059 */ 3430*1c42de6dSgd78059 count = (newptr - oldptr) / sizeof (lom_event_t); 3431*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_event_process", 3432*1c42de6dSgd78059 "bscv_event_process: lom reported " 3433*1c42de6dSgd78059 "more events (%d) than expected (%d).", 3434*1c42de6dSgd78059 unread, count); 3435*1c42de6dSgd78059 cmn_err(CE_CONT, "only processing %d events", count); 3436*1c42de6dSgd78059 } else { 3437*1c42de6dSgd78059 /* Less messages - perhaps the lom has been reset */ 3438*1c42de6dSgd78059 count = (newptr - oldptr) / sizeof (lom_event_t); 3439*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_event_process", 3440*1c42de6dSgd78059 "lom reported less events (%d) than expected (%d)" 3441*1c42de6dSgd78059 " - the lom may have been reset", 3442*1c42de6dSgd78059 unread, count); 3443*1c42de6dSgd78059 } 3444*1c42de6dSgd78059 /* Whatever happens only read a maximum of 255 entries */ 3445*1c42de6dSgd78059 if ((count >= 0xff)) { 3446*1c42de6dSgd78059 cmn_err(CE_WARN, 3447*1c42de6dSgd78059 "bscv_event_process: too many events (%d) to " 3448*1c42de6dSgd78059 "process - some may have been lost", count); 3449*1c42de6dSgd78059 count = 0xff; 3450*1c42de6dSgd78059 } 3451*1c42de6dSgd78059 return (count); 3452*1c42de6dSgd78059 } 3453*1c42de6dSgd78059 3454*1c42de6dSgd78059 /* 3455*1c42de6dSgd78059 * function - bscv_event_process_one 3456*1c42de6dSgd78059 * description - reports on state changes to the host. 3457*1c42de6dSgd78059 * 3458*1c42de6dSgd78059 * inputs - LOM soft state structure pointer. 3459*1c42de6dSgd78059 * 3460*1c42de6dSgd78059 * outputs - none. 3461*1c42de6dSgd78059 */ 3462*1c42de6dSgd78059 3463*1c42de6dSgd78059 static void 3464*1c42de6dSgd78059 bscv_event_process_one(bscv_soft_state_t *ssp, lom_event_t *event) 3465*1c42de6dSgd78059 { 3466*1c42de6dSgd78059 int level; 3467*1c42de6dSgd78059 char eventstr[100]; 3468*1c42de6dSgd78059 int msg_type = 0; 3469*1c42de6dSgd78059 3470*1c42de6dSgd78059 if (bscv_is_null_event(ssp, event)) { 3471*1c42de6dSgd78059 /* Cleared entry - do not report it */ 3472*1c42de6dSgd78059 return; 3473*1c42de6dSgd78059 } 3474*1c42de6dSgd78059 3475*1c42de6dSgd78059 level = bscv_level_of_event(event); 3476*1c42de6dSgd78059 3477*1c42de6dSgd78059 switch (level) { 3478*1c42de6dSgd78059 default: 3479*1c42de6dSgd78059 msg_type = CE_NOTE; 3480*1c42de6dSgd78059 break; 3481*1c42de6dSgd78059 3482*1c42de6dSgd78059 case EVENT_LEVEL_FATAL: 3483*1c42de6dSgd78059 case EVENT_LEVEL_FAULT: 3484*1c42de6dSgd78059 msg_type = CE_WARN; 3485*1c42de6dSgd78059 break; 3486*1c42de6dSgd78059 } 3487*1c42de6dSgd78059 3488*1c42de6dSgd78059 bscv_build_eventstring(ssp, event, eventstr, eventstr + 3489*1c42de6dSgd78059 sizeof (eventstr)); 3490*1c42de6dSgd78059 3491*1c42de6dSgd78059 if (level <= ssp->reporting_level) { 3492*1c42de6dSgd78059 /* 3493*1c42de6dSgd78059 * The message is important enough to be shown on the console 3494*1c42de6dSgd78059 * as well as the log. 3495*1c42de6dSgd78059 */ 3496*1c42de6dSgd78059 cmn_err(msg_type, "%s", eventstr); 3497*1c42de6dSgd78059 } else { 3498*1c42de6dSgd78059 /* 3499*1c42de6dSgd78059 * The message goes only to the log. 3500*1c42de6dSgd78059 */ 3501*1c42de6dSgd78059 cmn_err(msg_type, "!%s", eventstr); 3502*1c42de6dSgd78059 } 3503*1c42de6dSgd78059 } 3504*1c42de6dSgd78059 3505*1c42de6dSgd78059 /* 3506*1c42de6dSgd78059 * time formats 3507*1c42de6dSgd78059 * 3508*1c42de6dSgd78059 * The BSC represents times as seconds since epoch 1970. Currently it gives 3509*1c42de6dSgd78059 * us 32 bits, unsigned. In the future this might change to a 64-bit count, 3510*1c42de6dSgd78059 * to allow a greater range. 3511*1c42de6dSgd78059 * 3512*1c42de6dSgd78059 * Timestamp values below BSC_TIME_SANITY do not represent an absolute time, 3513*1c42de6dSgd78059 * but instead represent an offset from the last reset. This must be 3514*1c42de6dSgd78059 * borne in mind by output routines. 3515*1c42de6dSgd78059 */ 3516*1c42de6dSgd78059 3517*1c42de6dSgd78059 typedef uint32_t bsctime_t; 3518*1c42de6dSgd78059 3519*1c42de6dSgd78059 #define BSC_TIME_SANITY 1000000000 3520*1c42de6dSgd78059 3521*1c42de6dSgd78059 /* 3522*1c42de6dSgd78059 * render a formatted time for display 3523*1c42de6dSgd78059 */ 3524*1c42de6dSgd78059 3525*1c42de6dSgd78059 static size_t 3526*1c42de6dSgd78059 bscv_event_snprintgmttime(char *buf, size_t bufsz, todinfo_t t) 3527*1c42de6dSgd78059 { 3528*1c42de6dSgd78059 int year; 3529*1c42de6dSgd78059 3530*1c42de6dSgd78059 /* tod_year is base 1900 so this code needs to adjust */ 3531*1c42de6dSgd78059 year = 1900 + t.tod_year; 3532*1c42de6dSgd78059 3533*1c42de6dSgd78059 return (snprintf(buf, bufsz, "%04d-%02d-%02d %02d:%02d:%02dZ", 3534*1c42de6dSgd78059 year, t.tod_month, t.tod_day, t.tod_hour, 3535*1c42de6dSgd78059 t.tod_min, t.tod_sec)); 3536*1c42de6dSgd78059 } 3537*1c42de6dSgd78059 3538*1c42de6dSgd78059 /* 3539*1c42de6dSgd78059 * function - bscv_build_eventstring 3540*1c42de6dSgd78059 * description - reports on state changes to the host. 3541*1c42de6dSgd78059 * 3542*1c42de6dSgd78059 * inputs - LOM soft state structure pointer. 3543*1c42de6dSgd78059 * 3544*1c42de6dSgd78059 * outputs - none. 3545*1c42de6dSgd78059 */ 3546*1c42de6dSgd78059 3547*1c42de6dSgd78059 static void 3548*1c42de6dSgd78059 bscv_build_eventstring(bscv_soft_state_t *ssp, lom_event_t *event, 3549*1c42de6dSgd78059 char *buf, char *bufend) 3550*1c42de6dSgd78059 { 3551*1c42de6dSgd78059 uint8_t subsystem; 3552*1c42de6dSgd78059 uint8_t eventtype; 3553*1c42de6dSgd78059 bsctime_t bsctm; 3554*1c42de6dSgd78059 3555*1c42de6dSgd78059 bscv_trace(ssp, 'S', "bscv_build_eventstring", "event %2x%2x%2x%2x", 3556*1c42de6dSgd78059 event->ev_subsys, event->ev_event, 3557*1c42de6dSgd78059 event->ev_resource, event->ev_detail); 3558*1c42de6dSgd78059 bscv_trace(ssp, 'S', "bscv_build_eventstring", "time %2x%2x%2x%2x", 3559*1c42de6dSgd78059 event->ev_data[0], event->ev_data[1], 3560*1c42de6dSgd78059 event->ev_data[2], event->ev_data[3]); 3561*1c42de6dSgd78059 3562*1c42de6dSgd78059 /* 3563*1c42de6dSgd78059 * We accept bad subsystems and event type codes here. 3564*1c42de6dSgd78059 * The code decodes as much as possible and then produces 3565*1c42de6dSgd78059 * suitable output. 3566*1c42de6dSgd78059 */ 3567*1c42de6dSgd78059 subsystem = EVENT_DECODE_SUBSYS(event->ev_subsys); 3568*1c42de6dSgd78059 eventtype = event->ev_event; 3569*1c42de6dSgd78059 3570*1c42de6dSgd78059 /* time */ 3571*1c42de6dSgd78059 bsctm = (((uint32_t)event->ev_data[0]) << 24) | 3572*1c42de6dSgd78059 (((uint32_t)event->ev_data[1]) << 16) | 3573*1c42de6dSgd78059 (((uint32_t)event->ev_data[2]) << 8) | 3574*1c42de6dSgd78059 ((uint32_t)event->ev_data[3]); 3575*1c42de6dSgd78059 if (bsctm < BSC_TIME_SANITY) { 3576*1c42de6dSgd78059 /* offset */ 3577*1c42de6dSgd78059 buf += snprintf(buf, bufend-buf, "+P%dd%02dh%02dm%02ds", 3578*1c42de6dSgd78059 (int)(bsctm/86400), (int)(bsctm/3600%24), 3579*1c42de6dSgd78059 (int)(bsctm/60%60), (int)(bsctm%60)); 3580*1c42de6dSgd78059 } else { 3581*1c42de6dSgd78059 /* absolute time */ 3582*1c42de6dSgd78059 mutex_enter(&tod_lock); 3583*1c42de6dSgd78059 buf += bscv_event_snprintgmttime(buf, bufend-buf, 3584*1c42de6dSgd78059 utc_to_tod(bsctm)); 3585*1c42de6dSgd78059 mutex_exit(&tod_lock); 3586*1c42de6dSgd78059 } 3587*1c42de6dSgd78059 buf += snprintf(buf, bufend-buf, " "); 3588*1c42de6dSgd78059 3589*1c42de6dSgd78059 /* subsysp */ 3590*1c42de6dSgd78059 if (subsystem < 3591*1c42de6dSgd78059 (sizeof (eventSubsysStrings)/sizeof (*eventSubsysStrings))) { 3592*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "%s", 3593*1c42de6dSgd78059 eventSubsysStrings[subsystem]); 3594*1c42de6dSgd78059 } else { 3595*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3596*1c42de6dSgd78059 "unknown subsystem %d ", subsystem); 3597*1c42de6dSgd78059 } 3598*1c42de6dSgd78059 3599*1c42de6dSgd78059 /* resource */ 3600*1c42de6dSgd78059 switch (subsystem) { 3601*1c42de6dSgd78059 case EVENT_SUBSYS_ALARM: 3602*1c42de6dSgd78059 case EVENT_SUBSYS_TEMP: 3603*1c42de6dSgd78059 case EVENT_SUBSYS_OVERTEMP: 3604*1c42de6dSgd78059 case EVENT_SUBSYS_FAN: 3605*1c42de6dSgd78059 case EVENT_SUBSYS_SUPPLY: 3606*1c42de6dSgd78059 case EVENT_SUBSYS_BREAKER: 3607*1c42de6dSgd78059 case EVENT_SUBSYS_PSU: 3608*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "%d ", event->ev_resource); 3609*1c42de6dSgd78059 break; 3610*1c42de6dSgd78059 case EVENT_SUBSYS_LED: 3611*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "%s ", bscv_get_label( 3612*1c42de6dSgd78059 ssp->led_names, MAX_LED_ID, event->ev_resource - 1)); 3613*1c42de6dSgd78059 break; 3614*1c42de6dSgd78059 default: 3615*1c42de6dSgd78059 break; 3616*1c42de6dSgd78059 } 3617*1c42de6dSgd78059 3618*1c42de6dSgd78059 /* fatal */ 3619*1c42de6dSgd78059 if (event->ev_subsys & EVENT_MASK_FAULT) { 3620*1c42de6dSgd78059 if (event->ev_subsys & EVENT_MASK_FATAL) { 3621*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "FATAL FAULT: "); 3622*1c42de6dSgd78059 } else { 3623*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "FAULT: "); 3624*1c42de6dSgd78059 } 3625*1c42de6dSgd78059 } 3626*1c42de6dSgd78059 3627*1c42de6dSgd78059 /* eventp */ 3628*1c42de6dSgd78059 if (eventtype < 3629*1c42de6dSgd78059 (sizeof (eventTypeStrings)/sizeof (*eventTypeStrings))) { 3630*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "%s", 3631*1c42de6dSgd78059 eventTypeStrings[eventtype]); 3632*1c42de6dSgd78059 } else { 3633*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3634*1c42de6dSgd78059 "unknown event 0x%02x%02x%02x%02x", 3635*1c42de6dSgd78059 event->ev_subsys, event->ev_event, 3636*1c42de6dSgd78059 event->ev_resource, event->ev_detail); 3637*1c42de6dSgd78059 } 3638*1c42de6dSgd78059 3639*1c42de6dSgd78059 /* detail */ 3640*1c42de6dSgd78059 switch (subsystem) { 3641*1c42de6dSgd78059 case EVENT_SUBSYS_TEMP: 3642*1c42de6dSgd78059 if ((eventtype != EVENT_RECOVERED) && 3643*1c42de6dSgd78059 eventtype != EVENT_DEVICE_INACCESSIBLE) { 3644*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - %d degC", 3645*1c42de6dSgd78059 (int8_t)event->ev_detail); 3646*1c42de6dSgd78059 } 3647*1c42de6dSgd78059 break; 3648*1c42de6dSgd78059 case EVENT_SUBSYS_FAN: 3649*1c42de6dSgd78059 if (eventtype == EVENT_FAILED) { 3650*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3651*1c42de6dSgd78059 " %d%%", event->ev_detail); 3652*1c42de6dSgd78059 } 3653*1c42de6dSgd78059 break; 3654*1c42de6dSgd78059 case EVENT_SUBSYS_LOM: 3655*1c42de6dSgd78059 switch (eventtype) { 3656*1c42de6dSgd78059 case EVENT_FLASH_DOWNLOAD: 3657*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3658*1c42de6dSgd78059 ": v%d.%d to v%d.%d", 3659*1c42de6dSgd78059 (event->ev_resource >> 4), 3660*1c42de6dSgd78059 (event->ev_resource & 0x0f), 3661*1c42de6dSgd78059 (event->ev_detail >> 4), 3662*1c42de6dSgd78059 (event->ev_detail & 0x0f)); 3663*1c42de6dSgd78059 break; 3664*1c42de6dSgd78059 case EVENT_WATCHDOG_TRIGGER: 3665*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3666*1c42de6dSgd78059 event->ev_detail ? "- soft" : " - hard"); 3667*1c42de6dSgd78059 break; 3668*1c42de6dSgd78059 case EVENT_UNEXPECTED_RESET: 3669*1c42de6dSgd78059 if (event->ev_detail & 3670*1c42de6dSgd78059 LOM_UNEXPECTEDRESET_MASK_BADTRAP) { 3671*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3672*1c42de6dSgd78059 " - unclaimed exception 0x%x", 3673*1c42de6dSgd78059 event->ev_detail & 3674*1c42de6dSgd78059 ~LOM_UNEXPECTEDRESET_MASK_BADTRAP); 3675*1c42de6dSgd78059 } 3676*1c42de6dSgd78059 break; 3677*1c42de6dSgd78059 case EVENT_RESET: 3678*1c42de6dSgd78059 switch (event->ev_detail) { 3679*1c42de6dSgd78059 case LOM_RESET_DETAIL_BYUSER: 3680*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " by user"); 3681*1c42de6dSgd78059 break; 3682*1c42de6dSgd78059 case LOM_RESET_DETAIL_REPROGRAMMING: 3683*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3684*1c42de6dSgd78059 " after flash download"); 3685*1c42de6dSgd78059 break; 3686*1c42de6dSgd78059 default: 3687*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3688*1c42de6dSgd78059 " - unknown reason"); 3689*1c42de6dSgd78059 break; 3690*1c42de6dSgd78059 } 3691*1c42de6dSgd78059 break; 3692*1c42de6dSgd78059 default: 3693*1c42de6dSgd78059 break; 3694*1c42de6dSgd78059 } 3695*1c42de6dSgd78059 break; 3696*1c42de6dSgd78059 case EVENT_SUBSYS_LED: 3697*1c42de6dSgd78059 switch (event->ev_detail) { 3698*1c42de6dSgd78059 case LOM_LED_STATE_OFF: 3699*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": OFF"); 3700*1c42de6dSgd78059 break; 3701*1c42de6dSgd78059 case LOM_LED_STATE_ON_STEADY: 3702*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": ON"); 3703*1c42de6dSgd78059 break; 3704*1c42de6dSgd78059 case LOM_LED_STATE_ON_FLASHING: 3705*1c42de6dSgd78059 case LOM_LED_STATE_ON_SLOWFLASH: 3706*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": BLINKING"); 3707*1c42de6dSgd78059 break; 3708*1c42de6dSgd78059 case LOM_LED_STATE_INACCESSIBLE: 3709*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": inaccessible"); 3710*1c42de6dSgd78059 break; 3711*1c42de6dSgd78059 case LOM_LED_STATE_STANDBY: 3712*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": standby"); 3713*1c42de6dSgd78059 break; 3714*1c42de6dSgd78059 case LOM_LED_STATE_NOT_PRESENT: 3715*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": not present"); 3716*1c42de6dSgd78059 break; 3717*1c42de6dSgd78059 default: 3718*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": 0x%x", 3719*1c42de6dSgd78059 event->ev_resource); 3720*1c42de6dSgd78059 break; 3721*1c42de6dSgd78059 } 3722*1c42de6dSgd78059 break; 3723*1c42de6dSgd78059 case EVENT_SUBSYS_USER: 3724*1c42de6dSgd78059 switch (eventtype) { 3725*1c42de6dSgd78059 case EVENT_USER_ADDED: 3726*1c42de6dSgd78059 case EVENT_USER_REMOVED: 3727*1c42de6dSgd78059 case EVENT_USER_PERMSCHANGED: 3728*1c42de6dSgd78059 case EVENT_USER_LOGIN: 3729*1c42de6dSgd78059 case EVENT_USER_PASSWORD_CHANGE: 3730*1c42de6dSgd78059 case EVENT_USER_LOGINFAIL: 3731*1c42de6dSgd78059 case EVENT_USER_LOGOUT: 3732*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " %d", 3733*1c42de6dSgd78059 event->ev_resource); 3734*1c42de6dSgd78059 default: 3735*1c42de6dSgd78059 break; 3736*1c42de6dSgd78059 } 3737*1c42de6dSgd78059 break; 3738*1c42de6dSgd78059 case EVENT_SUBSYS_PSU: 3739*1c42de6dSgd78059 if (event->ev_detail & LOM_PSU_NOACCESS) { 3740*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - inaccessible"); 3741*1c42de6dSgd78059 } else if ((event->ev_detail & LOM_PSU_STATUS_MASK) 3742*1c42de6dSgd78059 == LOM_PSU_STATUS_MASK) { 3743*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - OK"); 3744*1c42de6dSgd78059 } else { 3745*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " -"); 3746*1c42de6dSgd78059 /* 3747*1c42de6dSgd78059 * If both inputs are seen to have failed then simply 3748*1c42de6dSgd78059 * indicate that the PSU input has failed 3749*1c42de6dSgd78059 */ 3750*1c42de6dSgd78059 if (!(event->ev_detail & 3751*1c42de6dSgd78059 (LOM_PSU_INPUT_A_OK | LOM_PSU_INPUT_B_OK))) { 3752*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " Input"); 3753*1c42de6dSgd78059 } else { 3754*1c42de6dSgd78059 /* At least one input is ok */ 3755*1c42de6dSgd78059 if (!(event->ev_detail & LOM_PSU_INPUT_A_OK)) { 3756*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3757*1c42de6dSgd78059 " InA"); 3758*1c42de6dSgd78059 } 3759*1c42de6dSgd78059 if (!(event->ev_detail & LOM_PSU_INPUT_B_OK)) { 3760*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3761*1c42de6dSgd78059 " InB"); 3762*1c42de6dSgd78059 } 3763*1c42de6dSgd78059 /* 3764*1c42de6dSgd78059 * Only flag an output error if an input is 3765*1c42de6dSgd78059 * still present 3766*1c42de6dSgd78059 */ 3767*1c42de6dSgd78059 if (!(event->ev_detail & LOM_PSU_OUTPUT_OK)) { 3768*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3769*1c42de6dSgd78059 " Output"); 3770*1c42de6dSgd78059 } 3771*1c42de6dSgd78059 } 3772*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " failed"); 3773*1c42de6dSgd78059 } 3774*1c42de6dSgd78059 break; 3775*1c42de6dSgd78059 case EVENT_SUBSYS_NONE: 3776*1c42de6dSgd78059 if (eventtype == EVENT_FAULT_LED) { 3777*1c42de6dSgd78059 switch (event->ev_detail) { 3778*1c42de6dSgd78059 case 0: 3779*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - ON"); 3780*1c42de6dSgd78059 break; 3781*1c42de6dSgd78059 case 255: 3782*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - OFF"); 3783*1c42de6dSgd78059 break; 3784*1c42de6dSgd78059 default: 3785*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3786*1c42de6dSgd78059 " - %dHz", event->ev_detail); 3787*1c42de6dSgd78059 break; 3788*1c42de6dSgd78059 } 3789*1c42de6dSgd78059 } 3790*1c42de6dSgd78059 break; 3791*1c42de6dSgd78059 case EVENT_SUBSYS_HOST: 3792*1c42de6dSgd78059 if (eventtype == EVENT_BOOTMODE_CHANGE) { 3793*1c42de6dSgd78059 switch (event->ev_detail & 3794*1c42de6dSgd78059 ~EBUS_BOOTMODE_FORCE_CONSOLE) { 3795*1c42de6dSgd78059 case EBUS_BOOTMODE_FORCE_NOBOOT: 3796*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3797*1c42de6dSgd78059 " - no boot"); 3798*1c42de6dSgd78059 break; 3799*1c42de6dSgd78059 case EBUS_BOOTMODE_RESET_DEFAULT: 3800*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3801*1c42de6dSgd78059 " - reset defaults"); 3802*1c42de6dSgd78059 break; 3803*1c42de6dSgd78059 case EBUS_BOOTMODE_FULLDIAG: 3804*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3805*1c42de6dSgd78059 " - full diag"); 3806*1c42de6dSgd78059 break; 3807*1c42de6dSgd78059 case EBUS_BOOTMODE_SKIPDIAG: 3808*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3809*1c42de6dSgd78059 " - skip diag"); 3810*1c42de6dSgd78059 break; 3811*1c42de6dSgd78059 default: 3812*1c42de6dSgd78059 break; 3813*1c42de6dSgd78059 } 3814*1c42de6dSgd78059 } 3815*1c42de6dSgd78059 if (eventtype == EVENT_SCC_STATUS) { 3816*1c42de6dSgd78059 switch (event->ev_detail) { 3817*1c42de6dSgd78059 case 0: 3818*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3819*1c42de6dSgd78059 " - inserted"); 3820*1c42de6dSgd78059 break; 3821*1c42de6dSgd78059 case 1: 3822*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 3823*1c42de6dSgd78059 " - removed"); 3824*1c42de6dSgd78059 break; 3825*1c42de6dSgd78059 default: 3826*1c42de6dSgd78059 break; 3827*1c42de6dSgd78059 } 3828*1c42de6dSgd78059 } 3829*1c42de6dSgd78059 break; 3830*1c42de6dSgd78059 3831*1c42de6dSgd78059 default: 3832*1c42de6dSgd78059 break; 3833*1c42de6dSgd78059 } 3834*1c42de6dSgd78059 3835*1c42de6dSgd78059 /* shutd */ 3836*1c42de6dSgd78059 if (event->ev_subsys & EVENT_MASK_SHUTDOWN_REQD) { 3837*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - shutdown req'd"); 3838*1c42de6dSgd78059 } 3839*1c42de6dSgd78059 3840*1c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "\n"); 3841*1c42de6dSgd78059 3842*1c42de6dSgd78059 if (buf >= bufend) { 3843*1c42de6dSgd78059 /* Ensure newline at end of string */ 3844*1c42de6dSgd78059 bufend[-2] = '\n'; 3845*1c42de6dSgd78059 bufend[-1] = '\0'; 3846*1c42de6dSgd78059 #ifdef DEBUG 3847*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_build_eventstring: buffer too small!"); 3848*1c42de6dSgd78059 #endif /* DEBUG */ 3849*1c42de6dSgd78059 } 3850*1c42de6dSgd78059 } 3851*1c42de6dSgd78059 3852*1c42de6dSgd78059 /* 3853*1c42de6dSgd78059 * function - bscv_level_of_event 3854*1c42de6dSgd78059 * description - This routine determines which level an event should be 3855*1c42de6dSgd78059 * reported at. 3856*1c42de6dSgd78059 * inputs - lom event structure pointer 3857*1c42de6dSgd78059 * outputs - event level. 3858*1c42de6dSgd78059 */ 3859*1c42de6dSgd78059 static int 3860*1c42de6dSgd78059 bscv_level_of_event(lom_event_t *event) 3861*1c42de6dSgd78059 { 3862*1c42de6dSgd78059 int level; 3863*1c42de6dSgd78059 /* 3864*1c42de6dSgd78059 * This is the same criteria that the firmware uses except we 3865*1c42de6dSgd78059 * log the fault led on as being EVENT_LEVEL_FAULT 3866*1c42de6dSgd78059 */ 3867*1c42de6dSgd78059 if (EVENT_DECODE_SUBSYS(event->ev_subsys) == EVENT_SUBSYS_USER) { 3868*1c42de6dSgd78059 level = EVENT_LEVEL_USER; 3869*1c42de6dSgd78059 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) == 3870*1c42de6dSgd78059 EVENT_SUBSYS_ALARM) && (event->ev_event == EVENT_STATE_ON)) { 3871*1c42de6dSgd78059 level = EVENT_LEVEL_FAULT; 3872*1c42de6dSgd78059 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) == 3873*1c42de6dSgd78059 EVENT_SUBSYS_NONE) && 3874*1c42de6dSgd78059 (event->ev_event == EVENT_FAULT_LED) && 3875*1c42de6dSgd78059 (event->ev_detail != 0xff)) { 3876*1c42de6dSgd78059 level = EVENT_LEVEL_FAULT; 3877*1c42de6dSgd78059 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) == 3878*1c42de6dSgd78059 EVENT_SUBSYS_LOM) && event->ev_event == EVENT_TIME_REFERENCE) { 3879*1c42de6dSgd78059 level = EVENT_LEVEL_NOTICE; 3880*1c42de6dSgd78059 } else if (event->ev_event == EVENT_RECOVERED) { 3881*1c42de6dSgd78059 /* 3882*1c42de6dSgd78059 * All recovery messages need to be reported to the console 3883*1c42de6dSgd78059 * because during boot, the faults which occurred whilst 3884*1c42de6dSgd78059 * Solaris was not running are relayed to the console. There 3885*1c42de6dSgd78059 * is a case whereby a fatal fault (eg. over temp) could 3886*1c42de6dSgd78059 * have occurred and then recovered. The recovery condition 3887*1c42de6dSgd78059 * needs to be reported so the user doesn't think that the 3888*1c42de6dSgd78059 * failure (over temp) is still present. 3889*1c42de6dSgd78059 */ 3890*1c42de6dSgd78059 level = EVENT_LEVEL_FAULT; 3891*1c42de6dSgd78059 } else if (EVENT_DECODE_FAULT(event->ev_subsys) == 0) { 3892*1c42de6dSgd78059 /* None of FAULT, FATAL or SHUTDOWN REQD are set */ 3893*1c42de6dSgd78059 level = EVENT_LEVEL_NOTICE; 3894*1c42de6dSgd78059 } else if (EVENT_DECODE_FAULT(event->ev_subsys) == EVENT_MASK_FAULT) { 3895*1c42de6dSgd78059 /* Only FAULT set i.e not FATAL or SHUTDOWN REQD */ 3896*1c42de6dSgd78059 level = EVENT_LEVEL_FAULT; 3897*1c42de6dSgd78059 } else { 3898*1c42de6dSgd78059 level = EVENT_LEVEL_FATAL; 3899*1c42de6dSgd78059 } 3900*1c42de6dSgd78059 3901*1c42de6dSgd78059 return (level); 3902*1c42de6dSgd78059 } 3903*1c42de6dSgd78059 3904*1c42de6dSgd78059 /* 3905*1c42de6dSgd78059 * function - bscv_status 3906*1c42de6dSgd78059 * description - This routine is called when any change in the LOMlite2 status 3907*1c42de6dSgd78059 * is indicated by the status registers. 3908*1c42de6dSgd78059 * 3909*1c42de6dSgd78059 * inputs - LOM soft state structure pointer 3910*1c42de6dSgd78059 * 3911*1c42de6dSgd78059 * outputs - none. 3912*1c42de6dSgd78059 */ 3913*1c42de6dSgd78059 static void 3914*1c42de6dSgd78059 bscv_status(bscv_soft_state_t *ssp, uint8_t state_chng, uint8_t dev_no) 3915*1c42de6dSgd78059 { 3916*1c42de6dSgd78059 int8_t temp; 3917*1c42de6dSgd78059 uint8_t fanspeed; 3918*1c42de6dSgd78059 3919*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 3920*1c42de6dSgd78059 3921*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_status", "state_chng 0x%x dev_no 0x%x", 3922*1c42de6dSgd78059 state_chng, dev_no); 3923*1c42de6dSgd78059 3924*1c42de6dSgd78059 /* 3925*1c42de6dSgd78059 * The device that has changed is given by the state change 3926*1c42de6dSgd78059 * register and the event detail register so react 3927*1c42de6dSgd78059 * accordingly. 3928*1c42de6dSgd78059 */ 3929*1c42de6dSgd78059 3930*1c42de6dSgd78059 if (state_chng == EBUS_STATE_NOTIFY) { 3931*1c42de6dSgd78059 /* 3932*1c42de6dSgd78059 * The BSC is indicating a self state change 3933*1c42de6dSgd78059 */ 3934*1c42de6dSgd78059 if (dev_no == EBUS_DETAIL_FLASH) { 3935*1c42de6dSgd78059 ssp->cssp_prog = B_TRUE; 3936*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_status", 3937*1c42de6dSgd78059 "ssp->cssp_prog changed to 0x%x", 3938*1c42de6dSgd78059 ssp->cssp_prog); 3939*1c42de6dSgd78059 /* 3940*1c42de6dSgd78059 * It takes the BSC at least 100 ms to 3941*1c42de6dSgd78059 * clear down the comms protocol. 3942*1c42de6dSgd78059 * We back-off from talking to the 3943*1c42de6dSgd78059 * BSC during this period. 3944*1c42de6dSgd78059 */ 3945*1c42de6dSgd78059 delay(BSC_EVENT_POLL_NORMAL); 3946*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_status", 3947*1c42de6dSgd78059 "completed delay"); 3948*1c42de6dSgd78059 } else if (dev_no == EBUS_DETAIL_RESET) { 3949*1c42de6dSgd78059 /* 3950*1c42de6dSgd78059 * The bsc has reset 3951*1c42de6dSgd78059 */ 3952*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_status", 3953*1c42de6dSgd78059 "BSC reset occured, re-synching"); 3954*1c42de6dSgd78059 (void) bscv_attach_common(ssp); 3955*1c42de6dSgd78059 bscv_trace(ssp, 'D', "bscv_status", 3956*1c42de6dSgd78059 "completed attach_common"); 3957*1c42de6dSgd78059 } 3958*1c42de6dSgd78059 3959*1c42de6dSgd78059 } 3960*1c42de6dSgd78059 3961*1c42de6dSgd78059 if ((state_chng & EBUS_STATE_FAN) && ((dev_no - 1) < MAX_FANS)) { 3962*1c42de6dSgd78059 fanspeed = bscv_get8(ssp, chan_general, 3963*1c42de6dSgd78059 EBUS_IDX_FAN1_SPEED + dev_no - 1); 3964*1c42de6dSgd78059 /* 3965*1c42de6dSgd78059 * Only remember fanspeeds which are real values or 3966*1c42de6dSgd78059 * NOT PRESENT values. 3967*1c42de6dSgd78059 */ 3968*1c42de6dSgd78059 if ((fanspeed <= LOM_FAN_MAX_SPEED) || 3969*1c42de6dSgd78059 (fanspeed == LOM_FAN_NOT_PRESENT)) { 3970*1c42de6dSgd78059 ssp->fanspeed[dev_no - 1] = fanspeed; 3971*1c42de6dSgd78059 } 3972*1c42de6dSgd78059 } 3973*1c42de6dSgd78059 3974*1c42de6dSgd78059 if ((state_chng & EBUS_STATE_PSU) && ((dev_no - 1) < MAX_PSUS)) { 3975*1c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, 3976*1c42de6dSgd78059 EBUS_IDX_PSU1_STAT + dev_no - 1); 3977*1c42de6dSgd78059 } 3978*1c42de6dSgd78059 3979*1c42de6dSgd78059 if (state_chng & EBUS_STATE_GP) { 3980*1c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_GPIP); 3981*1c42de6dSgd78059 } 3982*1c42de6dSgd78059 3983*1c42de6dSgd78059 if (state_chng & EBUS_STATE_CB) { 3984*1c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_CBREAK_STATUS); 3985*1c42de6dSgd78059 } 3986*1c42de6dSgd78059 3987*1c42de6dSgd78059 if ((state_chng & EBUS_STATE_TEMPERATURE) && 3988*1c42de6dSgd78059 ((dev_no - 1) < MAX_TEMPS)) { 3989*1c42de6dSgd78059 temp = bscv_get8(ssp, chan_general, 3990*1c42de6dSgd78059 EBUS_IDX_TEMP1 + dev_no - 1); 3991*1c42de6dSgd78059 /* 3992*1c42de6dSgd78059 * Only remember temperatures which are real values or 3993*1c42de6dSgd78059 * a NOT PRESENT value. 3994*1c42de6dSgd78059 */ 3995*1c42de6dSgd78059 if ((temp <= LOM_TEMP_MAX_VALUE) || 3996*1c42de6dSgd78059 (temp == LOM_TEMP_STATE_NOT_PRESENT)) { 3997*1c42de6dSgd78059 ssp->temps.temp[dev_no - 1] = temp; 3998*1c42de6dSgd78059 } 3999*1c42de6dSgd78059 } 4000*1c42de6dSgd78059 4001*1c42de6dSgd78059 if (state_chng & EBUS_STATE_RAIL) { 4002*1c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_SUPPLY_LO); 4003*1c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_SUPPLY_HI); 4004*1c42de6dSgd78059 } 4005*1c42de6dSgd78059 } 4006*1c42de6dSgd78059 4007*1c42de6dSgd78059 char * 4008*1c42de6dSgd78059 bscv_get_label(char labels[][MAX_LOM2_NAME_STR], int limit, int index) 4009*1c42de6dSgd78059 { 4010*1c42de6dSgd78059 4011*1c42de6dSgd78059 if (labels == NULL) 4012*1c42de6dSgd78059 return (""); 4013*1c42de6dSgd78059 4014*1c42de6dSgd78059 if (limit < 0 || index < 0 || index > limit) 4015*1c42de6dSgd78059 return ("-"); 4016*1c42de6dSgd78059 4017*1c42de6dSgd78059 return (labels[index]); 4018*1c42de6dSgd78059 } 4019*1c42de6dSgd78059 4020*1c42de6dSgd78059 static void 4021*1c42de6dSgd78059 bscv_generic_sysevent(bscv_soft_state_t *ssp, char *class, char *subclass, 4022*1c42de6dSgd78059 char *fru_id, char *res_id, int32_t fru_state, char *msg) 4023*1c42de6dSgd78059 { 4024*1c42de6dSgd78059 int rv; 4025*1c42de6dSgd78059 nvlist_t *attr_list; 4026*1c42de6dSgd78059 4027*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_generic_sysevent", "%s/%s:(%s,%s,%d) %s", 4028*1c42de6dSgd78059 class, subclass, fru_id, res_id, fru_state, msg); 4029*1c42de6dSgd78059 4030*1c42de6dSgd78059 4031*1c42de6dSgd78059 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP)) { 4032*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_generic_sysevent", 4033*1c42de6dSgd78059 "nvlist alloc failure"); 4034*1c42de6dSgd78059 return; 4035*1c42de6dSgd78059 } 4036*1c42de6dSgd78059 if (nvlist_add_uint32(attr_list, ENV_VERSION, 1)) { 4037*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_generic_sysevent", 4038*1c42de6dSgd78059 "nvlist ENV_VERSION failure"); 4039*1c42de6dSgd78059 nvlist_free(attr_list); 4040*1c42de6dSgd78059 return; 4041*1c42de6dSgd78059 } 4042*1c42de6dSgd78059 if (nvlist_add_string(attr_list, ENV_FRU_ID, fru_id)) { 4043*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_generic_sysevent", 4044*1c42de6dSgd78059 "nvlist ENV_FRU_ID failure"); 4045*1c42de6dSgd78059 nvlist_free(attr_list); 4046*1c42de6dSgd78059 return; 4047*1c42de6dSgd78059 } 4048*1c42de6dSgd78059 if (nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, res_id)) { 4049*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_generic_sysevent", 4050*1c42de6dSgd78059 "nvlist ENV_FRU_RESOURCE_ID failure"); 4051*1c42de6dSgd78059 nvlist_free(attr_list); 4052*1c42de6dSgd78059 return; 4053*1c42de6dSgd78059 } 4054*1c42de6dSgd78059 if (nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR)) { 4055*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_generic_sysevent", 4056*1c42de6dSgd78059 "nvlist ENV_FRU_DEVICE failure"); 4057*1c42de6dSgd78059 nvlist_free(attr_list); 4058*1c42de6dSgd78059 return; 4059*1c42de6dSgd78059 } 4060*1c42de6dSgd78059 if (nvlist_add_int32(attr_list, ENV_FRU_STATE, fru_state)) { 4061*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_generic_sysevent", 4062*1c42de6dSgd78059 "nvlist ENV_FRU_STATE failure"); 4063*1c42de6dSgd78059 nvlist_free(attr_list); 4064*1c42de6dSgd78059 return; 4065*1c42de6dSgd78059 } 4066*1c42de6dSgd78059 if (nvlist_add_string(attr_list, ENV_MSG, msg)) { 4067*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_generic_sysevent", 4068*1c42de6dSgd78059 "nvlist ENV_MSG failure"); 4069*1c42de6dSgd78059 nvlist_free(attr_list); 4070*1c42de6dSgd78059 return; 4071*1c42de6dSgd78059 } 4072*1c42de6dSgd78059 4073*1c42de6dSgd78059 rv = ddi_log_sysevent(ssp->dip, DDI_VENDOR_SUNW, class, 4074*1c42de6dSgd78059 subclass, attr_list, NULL, DDI_SLEEP); 4075*1c42de6dSgd78059 4076*1c42de6dSgd78059 if (rv == DDI_SUCCESS) { 4077*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_generic_sysevent", "sent sysevent"); 4078*1c42de6dSgd78059 } else { 4079*1c42de6dSgd78059 cmn_err(CE_WARN, "!cannot deliver sysevent"); 4080*1c42de6dSgd78059 } 4081*1c42de6dSgd78059 4082*1c42de6dSgd78059 nvlist_free(attr_list); 4083*1c42de6dSgd78059 } 4084*1c42de6dSgd78059 4085*1c42de6dSgd78059 /* 4086*1c42de6dSgd78059 * function - bscv_sysevent 4087*1c42de6dSgd78059 * description - send out a sysevent on the given change if needed 4088*1c42de6dSgd78059 * inputs - soft state pointer, event to report 4089*1c42de6dSgd78059 * outputs - none 4090*1c42de6dSgd78059 */ 4091*1c42de6dSgd78059 4092*1c42de6dSgd78059 static void 4093*1c42de6dSgd78059 bscv_sysevent(bscv_soft_state_t *ssp, lom_event_t *event) 4094*1c42de6dSgd78059 { 4095*1c42de6dSgd78059 char *class = NULL; 4096*1c42de6dSgd78059 char *subclass = NULL; 4097*1c42de6dSgd78059 char *fru_id = "Blade"; /* The blade is only one FRU */ 4098*1c42de6dSgd78059 char *res_id; 4099*1c42de6dSgd78059 int32_t fru_state = 0; 4100*1c42de6dSgd78059 4101*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_sysevent", "processing event"); 4102*1c42de6dSgd78059 4103*1c42de6dSgd78059 ASSERT(event != NULL); 4104*1c42de6dSgd78059 4105*1c42de6dSgd78059 /* Map ev_subsys to sysevent class/sub-class */ 4106*1c42de6dSgd78059 4107*1c42de6dSgd78059 switch (EVENT_DECODE_SUBSYS(event->ev_subsys)) { 4108*1c42de6dSgd78059 case EVENT_SUBSYS_NONE: 4109*1c42de6dSgd78059 break; 4110*1c42de6dSgd78059 case EVENT_SUBSYS_ALARM: 4111*1c42de6dSgd78059 break; 4112*1c42de6dSgd78059 case EVENT_SUBSYS_TEMP: 4113*1c42de6dSgd78059 class = EC_ENV, subclass = ESC_ENV_TEMP; 4114*1c42de6dSgd78059 res_id = bscv_get_label(ssp->temps.name, ssp->temps.num, 4115*1c42de6dSgd78059 event->ev_resource - 1); 4116*1c42de6dSgd78059 switch (event->ev_event) { 4117*1c42de6dSgd78059 case EVENT_SEVERE_OVERHEAT: 4118*1c42de6dSgd78059 fru_state = ENV_FAILED; 4119*1c42de6dSgd78059 break; 4120*1c42de6dSgd78059 case EVENT_OVERHEAT: 4121*1c42de6dSgd78059 fru_state = ENV_WARNING; 4122*1c42de6dSgd78059 break; 4123*1c42de6dSgd78059 case EVENT_NO_OVERHEAT: 4124*1c42de6dSgd78059 fru_state = ENV_OK; 4125*1c42de6dSgd78059 break; 4126*1c42de6dSgd78059 default: 4127*1c42de6dSgd78059 return; 4128*1c42de6dSgd78059 } 4129*1c42de6dSgd78059 break; 4130*1c42de6dSgd78059 case EVENT_SUBSYS_OVERTEMP: 4131*1c42de6dSgd78059 break; 4132*1c42de6dSgd78059 case EVENT_SUBSYS_FAN: 4133*1c42de6dSgd78059 class = EC_ENV, subclass = ESC_ENV_FAN; 4134*1c42de6dSgd78059 res_id = bscv_get_label(ssp->fan_names, ssp->num_fans, 4135*1c42de6dSgd78059 event->ev_resource - 1); 4136*1c42de6dSgd78059 switch (event->ev_event) { 4137*1c42de6dSgd78059 case EVENT_FAILED: 4138*1c42de6dSgd78059 fru_state = ENV_FAILED; 4139*1c42de6dSgd78059 break; 4140*1c42de6dSgd78059 case EVENT_RECOVERED: 4141*1c42de6dSgd78059 fru_state = ENV_OK; 4142*1c42de6dSgd78059 break; 4143*1c42de6dSgd78059 default: 4144*1c42de6dSgd78059 return; 4145*1c42de6dSgd78059 } 4146*1c42de6dSgd78059 break; 4147*1c42de6dSgd78059 case EVENT_SUBSYS_SUPPLY: 4148*1c42de6dSgd78059 class = EC_ENV, subclass = ESC_ENV_POWER; 4149*1c42de6dSgd78059 res_id = bscv_get_label(ssp->sflags.name, ssp->sflags.num, 4150*1c42de6dSgd78059 event->ev_resource - 1); 4151*1c42de6dSgd78059 switch (event->ev_event) { 4152*1c42de6dSgd78059 case EVENT_FAILED: 4153*1c42de6dSgd78059 fru_state = ENV_FAILED; 4154*1c42de6dSgd78059 break; 4155*1c42de6dSgd78059 case EVENT_RECOVERED: 4156*1c42de6dSgd78059 fru_state = ENV_OK; 4157*1c42de6dSgd78059 break; 4158*1c42de6dSgd78059 default: 4159*1c42de6dSgd78059 return; 4160*1c42de6dSgd78059 } 4161*1c42de6dSgd78059 break; 4162*1c42de6dSgd78059 case EVENT_SUBSYS_BREAKER: 4163*1c42de6dSgd78059 break; 4164*1c42de6dSgd78059 case EVENT_SUBSYS_PSU: 4165*1c42de6dSgd78059 break; 4166*1c42de6dSgd78059 case EVENT_SUBSYS_USER: 4167*1c42de6dSgd78059 break; 4168*1c42de6dSgd78059 case EVENT_SUBSYS_PHONEHOME: 4169*1c42de6dSgd78059 break; 4170*1c42de6dSgd78059 case EVENT_SUBSYS_LOM: 4171*1c42de6dSgd78059 break; 4172*1c42de6dSgd78059 case EVENT_SUBSYS_HOST: 4173*1c42de6dSgd78059 break; 4174*1c42de6dSgd78059 case EVENT_SUBSYS_EVENTLOG: 4175*1c42de6dSgd78059 break; 4176*1c42de6dSgd78059 case EVENT_SUBSYS_EXTRA: 4177*1c42de6dSgd78059 break; 4178*1c42de6dSgd78059 case EVENT_SUBSYS_LED: 4179*1c42de6dSgd78059 if (event->ev_event != EVENT_FAULT_LED && 4180*1c42de6dSgd78059 event->ev_event != EVENT_STATE_CHANGE) 4181*1c42de6dSgd78059 return; 4182*1c42de6dSgd78059 /* 4183*1c42de6dSgd78059 * There are 3 LEDs : Power, Service, Ready-to-Remove on a 4184*1c42de6dSgd78059 * JBOS blade. We'll never report the Power since Solaris 4185*1c42de6dSgd78059 * won't be running when it is _switched_ ON. Ready-to-Remove 4186*1c42de6dSgd78059 * will only be lit when we're powered down which also means 4187*1c42de6dSgd78059 * Solaris won't be running. We don't want to report it 4188*1c42de6dSgd78059 * during system testing / Sun VTS exercising the LEDs. 4189*1c42de6dSgd78059 * 4190*1c42de6dSgd78059 * Therefore, we only report the Service Required LED. 4191*1c42de6dSgd78059 */ 4192*1c42de6dSgd78059 class = EC_ENV, subclass = ESC_ENV_LED; 4193*1c42de6dSgd78059 res_id = bscv_get_label(ssp->led_names, MAX_LED_ID, 4194*1c42de6dSgd78059 event->ev_resource - 1); 4195*1c42de6dSgd78059 4196*1c42de6dSgd78059 switch (event->ev_detail) { 4197*1c42de6dSgd78059 case LOM_LED_STATE_ON_STEADY: 4198*1c42de6dSgd78059 fru_state = ENV_LED_ON; 4199*1c42de6dSgd78059 break; 4200*1c42de6dSgd78059 case LOM_LED_STATE_ON_FLASHING: 4201*1c42de6dSgd78059 case LOM_LED_STATE_ON_SLOWFLASH: 4202*1c42de6dSgd78059 fru_state = ENV_LED_BLINKING; 4203*1c42de6dSgd78059 break; 4204*1c42de6dSgd78059 case LOM_LED_STATE_OFF: 4205*1c42de6dSgd78059 fru_state = ENV_LED_OFF; 4206*1c42de6dSgd78059 break; 4207*1c42de6dSgd78059 case LOM_LED_STATE_INACCESSIBLE: 4208*1c42de6dSgd78059 fru_state = ENV_LED_INACCESSIBLE; 4209*1c42de6dSgd78059 break; 4210*1c42de6dSgd78059 case LOM_LED_STATE_STANDBY: 4211*1c42de6dSgd78059 fru_state = ENV_LED_STANDBY; 4212*1c42de6dSgd78059 break; 4213*1c42de6dSgd78059 case LOM_LED_STATE_NOT_PRESENT: 4214*1c42de6dSgd78059 fru_state = ENV_LED_NOT_PRESENT; 4215*1c42de6dSgd78059 break; 4216*1c42de6dSgd78059 default: 4217*1c42de6dSgd78059 fru_state = ENV_LED_INACCESSIBLE; 4218*1c42de6dSgd78059 break; 4219*1c42de6dSgd78059 } 4220*1c42de6dSgd78059 break; 4221*1c42de6dSgd78059 default : 4222*1c42de6dSgd78059 break; 4223*1c42de6dSgd78059 } 4224*1c42de6dSgd78059 4225*1c42de6dSgd78059 if (class == NULL || subclass == NULL) { 4226*1c42de6dSgd78059 bscv_trace(ssp, 'E', "bscv_sysevent", "class/subclass NULL"); 4227*1c42de6dSgd78059 return; 4228*1c42de6dSgd78059 } 4229*1c42de6dSgd78059 4230*1c42de6dSgd78059 bscv_generic_sysevent(ssp, class, subclass, fru_id, res_id, fru_state, 4231*1c42de6dSgd78059 ENV_RESERVED_ATTR); 4232*1c42de6dSgd78059 } 4233*1c42de6dSgd78059 4234*1c42de6dSgd78059 /* 4235*1c42de6dSgd78059 * ********************************************************************* 4236*1c42de6dSgd78059 * Firmware download (programming) 4237*1c42de6dSgd78059 * ********************************************************************* 4238*1c42de6dSgd78059 */ 4239*1c42de6dSgd78059 4240*1c42de6dSgd78059 /* 4241*1c42de6dSgd78059 * function - bscv_prog 4242*1c42de6dSgd78059 * description - LOMlite2 flash programming code. 4243*1c42de6dSgd78059 * 4244*1c42de6dSgd78059 * bscv_prog_image - download a complete image to the lom. 4245*1c42de6dSgd78059 * bscv_prog_receive_image - receive data to build up a 4246*1c42de6dSgd78059 * complete image. 4247*1c42de6dSgd78059 * bscv_prog_stop_lom - pause the event daemon and prepare 4248*1c42de6dSgd78059 * lom for firmware upgrade. 4249*1c42de6dSgd78059 * bscv_prog_start_lom - reinit the driver/lom after upgrade 4250*1c42de6dSgd78059 * and restart the event daemon 4251*1c42de6dSgd78059 * 4252*1c42de6dSgd78059 * inputs - soft state pointer, arg ptr, ioctl mode 4253*1c42de6dSgd78059 * outputs - status 4254*1c42de6dSgd78059 */ 4255*1c42de6dSgd78059 4256*1c42de6dSgd78059 static int 4257*1c42de6dSgd78059 bscv_prog(bscv_soft_state_t *ssp, intptr_t arg, int mode) 4258*1c42de6dSgd78059 { 4259*1c42de6dSgd78059 lom_prog_t *prog; 4260*1c42de6dSgd78059 int res = 0; 4261*1c42de6dSgd78059 4262*1c42de6dSgd78059 /* 4263*1c42de6dSgd78059 * We will get repeatedly called with bits of data first for 4264*1c42de6dSgd78059 * loader, then for main image. 4265*1c42de6dSgd78059 */ 4266*1c42de6dSgd78059 prog = (lom_prog_t *)kmem_alloc(sizeof (lom_prog_t), KM_SLEEP); 4267*1c42de6dSgd78059 4268*1c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)prog, sizeof (*prog), 4269*1c42de6dSgd78059 mode) < 0) { 4270*1c42de6dSgd78059 kmem_free((void *)prog, sizeof (*prog)); 4271*1c42de6dSgd78059 return (EFAULT); 4272*1c42de6dSgd78059 } 4273*1c42de6dSgd78059 4274*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_prog", 4275*1c42de6dSgd78059 "index 0x%x size 0x%x", prog->index, prog->size); 4276*1c42de6dSgd78059 4277*1c42de6dSgd78059 mutex_enter(&ssp->prog_mu); 4278*1c42de6dSgd78059 if (prog->size == 0) { 4279*1c42de6dSgd78059 if (prog->index == 2) { 4280*1c42de6dSgd78059 /* 4281*1c42de6dSgd78059 * This is the initial request for the chip type so we 4282*1c42de6dSgd78059 * know what we are programming. 4283*1c42de6dSgd78059 * The type will have been read in at init so just 4284*1c42de6dSgd78059 * return it in data[0]. 4285*1c42de6dSgd78059 */ 4286*1c42de6dSgd78059 prog->data[0] = bscv_get8_cached(ssp, 4287*1c42de6dSgd78059 EBUS_IDX_CPU_IDENT); 4288*1c42de6dSgd78059 4289*1c42de6dSgd78059 if (ddi_copyout((caddr_t)prog, (caddr_t)arg, 4290*1c42de6dSgd78059 sizeof (lom_prog_t), mode) < 0) { 4291*1c42de6dSgd78059 res = EFAULT; 4292*1c42de6dSgd78059 } 4293*1c42de6dSgd78059 } else if (prog->index == 0) { 4294*1c42de6dSgd78059 res = bscv_prog_stop_lom(ssp); 4295*1c42de6dSgd78059 } else if (prog->index == 1) { 4296*1c42de6dSgd78059 res = bscv_prog_start_lom(ssp); 4297*1c42de6dSgd78059 } else { 4298*1c42de6dSgd78059 res = EINVAL; 4299*1c42de6dSgd78059 } 4300*1c42de6dSgd78059 } else { 4301*1c42de6dSgd78059 if (ssp->image == NULL) { 4302*1c42de6dSgd78059 ssp->image = (uint8_t *)kmem_zalloc( 4303*1c42de6dSgd78059 BSC_IMAGE_MAX_SIZE, KM_SLEEP); 4304*1c42de6dSgd78059 } 4305*1c42de6dSgd78059 res = bscv_prog_receive_image(ssp, prog, 4306*1c42de6dSgd78059 ssp->image, BSC_IMAGE_MAX_SIZE); 4307*1c42de6dSgd78059 } 4308*1c42de6dSgd78059 mutex_exit(&ssp->prog_mu); 4309*1c42de6dSgd78059 kmem_free((void *)prog, sizeof (lom_prog_t)); 4310*1c42de6dSgd78059 4311*1c42de6dSgd78059 return (res); 4312*1c42de6dSgd78059 } 4313*1c42de6dSgd78059 4314*1c42de6dSgd78059 static int 4315*1c42de6dSgd78059 bscv_check_loader_config(bscv_soft_state_t *ssp, boolean_t is_image2) 4316*1c42de6dSgd78059 { 4317*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_check_loader_config", 4318*1c42de6dSgd78059 "loader_running %d, is_image2 %d", 4319*1c42de6dSgd78059 ssp->loader_running, is_image2); 4320*1c42de6dSgd78059 4321*1c42de6dSgd78059 /* 4322*1c42de6dSgd78059 * loader_running TRUE means that we have told the microcontroller to 4323*1c42de6dSgd78059 * JUMP into the loader code which has been downloaded into its RAM. 4324*1c42de6dSgd78059 * At this point its an error to try and download another loader. We 4325*1c42de6dSgd78059 * should be downloading the actual image at this point. 4326*1c42de6dSgd78059 * Conversely, it is an error to download an image when the loader is 4327*1c42de6dSgd78059 * not already downloaded and the microcontroller hasn't JUMPed into it. 4328*1c42de6dSgd78059 * is_image2 TRUE means the image is being downloaded. 4329*1c42de6dSgd78059 * is_image2 FALSE means the loader is being downloaded. 4330*1c42de6dSgd78059 */ 4331*1c42de6dSgd78059 if (ssp->loader_running && !is_image2) { 4332*1c42de6dSgd78059 cmn_err(CE_WARN, "Attempt to download loader image " 4333*1c42de6dSgd78059 "with loader image already active"); 4334*1c42de6dSgd78059 cmn_err(CE_CONT, "This maybe an attempt to restart a " 4335*1c42de6dSgd78059 "failed firmware download - ignoring download attempt"); 4336*1c42de6dSgd78059 return (B_FALSE); 4337*1c42de6dSgd78059 } else if (!ssp->loader_running && is_image2) { 4338*1c42de6dSgd78059 cmn_err(CE_WARN, "Attempt to download firmware image " 4339*1c42de6dSgd78059 "without loader image active"); 4340*1c42de6dSgd78059 return (B_FALSE); 4341*1c42de6dSgd78059 4342*1c42de6dSgd78059 } 4343*1c42de6dSgd78059 4344*1c42de6dSgd78059 return (B_TRUE); 4345*1c42de6dSgd78059 } 4346*1c42de6dSgd78059 4347*1c42de6dSgd78059 static uint32_t 4348*1c42de6dSgd78059 bscv_get_pagesize(bscv_soft_state_t *ssp) 4349*1c42de6dSgd78059 { 4350*1c42de6dSgd78059 uint32_t pagesize; 4351*1c42de6dSgd78059 4352*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 4353*1c42de6dSgd78059 4354*1c42de6dSgd78059 pagesize = bscv_get32(ssp, chan_prog, 4355*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PAGE0)); 4356*1c42de6dSgd78059 4357*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_get_pagesize", "pagesize 0x%x", pagesize); 4358*1c42de6dSgd78059 4359*1c42de6dSgd78059 return (pagesize); 4360*1c42de6dSgd78059 } 4361*1c42de6dSgd78059 4362*1c42de6dSgd78059 /* 4363*1c42de6dSgd78059 * Sets the pagesize, returning the old value. 4364*1c42de6dSgd78059 */ 4365*1c42de6dSgd78059 static uint32_t 4366*1c42de6dSgd78059 bscv_set_pagesize(bscv_soft_state_t *ssp, uint32_t pagesize) 4367*1c42de6dSgd78059 { 4368*1c42de6dSgd78059 uint32_t old_pagesize; 4369*1c42de6dSgd78059 4370*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 4371*1c42de6dSgd78059 4372*1c42de6dSgd78059 old_pagesize = bscv_get_pagesize(ssp); 4373*1c42de6dSgd78059 4374*1c42de6dSgd78059 /* 4375*1c42de6dSgd78059 * The microcontroller remembers this value until until someone 4376*1c42de6dSgd78059 * changes it. 4377*1c42de6dSgd78059 */ 4378*1c42de6dSgd78059 bscv_put32(ssp, chan_prog, 4379*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PSIZ0), pagesize); 4380*1c42de6dSgd78059 4381*1c42de6dSgd78059 return (old_pagesize); 4382*1c42de6dSgd78059 } 4383*1c42de6dSgd78059 4384*1c42de6dSgd78059 static uint8_t 4385*1c42de6dSgd78059 bscv_enter_programming_mode(bscv_soft_state_t *ssp) 4386*1c42de6dSgd78059 { 4387*1c42de6dSgd78059 uint8_t retval; 4388*1c42de6dSgd78059 4389*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 4390*1c42de6dSgd78059 4391*1c42de6dSgd78059 bscv_put8(ssp, chan_prog, 4392*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), 4393*1c42de6dSgd78059 EBUS_PROGRAM_PCR_PRGMODE_ON); 4394*1c42de6dSgd78059 4395*1c42de6dSgd78059 retval = bscv_get8(ssp, chan_prog, BSCVA(EBUS_CMD_SPACE_PROGRAM, 4396*1c42de6dSgd78059 EBUS_PROGRAM_PCSR)); 4397*1c42de6dSgd78059 4398*1c42de6dSgd78059 return (retval); 4399*1c42de6dSgd78059 } 4400*1c42de6dSgd78059 4401*1c42de6dSgd78059 static void 4402*1c42de6dSgd78059 bscv_leave_programming_mode(bscv_soft_state_t *ssp, boolean_t with_jmp) 4403*1c42de6dSgd78059 { 4404*1c42de6dSgd78059 uint8_t reg; 4405*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 4406*1c42de6dSgd78059 4407*1c42de6dSgd78059 if (with_jmp) { 4408*1c42de6dSgd78059 reg = EBUS_PROGRAM_PCR_PROGOFF_JUMPTOADDR; 4409*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_leave_programming_mode", 4410*1c42de6dSgd78059 "jumptoaddr"); 4411*1c42de6dSgd78059 } else { 4412*1c42de6dSgd78059 reg = EBUS_PROGRAM_PCR_PRGMODE_OFF; 4413*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_leave_programming_mode", 4414*1c42de6dSgd78059 "prgmode_off"); 4415*1c42de6dSgd78059 } 4416*1c42de6dSgd78059 4417*1c42de6dSgd78059 bscv_put8(ssp, chan_prog, 4418*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), reg); 4419*1c42de6dSgd78059 } 4420*1c42de6dSgd78059 4421*1c42de6dSgd78059 4422*1c42de6dSgd78059 static void 4423*1c42de6dSgd78059 bscv_set_jump_to_addr(bscv_soft_state_t *ssp, uint32_t loadaddr) 4424*1c42de6dSgd78059 { 4425*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 4426*1c42de6dSgd78059 4427*1c42de6dSgd78059 bscv_put32(ssp, chan_prog, 4428*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0), loadaddr); 4429*1c42de6dSgd78059 4430*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_set_jump_to_addr", 4431*1c42de6dSgd78059 "set jump to loadaddr 0x%x", loadaddr); 4432*1c42de6dSgd78059 } 4433*1c42de6dSgd78059 4434*1c42de6dSgd78059 static uint8_t 4435*1c42de6dSgd78059 bscv_erase_once(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size) 4436*1c42de6dSgd78059 { 4437*1c42de6dSgd78059 uint8_t retval; 4438*1c42de6dSgd78059 4439*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 4440*1c42de6dSgd78059 4441*1c42de6dSgd78059 /* 4442*1c42de6dSgd78059 * write PADR, PSIZ to define area to be erased 4443*1c42de6dSgd78059 * We do not send erase for zero size because the current 4444*1c42de6dSgd78059 * downloader gets this wrong 4445*1c42de6dSgd78059 */ 4446*1c42de6dSgd78059 4447*1c42de6dSgd78059 /* 4448*1c42de6dSgd78059 * start at 0 4449*1c42de6dSgd78059 */ 4450*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_erase_once", "sending erase command"); 4451*1c42de6dSgd78059 4452*1c42de6dSgd78059 bscv_put32(ssp, chan_prog, 4453*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0), 4454*1c42de6dSgd78059 loadaddr); 4455*1c42de6dSgd78059 4456*1c42de6dSgd78059 /* set PSIZ to full size of image to be programmed */ 4457*1c42de6dSgd78059 bscv_put32(ssp, chan_prog, 4458*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PSIZ0), 4459*1c42de6dSgd78059 image_size); 4460*1c42de6dSgd78059 4461*1c42de6dSgd78059 /* write ERASE to PCSR */ 4462*1c42de6dSgd78059 bscv_put8(ssp, chan_prog, 4463*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), 4464*1c42de6dSgd78059 EBUS_PROGRAM_PCR_ERASE); 4465*1c42de6dSgd78059 4466*1c42de6dSgd78059 /* read PCSR to check status */ 4467*1c42de6dSgd78059 retval = bscv_get8(ssp, chan_prog, 4468*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR)); 4469*1c42de6dSgd78059 return (retval); 4470*1c42de6dSgd78059 } 4471*1c42de6dSgd78059 4472*1c42de6dSgd78059 static uint8_t 4473*1c42de6dSgd78059 bscv_do_erase(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size, 4474*1c42de6dSgd78059 boolean_t is_image2) 4475*1c42de6dSgd78059 { 4476*1c42de6dSgd78059 int retryable = BSC_ERASE_RETRY_LIMIT; 4477*1c42de6dSgd78059 uint8_t retval; 4478*1c42de6dSgd78059 4479*1c42de6dSgd78059 while (retryable--) { 4480*1c42de6dSgd78059 retval = bscv_erase_once(ssp, loadaddr, image_size); 4481*1c42de6dSgd78059 if (PSR_SUCCESS(retval)) 4482*1c42de6dSgd78059 break; 4483*1c42de6dSgd78059 else 4484*1c42de6dSgd78059 cmn_err(CE_WARN, "erase error 0x%x, attempt %d" 4485*1c42de6dSgd78059 ", base 0x%x, size 0x%x, %s image", 4486*1c42de6dSgd78059 retval, BSC_ERASE_RETRY_LIMIT - retryable, 4487*1c42de6dSgd78059 loadaddr, image_size, 4488*1c42de6dSgd78059 is_image2 ? "main" : "loader"); 4489*1c42de6dSgd78059 } 4490*1c42de6dSgd78059 4491*1c42de6dSgd78059 return (retval); 4492*1c42de6dSgd78059 } 4493*1c42de6dSgd78059 4494*1c42de6dSgd78059 static uint8_t 4495*1c42de6dSgd78059 bscv_set_page(bscv_soft_state_t *ssp, uint32_t addr) 4496*1c42de6dSgd78059 { 4497*1c42de6dSgd78059 uint32_t retval; 4498*1c42de6dSgd78059 int retryable = BSC_PAGE_RETRY_LIMIT; 4499*1c42de6dSgd78059 4500*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 4501*1c42de6dSgd78059 4502*1c42de6dSgd78059 while (retryable--) { 4503*1c42de6dSgd78059 4504*1c42de6dSgd78059 /* 4505*1c42de6dSgd78059 * Write the page address and read it back for confirmation. 4506*1c42de6dSgd78059 */ 4507*1c42de6dSgd78059 bscv_put32(ssp, chan_prog, 4508*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0), 4509*1c42de6dSgd78059 addr); 4510*1c42de6dSgd78059 retval = bscv_get32(ssp, chan_prog, 4511*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0)); 4512*1c42de6dSgd78059 4513*1c42de6dSgd78059 if (retval == addr) 4514*1c42de6dSgd78059 break; 4515*1c42de6dSgd78059 else { 4516*1c42de6dSgd78059 cmn_err(CE_WARN, "programmming error, attempt %d, " 4517*1c42de6dSgd78059 "set page 0x%x, read back 0x%x", 4518*1c42de6dSgd78059 BSC_PAGE_RETRY_LIMIT - retryable, 4519*1c42de6dSgd78059 addr, retval); 4520*1c42de6dSgd78059 } 4521*1c42de6dSgd78059 } 4522*1c42de6dSgd78059 return ((addr == retval) ? EBUS_PROGRAM_PSR_SUCCESS : 4523*1c42de6dSgd78059 EBUS_PROGRAM_PSR_INVALID_OPERATION); 4524*1c42de6dSgd78059 } 4525*1c42de6dSgd78059 4526*1c42de6dSgd78059 static uint8_t 4527*1c42de6dSgd78059 bscv_do_page_data_once(bscv_soft_state_t *ssp, uint32_t index, 4528*1c42de6dSgd78059 uint32_t image_size, uint32_t pagesize, uint8_t *imagep, 4529*1c42de6dSgd78059 uint16_t *calcd_chksum) 4530*1c42de6dSgd78059 { 4531*1c42de6dSgd78059 uint32_t size; 4532*1c42de6dSgd78059 uint16_t chksum; 4533*1c42de6dSgd78059 int i; 4534*1c42de6dSgd78059 uint8_t retval; 4535*1c42de6dSgd78059 4536*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 4537*1c42de6dSgd78059 4538*1c42de6dSgd78059 bscv_trace(ssp, 'P', "bscv_do_page_data_once", "index 0x%x", index); 4539*1c42de6dSgd78059 4540*1c42de6dSgd78059 /* write PSIZ bytes to PDAT */ 4541*1c42de6dSgd78059 if (index + pagesize < image_size) { 4542*1c42de6dSgd78059 bscv_rep_rw8(ssp, chan_prog, imagep + index, 4543*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_DATA), 4544*1c42de6dSgd78059 pagesize, DDI_DEV_NO_AUTOINCR, B_TRUE /* write */); 4545*1c42de6dSgd78059 size = pagesize; 4546*1c42de6dSgd78059 } else { 4547*1c42de6dSgd78059 bscv_trace(ssp, 'P', "bscv_do_page_once", 4548*1c42de6dSgd78059 "Sending last block, last 0x%x bytes", 4549*1c42de6dSgd78059 (image_size % pagesize)); 4550*1c42de6dSgd78059 size = (image_size - index); 4551*1c42de6dSgd78059 bscv_rep_rw8(ssp, chan_prog, imagep + index, 4552*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_DATA), 4553*1c42de6dSgd78059 size, DDI_DEV_NO_AUTOINCR, B_TRUE /* write */); 4554*1c42de6dSgd78059 /* Now pad the rest of the page with zeros */ 4555*1c42de6dSgd78059 for (i = size; i < pagesize; i++) { 4556*1c42de6dSgd78059 bscv_put8(ssp, chan_prog, 4557*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, 4558*1c42de6dSgd78059 EBUS_PROGRAM_DATA), 4559*1c42de6dSgd78059 0); 4560*1c42de6dSgd78059 } 4561*1c42de6dSgd78059 } 4562*1c42de6dSgd78059 4563*1c42de6dSgd78059 /* write the checksum to PCSM */ 4564*1c42de6dSgd78059 chksum = 0; 4565*1c42de6dSgd78059 for (i = 0; i < size; i++) { 4566*1c42de6dSgd78059 chksum = ((chksum << 3) | (chksum >> 13)) ^ 4567*1c42de6dSgd78059 *(imagep + index + i); 4568*1c42de6dSgd78059 } 4569*1c42de6dSgd78059 /* Cope with non-pagesize sized bufers */ 4570*1c42de6dSgd78059 for (; i < pagesize; i++) { 4571*1c42de6dSgd78059 chksum = ((chksum << 3) | (chksum >> 13)) ^ 0; 4572*1c42de6dSgd78059 } 4573*1c42de6dSgd78059 bscv_put16(ssp, chan_prog, 4574*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSM0), chksum); 4575*1c42de6dSgd78059 4576*1c42de6dSgd78059 bscv_put8(ssp, chan_prog, 4577*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), 4578*1c42de6dSgd78059 EBUS_PROGRAM_PCR_PROGRAM); 4579*1c42de6dSgd78059 4580*1c42de6dSgd78059 retval = bscv_get8(ssp, chan_prog, 4581*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR)); 4582*1c42de6dSgd78059 4583*1c42de6dSgd78059 *calcd_chksum = chksum; 4584*1c42de6dSgd78059 return (retval); 4585*1c42de6dSgd78059 } 4586*1c42de6dSgd78059 4587*1c42de6dSgd78059 static uint8_t bscv_do_page(bscv_soft_state_t *ssp, uint32_t loadaddr, 4588*1c42de6dSgd78059 uint32_t index, uint32_t image_size, uint32_t pagesize, uint8_t *imagep, 4589*1c42de6dSgd78059 boolean_t is_image2) 4590*1c42de6dSgd78059 { 4591*1c42de6dSgd78059 int retryable = BSC_PAGE_RETRY_LIMIT; 4592*1c42de6dSgd78059 uint8_t retval; 4593*1c42de6dSgd78059 uint16_t checksum; 4594*1c42de6dSgd78059 4595*1c42de6dSgd78059 bscv_trace(ssp, 'P', "bscv_do_page", "index 0x%x", index); 4596*1c42de6dSgd78059 4597*1c42de6dSgd78059 while (retryable--) { 4598*1c42de6dSgd78059 /* 4599*1c42de6dSgd78059 * Set the page address (with retries). If this is not 4600*1c42de6dSgd78059 * successful, then there is no point carrying on and sending 4601*1c42de6dSgd78059 * the page's data since that could cause random memory 4602*1c42de6dSgd78059 * corruption in the microcontroller. 4603*1c42de6dSgd78059 */ 4604*1c42de6dSgd78059 retval = bscv_set_page(ssp, loadaddr + index); 4605*1c42de6dSgd78059 if (!PSR_SUCCESS(retval)) { 4606*1c42de6dSgd78059 cmn_err(CE_WARN, "programming error 0x%x, " 4607*1c42de6dSgd78059 "could not setup page address 0x%x, %s image", 4608*1c42de6dSgd78059 retval, loadaddr + index, 4609*1c42de6dSgd78059 is_image2 ? "main" : "loader"); 4610*1c42de6dSgd78059 break; 4611*1c42de6dSgd78059 } 4612*1c42de6dSgd78059 4613*1c42de6dSgd78059 /* 4614*1c42de6dSgd78059 * Send down the data for the page 4615*1c42de6dSgd78059 */ 4616*1c42de6dSgd78059 4617*1c42de6dSgd78059 bscv_trace(ssp, 'P', "bscv_do_page", "sending data for page"); 4618*1c42de6dSgd78059 4619*1c42de6dSgd78059 retval = bscv_do_page_data_once(ssp, index, image_size, 4620*1c42de6dSgd78059 pagesize, imagep, &checksum); 4621*1c42de6dSgd78059 if (PSR_SUCCESS(retval)) 4622*1c42de6dSgd78059 break; 4623*1c42de6dSgd78059 else 4624*1c42de6dSgd78059 cmn_err(CE_WARN, "programming error 0x%x," 4625*1c42de6dSgd78059 " attempt %d, index 0x%x, checksum 0x%x, %s image", 4626*1c42de6dSgd78059 retval, BSC_PAGE_RETRY_LIMIT - retryable, 4627*1c42de6dSgd78059 index, checksum, is_image2 ? "main" : "loader"); 4628*1c42de6dSgd78059 } 4629*1c42de6dSgd78059 4630*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_do_page", "Returning 0x%x for index 0x%x," 4631*1c42de6dSgd78059 " checksum 0x%x, %s image", retval, index, checksum, 4632*1c42de6dSgd78059 is_image2 ? "main" : "loader"); 4633*1c42de6dSgd78059 4634*1c42de6dSgd78059 return (retval); 4635*1c42de6dSgd78059 } 4636*1c42de6dSgd78059 4637*1c42de6dSgd78059 static uint8_t 4638*1c42de6dSgd78059 bscv_do_pages(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size, 4639*1c42de6dSgd78059 uint32_t pagesize, uint8_t *imagep, boolean_t is_image2) 4640*1c42de6dSgd78059 { 4641*1c42de6dSgd78059 uint8_t retval; 4642*1c42de6dSgd78059 uint32_t index; 4643*1c42de6dSgd78059 4644*1c42de6dSgd78059 bscv_trace(ssp, 'P', "bscv_do_pages", "entered"); 4645*1c42de6dSgd78059 4646*1c42de6dSgd78059 for (index = 0; index < image_size; index += pagesize) { 4647*1c42de6dSgd78059 retval = bscv_do_page(ssp, loadaddr, index, image_size, 4648*1c42de6dSgd78059 pagesize, imagep, is_image2); 4649*1c42de6dSgd78059 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) { 4650*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_do_pages", 4651*1c42de6dSgd78059 "Failed to program lom (status 0x%x)", retval); 4652*1c42de6dSgd78059 break; 4653*1c42de6dSgd78059 } 4654*1c42de6dSgd78059 } 4655*1c42de6dSgd78059 4656*1c42de6dSgd78059 return (retval); 4657*1c42de6dSgd78059 } 4658*1c42de6dSgd78059 4659*1c42de6dSgd78059 static int 4660*1c42de6dSgd78059 bscv_prog_image(bscv_soft_state_t *ssp, boolean_t is_image2, 4661*1c42de6dSgd78059 uint8_t *imagep, int image_size, uint32_t loadaddr) 4662*1c42de6dSgd78059 { 4663*1c42de6dSgd78059 uint32_t pagesize; 4664*1c42de6dSgd78059 int res = 0; 4665*1c42de6dSgd78059 uint8_t retval; 4666*1c42de6dSgd78059 4667*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_prog_image", 4668*1c42de6dSgd78059 "image 0x%x, imagep %p, size 0x%x", 4669*1c42de6dSgd78059 is_image2 ? 2 : 1, imagep, image_size); 4670*1c42de6dSgd78059 4671*1c42de6dSgd78059 if (!bscv_check_loader_config(ssp, is_image2)) 4672*1c42de6dSgd78059 /* 4673*1c42de6dSgd78059 * Return no error to allow userland to continue on with 4674*1c42de6dSgd78059 * downloading the image. 4675*1c42de6dSgd78059 */ 4676*1c42de6dSgd78059 return (0); 4677*1c42de6dSgd78059 4678*1c42de6dSgd78059 bscv_enter(ssp); 4679*1c42de6dSgd78059 4680*1c42de6dSgd78059 pagesize = bscv_get_pagesize(ssp); 4681*1c42de6dSgd78059 4682*1c42de6dSgd78059 retval = bscv_enter_programming_mode(ssp); 4683*1c42de6dSgd78059 if (bscv_faulty(ssp) || !PSR_PROG(retval)) { 4684*1c42de6dSgd78059 cmn_err(CE_WARN, "lom: Failed to enter program mode, error 0x%x" 4685*1c42de6dSgd78059 ", %s image", retval, is_image2 ? "main" : "loader"); 4686*1c42de6dSgd78059 res = EIO; 4687*1c42de6dSgd78059 goto BSCV_PROG_IMAGE_END; 4688*1c42de6dSgd78059 } 4689*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_prog_image", "entered programming mode"); 4690*1c42de6dSgd78059 4691*1c42de6dSgd78059 /* 4692*1c42de6dSgd78059 * Only issue an erase if we are downloading the image. The loader 4693*1c42de6dSgd78059 * does not need this step. 4694*1c42de6dSgd78059 */ 4695*1c42de6dSgd78059 if (is_image2 && (image_size != 0)) { 4696*1c42de6dSgd78059 retval = bscv_do_erase(ssp, loadaddr, image_size, is_image2); 4697*1c42de6dSgd78059 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) { 4698*1c42de6dSgd78059 cmn_err(CE_WARN, 4699*1c42de6dSgd78059 "lom: Erase failed during programming, status 0x%x", 4700*1c42de6dSgd78059 retval); 4701*1c42de6dSgd78059 res = EIO; 4702*1c42de6dSgd78059 goto BSCV_PROG_IMAGE_END; 4703*1c42de6dSgd78059 } else { 4704*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_prog_image", 4705*1c42de6dSgd78059 "erase complete - programming..."); 4706*1c42de6dSgd78059 4707*1c42de6dSgd78059 } 4708*1c42de6dSgd78059 } 4709*1c42de6dSgd78059 4710*1c42de6dSgd78059 (void) bscv_set_pagesize(ssp, pagesize); 4711*1c42de6dSgd78059 4712*1c42de6dSgd78059 retval = bscv_do_pages(ssp, loadaddr, image_size, pagesize, imagep, 4713*1c42de6dSgd78059 is_image2); 4714*1c42de6dSgd78059 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) { 4715*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_prog_image", 4716*1c42de6dSgd78059 "Failed to program lom (status 0x%x)", retval); 4717*1c42de6dSgd78059 res = EIO; 4718*1c42de6dSgd78059 goto BSCV_PROG_IMAGE_END; 4719*1c42de6dSgd78059 } 4720*1c42de6dSgd78059 4721*1c42de6dSgd78059 BSCV_PROG_IMAGE_END: 4722*1c42de6dSgd78059 if (res == 0 && !is_image2) { 4723*1c42de6dSgd78059 /* 4724*1c42de6dSgd78059 * We've downloaded the loader successfully. Now make the 4725*1c42de6dSgd78059 * microcontroller jump to it. 4726*1c42de6dSgd78059 */ 4727*1c42de6dSgd78059 bscv_set_jump_to_addr(ssp, loadaddr); 4728*1c42de6dSgd78059 ssp->loader_running = B_TRUE; 4729*1c42de6dSgd78059 bscv_leave_programming_mode(ssp, B_TRUE); 4730*1c42de6dSgd78059 } else { 4731*1c42de6dSgd78059 /* 4732*1c42de6dSgd78059 * We've just downloaded either the loader which failed, or 4733*1c42de6dSgd78059 * the image (which may or may not have been successful). 4734*1c42de6dSgd78059 */ 4735*1c42de6dSgd78059 bscv_set_jump_to_addr(ssp, 0); 4736*1c42de6dSgd78059 4737*1c42de6dSgd78059 if (res != 0) { 4738*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_prog_image", 4739*1c42de6dSgd78059 "got error 0x%x - leaving programming mode", 4740*1c42de6dSgd78059 res); 4741*1c42de6dSgd78059 cmn_err(CE_WARN, "programming error 0x%x, %s image", 4742*1c42de6dSgd78059 res, is_image2 ? "main" : "loader"); 4743*1c42de6dSgd78059 } else { 4744*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_prog_image", 4745*1c42de6dSgd78059 "programming complete - leaving programming mode"); 4746*1c42de6dSgd78059 } 4747*1c42de6dSgd78059 4748*1c42de6dSgd78059 bscv_leave_programming_mode(ssp, B_FALSE); 4749*1c42de6dSgd78059 ssp->loader_running = B_FALSE; 4750*1c42de6dSgd78059 } 4751*1c42de6dSgd78059 4752*1c42de6dSgd78059 bscv_exit(ssp); 4753*1c42de6dSgd78059 4754*1c42de6dSgd78059 return (res); 4755*1c42de6dSgd78059 } 4756*1c42de6dSgd78059 4757*1c42de6dSgd78059 4758*1c42de6dSgd78059 static int 4759*1c42de6dSgd78059 bscv_prog_receive_image(bscv_soft_state_t *ssp, lom_prog_t *prog, 4760*1c42de6dSgd78059 uint8_t *imagep, int max_size) 4761*1c42de6dSgd78059 { 4762*1c42de6dSgd78059 int res = 0; 4763*1c42de6dSgd78059 uint_t size; 4764*1c42de6dSgd78059 int32_t loadaddr; 4765*1c42de6dSgd78059 lom_prog_data_t *prog_data; 4766*1c42de6dSgd78059 4767*1c42de6dSgd78059 if ((prog->index & 0x7FFF) != ssp->prog_index) { 4768*1c42de6dSgd78059 bscv_trace(ssp, 'U', "bscv_prog_receive_image", 4769*1c42de6dSgd78059 "Got wrong buffer 0x%x, expected 0x%x", 4770*1c42de6dSgd78059 prog->index & 0x7fff, ssp->prog_index); 4771*1c42de6dSgd78059 return (EINVAL); 4772*1c42de6dSgd78059 } 4773*1c42de6dSgd78059 4774*1c42de6dSgd78059 /* 4775*1c42de6dSgd78059 * We want to get the whole image and then do the download. 4776*1c42de6dSgd78059 * It is assumed the device is now in programming mode. 4777*1c42de6dSgd78059 */ 4778*1c42de6dSgd78059 4779*1c42de6dSgd78059 if ((prog->index & 0x7fff) == 0) { 4780*1c42de6dSgd78059 /* Starting a new image */ 4781*1c42de6dSgd78059 ssp->image_ptr = 0; 4782*1c42de6dSgd78059 } 4783*1c42de6dSgd78059 4784*1c42de6dSgd78059 if ((ssp->image_ptr + prog->size) > max_size) { 4785*1c42de6dSgd78059 cmn_err(CE_WARN, 4786*1c42de6dSgd78059 "lom image exceeded maximum size: got 0x%x, maximum 0x%x", 4787*1c42de6dSgd78059 (ssp->image_ptr + prog->size), max_size); 4788*1c42de6dSgd78059 return (EFAULT); 4789*1c42de6dSgd78059 } 4790*1c42de6dSgd78059 bcopy(prog->data, &imagep[ssp->image_ptr], prog->size); 4791*1c42de6dSgd78059 ssp->image_ptr += prog->size; 4792*1c42de6dSgd78059 4793*1c42de6dSgd78059 ssp->prog_index++; 4794*1c42de6dSgd78059 4795*1c42de6dSgd78059 if (prog->index & 0x8000) { 4796*1c42de6dSgd78059 /* 4797*1c42de6dSgd78059 * OK we have the whole image so synch up and start download. 4798*1c42de6dSgd78059 */ 4799*1c42de6dSgd78059 prog_data = (lom_prog_data_t *)imagep; 4800*1c42de6dSgd78059 if (prog_data->header.magic != PROG_MAGIC) { 4801*1c42de6dSgd78059 /* Old style programming data */ 4802*1c42de6dSgd78059 /* Take care image may not fill all of structure */ 4803*1c42de6dSgd78059 4804*1c42de6dSgd78059 /* sign extend loadaddr from 16 to 32 bits */ 4805*1c42de6dSgd78059 loadaddr = (int16_t)((uint16_t)((imagep[2] << 8) + 4806*1c42de6dSgd78059 imagep[3])); 4807*1c42de6dSgd78059 4808*1c42de6dSgd78059 size = (imagep[0] << 8) + imagep[1]; 4809*1c42de6dSgd78059 if (size != (ssp->image_ptr - 4)) { 4810*1c42de6dSgd78059 cmn_err(CE_WARN, "Image size mismatch:" 4811*1c42de6dSgd78059 " expected 0x%x, got 0x%x", 4812*1c42de6dSgd78059 size, (ssp->image_ptr - 1)); 4813*1c42de6dSgd78059 } 4814*1c42de6dSgd78059 4815*1c42de6dSgd78059 res = bscv_prog_image(ssp, 4816*1c42de6dSgd78059 ssp->image2_processing, 4817*1c42de6dSgd78059 imagep + 4, ssp->image_ptr - 4, loadaddr); 4818*1c42de6dSgd78059 4819*1c42de6dSgd78059 /* 4820*1c42de6dSgd78059 * Done the loading so set the flag to say we are doing 4821*1c42de6dSgd78059 * the other image. 4822*1c42de6dSgd78059 */ 4823*1c42de6dSgd78059 ssp->image2_processing = !ssp->image2_processing; 4824*1c42de6dSgd78059 } else if ((ssp->image_ptr < sizeof (*prog_data)) || 4825*1c42de6dSgd78059 (prog_data->platform.bscv.size != 4826*1c42de6dSgd78059 (ssp->image_ptr - sizeof (*prog_data)))) { 4827*1c42de6dSgd78059 /* Image too small for new style image */ 4828*1c42de6dSgd78059 cmn_err(CE_WARN, "image too small"); 4829*1c42de6dSgd78059 res = EINVAL; 4830*1c42de6dSgd78059 } else { 4831*1c42de6dSgd78059 /* New style programming image */ 4832*1c42de6dSgd78059 switch (prog_data->platmagic) { 4833*1c42de6dSgd78059 case PROG_PLAT_BSCV_IMAGE: 4834*1c42de6dSgd78059 res = bscv_prog_image(ssp, B_TRUE, 4835*1c42de6dSgd78059 imagep + sizeof (*prog_data), 4836*1c42de6dSgd78059 prog_data->platform.bscv.size, 4837*1c42de6dSgd78059 prog_data->platform.bscv.loadaddr); 4838*1c42de6dSgd78059 ssp->image2_processing = B_FALSE; 4839*1c42de6dSgd78059 break; 4840*1c42de6dSgd78059 case PROG_PLAT_BSCV_LOADER: 4841*1c42de6dSgd78059 res = bscv_prog_image(ssp, B_FALSE, 4842*1c42de6dSgd78059 imagep + sizeof (*prog_data), 4843*1c42de6dSgd78059 prog_data->platform.bscv.size, 4844*1c42de6dSgd78059 prog_data->platform.bscv.loadaddr); 4845*1c42de6dSgd78059 ssp->image2_processing = B_TRUE; 4846*1c42de6dSgd78059 break; 4847*1c42de6dSgd78059 default: 4848*1c42de6dSgd78059 cmn_err(CE_WARN, "unknown platmagic 0x%x", 4849*1c42de6dSgd78059 prog_data->platmagic); 4850*1c42de6dSgd78059 res = EINVAL; 4851*1c42de6dSgd78059 break; 4852*1c42de6dSgd78059 } 4853*1c42de6dSgd78059 } 4854*1c42de6dSgd78059 ssp->prog_index = 0; 4855*1c42de6dSgd78059 ssp->image_ptr = 0; 4856*1c42de6dSgd78059 } 4857*1c42de6dSgd78059 return (res); 4858*1c42de6dSgd78059 } 4859*1c42de6dSgd78059 4860*1c42de6dSgd78059 static int 4861*1c42de6dSgd78059 bscv_prog_stop_lom(bscv_soft_state_t *ssp) 4862*1c42de6dSgd78059 { 4863*1c42de6dSgd78059 if (ssp->programming) { 4864*1c42de6dSgd78059 /* 4865*1c42de6dSgd78059 * Already programming - this may be a retry of a failed 4866*1c42de6dSgd78059 * programming attempt or just a software error! 4867*1c42de6dSgd78059 */ 4868*1c42de6dSgd78059 goto queue_stopped; 4869*1c42de6dSgd78059 } 4870*1c42de6dSgd78059 4871*1c42de6dSgd78059 if (bscv_pause_event_daemon(ssp) == BSCV_FAILURE) { 4872*1c42de6dSgd78059 bscv_trace(ssp, 'Q', "bscv_prog_stop_lom", 4873*1c42de6dSgd78059 "failed to pause event daemon thread"); 4874*1c42de6dSgd78059 return (EAGAIN); 4875*1c42de6dSgd78059 } 4876*1c42de6dSgd78059 4877*1c42de6dSgd78059 bscv_enter(ssp); 4878*1c42de6dSgd78059 4879*1c42de6dSgd78059 ssp->programming = B_TRUE; 4880*1c42de6dSgd78059 4881*1c42de6dSgd78059 bscv_exit(ssp); 4882*1c42de6dSgd78059 4883*1c42de6dSgd78059 queue_stopped: 4884*1c42de6dSgd78059 4885*1c42de6dSgd78059 ssp->prog_index = 0; 4886*1c42de6dSgd78059 ssp->image2_processing = B_FALSE; 4887*1c42de6dSgd78059 4888*1c42de6dSgd78059 return (0); 4889*1c42de6dSgd78059 } 4890*1c42de6dSgd78059 4891*1c42de6dSgd78059 static int 4892*1c42de6dSgd78059 bscv_prog_start_lom(bscv_soft_state_t *ssp) 4893*1c42de6dSgd78059 { 4894*1c42de6dSgd78059 int res = 0; 4895*1c42de6dSgd78059 4896*1c42de6dSgd78059 if (!ssp->programming) { 4897*1c42de6dSgd78059 /* Not programming so this is not a valid command */ 4898*1c42de6dSgd78059 return (EINVAL); 4899*1c42de6dSgd78059 } 4900*1c42de6dSgd78059 4901*1c42de6dSgd78059 if (ssp->image != NULL) { 4902*1c42de6dSgd78059 kmem_free((void *)ssp->image, BSC_IMAGE_MAX_SIZE); 4903*1c42de6dSgd78059 ssp->image = NULL; 4904*1c42de6dSgd78059 } 4905*1c42de6dSgd78059 4906*1c42de6dSgd78059 /* 4907*1c42de6dSgd78059 * OK we are out of reset now so: 4908*1c42de6dSgd78059 * Probe the firmware and set everything up. 4909*1c42de6dSgd78059 */ 4910*1c42de6dSgd78059 4911*1c42de6dSgd78059 bscv_enter(ssp); 4912*1c42de6dSgd78059 4913*1c42de6dSgd78059 /* Explicit clear fault because things may have been mended now */ 4914*1c42de6dSgd78059 bscv_clear_fault(ssp); 4915*1c42de6dSgd78059 4916*1c42de6dSgd78059 if (ssp->loader_running) { 4917*1c42de6dSgd78059 cmn_err(CE_WARN, "Firmware upgrade failed to exit loader - " 4918*1c42de6dSgd78059 "performing forced exit"); 4919*1c42de6dSgd78059 /* Must try to restart the lom here. */ 4920*1c42de6dSgd78059 /* Ensure prog mode entry to enable PRGMODE_OFF */ 4921*1c42de6dSgd78059 bscv_put8(ssp, chan_prog, 4922*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), 4923*1c42de6dSgd78059 EBUS_PROGRAM_PCR_PRGMODE_ON); 4924*1c42de6dSgd78059 bscv_put8(ssp, chan_prog, 4925*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), 4926*1c42de6dSgd78059 EBUS_PROGRAM_PCR_PRGMODE_OFF); 4927*1c42de6dSgd78059 ssp->loader_running = B_FALSE; 4928*1c42de6dSgd78059 /* give the lom chance to recover */ 4929*1c42de6dSgd78059 delay(drv_usectohz(5000000)); /* 5 seconds */ 4930*1c42de6dSgd78059 } 4931*1c42de6dSgd78059 4932*1c42de6dSgd78059 ssp->prog_mode_only = B_FALSE; 4933*1c42de6dSgd78059 ssp->programming = B_FALSE; 4934*1c42de6dSgd78059 4935*1c42de6dSgd78059 if (bscv_attach_common(ssp) == DDI_FAILURE) { 4936*1c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 4937*1c42de6dSgd78059 res = EIO; 4938*1c42de6dSgd78059 } 4939*1c42de6dSgd78059 4940*1c42de6dSgd78059 bscv_exit(ssp); 4941*1c42de6dSgd78059 4942*1c42de6dSgd78059 if (!ssp->prog_mode_only) { 4943*1c42de6dSgd78059 /* 4944*1c42de6dSgd78059 * Start the event thread after the queue has started 4945*1c42de6dSgd78059 * 4946*1c42de6dSgd78059 * Not sure if this is entirely correct because 4947*1c42de6dSgd78059 * the other code at the end of bscv_attach() 4948*1c42de6dSgd78059 * does not get run here. 4949*1c42de6dSgd78059 */ 4950*1c42de6dSgd78059 bscv_start_event_daemon(ssp); 4951*1c42de6dSgd78059 bscv_resume_event_daemon(ssp); 4952*1c42de6dSgd78059 } 4953*1c42de6dSgd78059 4954*1c42de6dSgd78059 return (res); 4955*1c42de6dSgd78059 } 4956*1c42de6dSgd78059 4957*1c42de6dSgd78059 4958*1c42de6dSgd78059 /* 4959*1c42de6dSgd78059 * ********************************************************************* 4960*1c42de6dSgd78059 * Attach processing 4961*1c42de6dSgd78059 * ********************************************************************* 4962*1c42de6dSgd78059 */ 4963*1c42de6dSgd78059 4964*1c42de6dSgd78059 /* 4965*1c42de6dSgd78059 * function - bscv_attach_common 4966*1c42de6dSgd78059 * description - this routine co-ordinates the initialisation of the 4967*1c42de6dSgd78059 * driver both at attach time and after firmware programming. 4968*1c42de6dSgd78059 * sequence - bscv_setup_capability - read LOMlite2 capabilities 4969*1c42de6dSgd78059 * bscv_probe_check - test comms and setup register cache 4970*1c42de6dSgd78059 * bscv_setup_hostname - sync stored name in lom with nodename. 4971*1c42de6dSgd78059 * bscv_setup_static_info - read device names etc. 4972*1c42de6dSgd78059 * bscv_setup_events - start event daemon etc. 4973*1c42de6dSgd78059 * 4974*1c42de6dSgd78059 * inputs - device information structure, DDI_ATTACH command 4975*1c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 4976*1c42de6dSgd78059 */ 4977*1c42de6dSgd78059 4978*1c42de6dSgd78059 static int 4979*1c42de6dSgd78059 bscv_attach_common(bscv_soft_state_t *ssp) 4980*1c42de6dSgd78059 { 4981*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 4982*1c42de6dSgd78059 4983*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_attach_common:", ""); 4984*1c42de6dSgd78059 4985*1c42de6dSgd78059 /* 4986*1c42de6dSgd78059 * Set the threshold for reporting messages to the console to 4987*1c42de6dSgd78059 * Warnings or higher. 4988*1c42de6dSgd78059 */ 4989*1c42de6dSgd78059 ssp->reporting_level = 2; 4990*1c42de6dSgd78059 4991*1c42de6dSgd78059 /* 4992*1c42de6dSgd78059 * When the system is not running the Operating System, make 4993*1c42de6dSgd78059 * the microcontroller print event messages straight onto the 4994*1c42de6dSgd78059 * console. 4995*1c42de6dSgd78059 */ 4996*1c42de6dSgd78059 ssp->serial_reporting = LOM_SER_EVENTS_DEF; 4997*1c42de6dSgd78059 4998*1c42de6dSgd78059 /* Setup capabilities */ 4999*1c42de6dSgd78059 bscv_setup_capability(ssp); 5000*1c42de6dSgd78059 5001*1c42de6dSgd78059 if (bscv_probe_check(ssp) == DDI_FAILURE) { 5002*1c42de6dSgd78059 cmn_err(CE_WARN, "BSC chip not responding"); 5003*1c42de6dSgd78059 /* 5004*1c42de6dSgd78059 * We want lom -G to talk to this driver upon broken firmware 5005*1c42de6dSgd78059 * so we prematurely return success here. 5006*1c42de6dSgd78059 */ 5007*1c42de6dSgd78059 return (DDI_SUCCESS); 5008*1c42de6dSgd78059 } 5009*1c42de6dSgd78059 5010*1c42de6dSgd78059 bscv_setup_hostname(ssp); 5011*1c42de6dSgd78059 bscv_setup_static_info(ssp); 5012*1c42de6dSgd78059 bscv_setup_events(ssp); 5013*1c42de6dSgd78059 5014*1c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 5015*1c42de6dSgd78059 bscv_inform_bsc(ssp, BSC_INFORM_ONLINE); 5016*1c42de6dSgd78059 #endif /* __i386 || __amd64 */ 5017*1c42de6dSgd78059 /* 5018*1c42de6dSgd78059 * Watchdog configuration and CPU signatures are sent asynchronously 5019*1c42de6dSgd78059 * with respect to attach so only inform the BSC if we've already 5020*1c42de6dSgd78059 * sent the data in the past. 5021*1c42de6dSgd78059 */ 5022*1c42de6dSgd78059 5023*1c42de6dSgd78059 if (ssp->progress & BSCV_WDOG_CFG) 5024*1c42de6dSgd78059 bscv_setup_watchdog(ssp); 5025*1c42de6dSgd78059 5026*1c42de6dSgd78059 #ifdef __sparc 5027*1c42de6dSgd78059 if (ssp->progress & BSCV_SIG_SENT) 5028*1c42de6dSgd78059 bscv_write_sig(ssp, ssp->last_sig); 5029*1c42de6dSgd78059 #endif /* __sparc */ 5030*1c42de6dSgd78059 5031*1c42de6dSgd78059 return (DDI_SUCCESS); 5032*1c42de6dSgd78059 } 5033*1c42de6dSgd78059 5034*1c42de6dSgd78059 /* 5035*1c42de6dSgd78059 * function - bscv_cleanup 5036*1c42de6dSgd78059 * description - routine that does the necessary tidying up if the attach 5037*1c42de6dSgd78059 * request fails or the driver is to be detached. 5038*1c42de6dSgd78059 * If the event thread has been started we may fail to 5039*1c42de6dSgd78059 * stop it (because it is busy) so we fail the cleanup 5040*1c42de6dSgd78059 * and hence the detach. All other calls to bscv_cleanup 5041*1c42de6dSgd78059 * are done before the event daemon is started. 5042*1c42de6dSgd78059 * inputs - soft state structure address. 5043*1c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE. 5044*1c42de6dSgd78059 */ 5045*1c42de6dSgd78059 5046*1c42de6dSgd78059 static int 5047*1c42de6dSgd78059 bscv_cleanup(bscv_soft_state_t *ssp) 5048*1c42de6dSgd78059 { 5049*1c42de6dSgd78059 int instance; 5050*1c42de6dSgd78059 uint8_t bits2set; 5051*1c42de6dSgd78059 uint8_t bits2clear; 5052*1c42de6dSgd78059 5053*1c42de6dSgd78059 instance = ssp->instance; 5054*1c42de6dSgd78059 5055*1c42de6dSgd78059 if (ssp->progress & BSCV_LOCKS) { 5056*1c42de6dSgd78059 bscv_enter(ssp); 5057*1c42de6dSgd78059 } 5058*1c42de6dSgd78059 5059*1c42de6dSgd78059 if (ssp->progress & BSCV_THREAD) { 5060*1c42de6dSgd78059 if (bscv_stop_event_daemon(ssp) == DDI_FAILURE) { 5061*1c42de6dSgd78059 /* Fail the cleanup - may be able to cleanup later */ 5062*1c42de6dSgd78059 if (ssp->progress & BSCV_LOCKS) { 5063*1c42de6dSgd78059 bscv_exit(ssp); 5064*1c42de6dSgd78059 } 5065*1c42de6dSgd78059 return (DDI_FAILURE); 5066*1c42de6dSgd78059 } 5067*1c42de6dSgd78059 } 5068*1c42de6dSgd78059 5069*1c42de6dSgd78059 if (ssp->progress & BSCV_NODES) { 5070*1c42de6dSgd78059 ddi_remove_minor_node(ssp->dip, NULL); 5071*1c42de6dSgd78059 } 5072*1c42de6dSgd78059 5073*1c42de6dSgd78059 if (ssp->progress & BSCV_MAPPED_REGS) { 5074*1c42de6dSgd78059 /* 5075*1c42de6dSgd78059 * switch back on serial event reporting - cover all configs. 5076*1c42de6dSgd78059 */ 5077*1c42de6dSgd78059 bits2set = 0; 5078*1c42de6dSgd78059 bits2clear = 0; 5079*1c42de6dSgd78059 if (ssp->serial_reporting == LOM_SER_EVENTS_ON) { 5080*1c42de6dSgd78059 bits2clear |= EBUS_ALARM_NOEVENTS; 5081*1c42de6dSgd78059 } else if (ssp->serial_reporting == LOM_SER_EVENTS_OFF) { 5082*1c42de6dSgd78059 bits2set |= EBUS_ALARM_NOEVENTS; 5083*1c42de6dSgd78059 } else if (ssp->serial_reporting == LOM_SER_EVENTS_DEF) { 5084*1c42de6dSgd78059 bits2clear |= EBUS_ALARM_NOEVENTS; 5085*1c42de6dSgd78059 } 5086*1c42de6dSgd78059 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_ALARM, 5087*1c42de6dSgd78059 bits2set, bits2clear); 5088*1c42de6dSgd78059 5089*1c42de6dSgd78059 /* 5090*1c42de6dSgd78059 * disable the reset function if we have enabled 5091*1c42de6dSgd78059 * it. We don't want any nasty surprises like system 5092*1c42de6dSgd78059 * rebooting unexpectedly. If we timeout on the busy 5093*1c42de6dSgd78059 * flag we just have to carry on. 5094*1c42de6dSgd78059 */ 5095*1c42de6dSgd78059 5096*1c42de6dSgd78059 bscv_trace(ssp, 'W', "bscv_cleanup", 5097*1c42de6dSgd78059 "bscv_cleanup - disable wdog"); 5098*1c42de6dSgd78059 if (bscv_get8_cached(ssp, EBUS_IDX_WDOG_CTRL) & 5099*1c42de6dSgd78059 EBUS_WDOG_ENABLE) { 5100*1c42de6dSgd78059 bscv_setclear8(ssp, chan_general, EBUS_IDX_WDOG_CTRL, 5101*1c42de6dSgd78059 0, EBUS_WDOG_RST | EBUS_WDOG_ENABLE); 5102*1c42de6dSgd78059 } 5103*1c42de6dSgd78059 } 5104*1c42de6dSgd78059 5105*1c42de6dSgd78059 /* 5106*1c42de6dSgd78059 * unmap registers 5107*1c42de6dSgd78059 */ 5108*1c42de6dSgd78059 5109*1c42de6dSgd78059 if (ssp->progress & BSCV_MAPPED_REGS) { 5110*1c42de6dSgd78059 bscv_unmap_regs(ssp); 5111*1c42de6dSgd78059 } 5112*1c42de6dSgd78059 5113*1c42de6dSgd78059 /* 5114*1c42de6dSgd78059 * release any memory allocated for mutexes and condition 5115*1c42de6dSgd78059 * variables before deallocating the structures containing them 5116*1c42de6dSgd78059 */ 5117*1c42de6dSgd78059 5118*1c42de6dSgd78059 if (ssp->progress & BSCV_LOCKS) { 5119*1c42de6dSgd78059 bscv_exit(ssp); 5120*1c42de6dSgd78059 cv_destroy(&ssp->task_cv); 5121*1c42de6dSgd78059 cv_destroy(&ssp->task_evnt_cv); 5122*1c42de6dSgd78059 mutex_destroy(&ssp->task_mu); 5123*1c42de6dSgd78059 mutex_destroy(&ssp->prog_mu); 5124*1c42de6dSgd78059 mutex_destroy(&ssp->cmd_mutex); 5125*1c42de6dSgd78059 } 5126*1c42de6dSgd78059 5127*1c42de6dSgd78059 if (ssp->image != NULL) { 5128*1c42de6dSgd78059 kmem_free((void *)ssp->image, BSC_IMAGE_MAX_SIZE); 5129*1c42de6dSgd78059 } 5130*1c42de6dSgd78059 5131*1c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 5132*1c42de6dSgd78059 mutex_enter(&cpu_lock); 5133*1c42de6dSgd78059 bscv_watchdog_cyclic_remove(ssp); 5134*1c42de6dSgd78059 mutex_exit(&cpu_lock); 5135*1c42de6dSgd78059 #endif /* __i386 || __amd64 */ 5136*1c42de6dSgd78059 ddi_soft_state_free(bscv_statep, instance); 5137*1c42de6dSgd78059 5138*1c42de6dSgd78059 return (DDI_SUCCESS); 5139*1c42de6dSgd78059 } 5140*1c42de6dSgd78059 5141*1c42de6dSgd78059 /* 5142*1c42de6dSgd78059 * function - bscv_setup_capability 5143*1c42de6dSgd78059 * description - probe the lom find what capabilities are present for 5144*1c42de6dSgd78059 * us to use. 5145*1c42de6dSgd78059 * inputs - soft state ptr 5146*1c42de6dSgd78059 * outputs - returns DDI_SUCCESS or DDI_FAILURE 5147*1c42de6dSgd78059 */ 5148*1c42de6dSgd78059 static void bscv_setup_capability(bscv_soft_state_t *ssp) 5149*1c42de6dSgd78059 { 5150*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 5151*1c42de6dSgd78059 5152*1c42de6dSgd78059 if (ssp->prog_mode_only) { 5153*1c42de6dSgd78059 /* Turn off all capabilities */ 5154*1c42de6dSgd78059 ssp->cap0 = 0; 5155*1c42de6dSgd78059 ssp->cap1 = 0; 5156*1c42de6dSgd78059 ssp->cap2 = 0; 5157*1c42de6dSgd78059 return; 5158*1c42de6dSgd78059 } 5159*1c42de6dSgd78059 5160*1c42de6dSgd78059 ssp->cap0 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP0); 5161*1c42de6dSgd78059 ssp->cap1 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP1); 5162*1c42de6dSgd78059 ssp->cap2 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP2); 5163*1c42de6dSgd78059 if (!bscv_faulty(ssp)) { 5164*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_setup_capability", 5165*1c42de6dSgd78059 "Capability flags cap0=0x%x cap1=0x%x, cap2=0x%x", 5166*1c42de6dSgd78059 ssp->cap0, ssp->cap1, ssp->cap2); 5167*1c42de6dSgd78059 } else { 5168*1c42de6dSgd78059 cmn_err(CE_WARN, "!Could not read capability flags"); 5169*1c42de6dSgd78059 ssp->cap0 = 0; ssp->cap1 = 0; ssp->cap2 = 0; 5170*1c42de6dSgd78059 } 5171*1c42de6dSgd78059 } 5172*1c42de6dSgd78059 5173*1c42de6dSgd78059 /* 5174*1c42de6dSgd78059 * function - bscv_probe_check 5175*1c42de6dSgd78059 * description - probe the lom to check for correct operation 5176*1c42de6dSgd78059 * has a side effect of setting up the cached registers and 5177*1c42de6dSgd78059 * updates ssp->prog_mode_only. 5178*1c42de6dSgd78059 * inputs - soft state ptr 5179*1c42de6dSgd78059 * outputs - returns DDI_SUCCESS or DDI_FAILURE 5180*1c42de6dSgd78059 */ 5181*1c42de6dSgd78059 5182*1c42de6dSgd78059 static int bscv_probe_check(bscv_soft_state_t *ssp) 5183*1c42de6dSgd78059 { 5184*1c42de6dSgd78059 int i; 5185*1c42de6dSgd78059 uint8_t probeval; 5186*1c42de6dSgd78059 5187*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 5188*1c42de6dSgd78059 5189*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_probe_check", ""); 5190*1c42de6dSgd78059 5191*1c42de6dSgd78059 if (!ssp->prog_mode_only) { 5192*1c42de6dSgd78059 /* 5193*1c42de6dSgd78059 * Make sure probe location is OK so that we are 5194*1c42de6dSgd78059 * in sync. 5195*1c42de6dSgd78059 * We want to make sure that this is not faulty so we 5196*1c42de6dSgd78059 * do a bscv_clear_fault to clear any existing 5197*1c42de6dSgd78059 * fault records down. 5198*1c42de6dSgd78059 */ 5199*1c42de6dSgd78059 bscv_clear_fault(ssp); 5200*1c42de6dSgd78059 probeval = bscv_get8(ssp, chan_general, EBUS_IDX_PROBEAA); 5201*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 5202*1c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 5203*1c42de6dSgd78059 } else if (probeval != 0xAA) { 5204*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_probe_check", 5205*1c42de6dSgd78059 "LOMlite out of sync"); 5206*1c42de6dSgd78059 5207*1c42de6dSgd78059 /* 5208*1c42de6dSgd78059 * It may be that the LOMlite was out of 5209*1c42de6dSgd78059 * sync so lets try the read again. 5210*1c42de6dSgd78059 */ 5211*1c42de6dSgd78059 probeval = bscv_get8(ssp, chan_general, 5212*1c42de6dSgd78059 EBUS_IDX_PROBEAA); 5213*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 5214*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_probe_check", 5215*1c42de6dSgd78059 "Init readAA1 failed"); 5216*1c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 5217*1c42de6dSgd78059 } else if (probeval != 0xAA) { 5218*1c42de6dSgd78059 /* 5219*1c42de6dSgd78059 * OK that is twice we are out so I 5220*1c42de6dSgd78059 * guess the LOMlite is in trouble 5221*1c42de6dSgd78059 */ 5222*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_probe_check", 5223*1c42de6dSgd78059 "Init readAA probe failed - got 0x%x", 5224*1c42de6dSgd78059 probeval); 5225*1c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 5226*1c42de6dSgd78059 } 5227*1c42de6dSgd78059 } 5228*1c42de6dSgd78059 } 5229*1c42de6dSgd78059 5230*1c42de6dSgd78059 /* 5231*1c42de6dSgd78059 * Read in all page zero lom registers. 5232*1c42de6dSgd78059 * Read state change 1st so we dont miss anything and clear it. 5233*1c42de6dSgd78059 * Note: we discard the values because we rely on bscv_get8 to 5234*1c42de6dSgd78059 * setup the cache of register values. 5235*1c42de6dSgd78059 */ 5236*1c42de6dSgd78059 5237*1c42de6dSgd78059 if (!ssp->prog_mode_only) { 5238*1c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_STATE_CHNG); 5239*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 5240*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_probe_check", 5241*1c42de6dSgd78059 "Read of state change register failed"); 5242*1c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 5243*1c42de6dSgd78059 } 5244*1c42de6dSgd78059 } 5245*1c42de6dSgd78059 5246*1c42de6dSgd78059 if (!ssp->prog_mode_only) { 5247*1c42de6dSgd78059 for (i = 1; i < 0x80; i++) { 5248*1c42de6dSgd78059 switch (i) { 5249*1c42de6dSgd78059 case EBUS_IDX_STATE_CHNG: 5250*1c42de6dSgd78059 case EBUS_IDX_CMD_RES: 5251*1c42de6dSgd78059 case EBUS_IDX_HNAME_CHAR: 5252*1c42de6dSgd78059 /* 5253*1c42de6dSgd78059 * Should not read these - they have side 5254*1c42de6dSgd78059 * effects. 5255*1c42de6dSgd78059 */ 5256*1c42de6dSgd78059 break; 5257*1c42de6dSgd78059 default: 5258*1c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, i); 5259*1c42de6dSgd78059 break; 5260*1c42de6dSgd78059 } 5261*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 5262*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_probe_check", 5263*1c42de6dSgd78059 "Initial read or register %2x failed", i); 5264*1c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 5265*1c42de6dSgd78059 /* Might as well give up now! */ 5266*1c42de6dSgd78059 break; 5267*1c42de6dSgd78059 } 5268*1c42de6dSgd78059 } 5269*1c42de6dSgd78059 } 5270*1c42de6dSgd78059 5271*1c42de6dSgd78059 /* 5272*1c42de6dSgd78059 * Check the probe keys so we know the lom is OK 5273*1c42de6dSgd78059 */ 5274*1c42de6dSgd78059 5275*1c42de6dSgd78059 if (!ssp->prog_mode_only) { 5276*1c42de6dSgd78059 if ((bscv_get8_cached(ssp, EBUS_IDX_PROBE55) != 0x55) || 5277*1c42de6dSgd78059 (bscv_get8_cached(ssp, EBUS_IDX_PROBEAA) != 0xAA)) { 5278*1c42de6dSgd78059 5279*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_probe_check", 5280*1c42de6dSgd78059 "LOMlite Probe failed"); 5281*1c42de6dSgd78059 for (i = 0; i < 0x8; i++) { 5282*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_probe_check", 5283*1c42de6dSgd78059 "%2x %2x %2x %2x %2x %2x %2x %2x %2x " 5284*1c42de6dSgd78059 "%2x %2x %2x %2x %2x %2x %2x %2x %2x", 5285*1c42de6dSgd78059 bscv_get8_cached(ssp, i), 5286*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 1), 5287*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 2), 5288*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 3), 5289*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 4), 5290*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 5), 5291*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 6), 5292*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 7), 5293*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 8), 5294*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 9), 5295*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 10), 5296*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 11), 5297*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 12), 5298*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 13), 5299*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 14), 5300*1c42de6dSgd78059 bscv_get8_cached(ssp, i + 15)); 5301*1c42de6dSgd78059 } 5302*1c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 5303*1c42de6dSgd78059 } 5304*1c42de6dSgd78059 } 5305*1c42de6dSgd78059 5306*1c42de6dSgd78059 return ((ssp->prog_mode_only == B_FALSE) ? DDI_SUCCESS : DDI_FAILURE); 5307*1c42de6dSgd78059 } 5308*1c42de6dSgd78059 5309*1c42de6dSgd78059 #ifdef __sparc 5310*1c42de6dSgd78059 /* 5311*1c42de6dSgd78059 * function - bscv_idi_set 5312*1c42de6dSgd78059 * description - bscv inter driver interface set function 5313*1c42de6dSgd78059 * inputs - structure which defines type of service required and data 5314*1c42de6dSgd78059 * ouputs - none 5315*1c42de6dSgd78059 * 5316*1c42de6dSgd78059 * This is the Entry Point function for the platmod driver. It works out which 5317*1c42de6dSgd78059 * X Bus channel ought to deliver the service requested. 5318*1c42de6dSgd78059 */ 5319*1c42de6dSgd78059 void 5320*1c42de6dSgd78059 bscv_idi_set(struct bscv_idi_info info) 5321*1c42de6dSgd78059 { 5322*1c42de6dSgd78059 struct bscv_idi_callout *tbl; 5323*1c42de6dSgd78059 boolean_t retval; 5324*1c42de6dSgd78059 5325*1c42de6dSgd78059 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC); 5326*1c42de6dSgd78059 5327*1c42de6dSgd78059 if (bscv_idi_mgr.tbl == NULL) { 5328*1c42de6dSgd78059 if (bscv_idi_err()) 5329*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_idi_set : cannot find " 5330*1c42de6dSgd78059 "bscv_callout_table"); 5331*1c42de6dSgd78059 return; 5332*1c42de6dSgd78059 } else if (bscv_idi_mgr.valid_inst == (uint32_t)~0) { 5333*1c42de6dSgd78059 if (bscv_idi_err()) 5334*1c42de6dSgd78059 /* 5335*1c42de6dSgd78059 * This error message can appear in the context of 5336*1c42de6dSgd78059 * another driver, say platmod or todblade. We want 5337*1c42de6dSgd78059 * to clearly indicate the culprit driver so put in 5338*1c42de6dSgd78059 * the driver name. 5339*1c42de6dSgd78059 */ 5340*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_idi_set : no valid " 5341*1c42de6dSgd78059 "driver instance of " 5342*1c42de6dSgd78059 MYNAME); 5343*1c42de6dSgd78059 return; 5344*1c42de6dSgd78059 } 5345*1c42de6dSgd78059 5346*1c42de6dSgd78059 tbl = bscv_idi_mgr.tbl; 5347*1c42de6dSgd78059 5348*1c42de6dSgd78059 while (tbl->type != BSCV_IDI_NULL) { 5349*1c42de6dSgd78059 if (tbl->type == info.type) { 5350*1c42de6dSgd78059 /* 5351*1c42de6dSgd78059 * We service the request with a valid instance number 5352*1c42de6dSgd78059 * for the driver. 5353*1c42de6dSgd78059 */ 5354*1c42de6dSgd78059 retval = ((tbl->fn) (info)); 5355*1c42de6dSgd78059 5356*1c42de6dSgd78059 /* 5357*1c42de6dSgd78059 * If the request was serviced, clear any accumulated 5358*1c42de6dSgd78059 * error counters so future warnings will be reported if 5359*1c42de6dSgd78059 * seen. 5360*1c42de6dSgd78059 */ 5361*1c42de6dSgd78059 if (retval == B_TRUE) 5362*1c42de6dSgd78059 bscv_idi_clear_err(); 5363*1c42de6dSgd78059 return; 5364*1c42de6dSgd78059 } else { 5365*1c42de6dSgd78059 tbl++; 5366*1c42de6dSgd78059 } 5367*1c42de6dSgd78059 } 5368*1c42de6dSgd78059 5369*1c42de6dSgd78059 if (bscv_idi_err()) 5370*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_idi_set : cannot match info.type %d", 5371*1c42de6dSgd78059 info.type); 5372*1c42de6dSgd78059 } 5373*1c42de6dSgd78059 5374*1c42de6dSgd78059 /* 5375*1c42de6dSgd78059 * function - bscv_nodename_set 5376*1c42de6dSgd78059 * description - notify the event thread that a nodename change has occurred. 5377*1c42de6dSgd78059 * inputs - data from client driver 5378*1c42de6dSgd78059 * outputs - none. 5379*1c42de6dSgd78059 * side-effects - the event thread will schedule an update to the lom firmware. 5380*1c42de6dSgd78059 */ 5381*1c42de6dSgd78059 /*ARGSUSED*/ 5382*1c42de6dSgd78059 static boolean_t 5383*1c42de6dSgd78059 bscv_nodename_set(struct bscv_idi_info info) 5384*1c42de6dSgd78059 { 5385*1c42de6dSgd78059 bscv_soft_state_t *ssp; 5386*1c42de6dSgd78059 5387*1c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst); 5388*1c42de6dSgd78059 5389*1c42de6dSgd78059 if (ssp == NULL) { 5390*1c42de6dSgd78059 if (bscv_idi_err()) 5391*1c42de6dSgd78059 cmn_err(CE_WARN, "!blade_nodename_set: cannot get ssp"); 5392*1c42de6dSgd78059 return (B_FALSE); 5393*1c42de6dSgd78059 } 5394*1c42de6dSgd78059 5395*1c42de6dSgd78059 /* Get a lock on the SSP, notify our change, then exit */ 5396*1c42de6dSgd78059 mutex_enter(&ssp->task_mu); 5397*1c42de6dSgd78059 ssp->nodename_change = B_TRUE; 5398*1c42de6dSgd78059 cv_signal(&ssp->task_cv); 5399*1c42de6dSgd78059 mutex_exit(&ssp->task_mu); 5400*1c42de6dSgd78059 5401*1c42de6dSgd78059 return (B_TRUE); 5402*1c42de6dSgd78059 } 5403*1c42de6dSgd78059 5404*1c42de6dSgd78059 /* 5405*1c42de6dSgd78059 * function - bscv_sig_set 5406*1c42de6dSgd78059 * description - write a signature 5407*1c42de6dSgd78059 * inputs - data from client driver 5408*1c42de6dSgd78059 * outputs - none. 5409*1c42de6dSgd78059 */ 5410*1c42de6dSgd78059 static boolean_t 5411*1c42de6dSgd78059 bscv_sig_set(struct bscv_idi_info info) 5412*1c42de6dSgd78059 { 5413*1c42de6dSgd78059 bscv_soft_state_t *ssp; 5414*1c42de6dSgd78059 bscv_sig_t sig; 5415*1c42de6dSgd78059 5416*1c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst); 5417*1c42de6dSgd78059 5418*1c42de6dSgd78059 if (ssp == NULL) { 5419*1c42de6dSgd78059 if (bscv_idi_err()) 5420*1c42de6dSgd78059 cmn_err(CE_WARN, "!blade_nodename_set: cannot get ssp"); 5421*1c42de6dSgd78059 return (B_FALSE); 5422*1c42de6dSgd78059 } 5423*1c42de6dSgd78059 5424*1c42de6dSgd78059 /* Service the request */ 5425*1c42de6dSgd78059 bcopy(info.data, &sig, sizeof (sig)); 5426*1c42de6dSgd78059 bscv_enter(ssp); 5427*1c42de6dSgd78059 bscv_write_sig(ssp, sig); 5428*1c42de6dSgd78059 bscv_exit(ssp); 5429*1c42de6dSgd78059 5430*1c42de6dSgd78059 return (B_TRUE); 5431*1c42de6dSgd78059 } 5432*1c42de6dSgd78059 #endif /* __sparc */ 5433*1c42de6dSgd78059 5434*1c42de6dSgd78059 static void 5435*1c42de6dSgd78059 bscv_wdog_do_pat(bscv_soft_state_t *ssp) 5436*1c42de6dSgd78059 { 5437*1c42de6dSgd78059 uint8_t pat; 5438*1c42de6dSgd78059 5439*1c42de6dSgd78059 /* 5440*1c42de6dSgd78059 * The value of the dog pat is a sequence number which wraps around, 5441*1c42de6dSgd78059 * bounded by BSCV_WDOG_PAT_SEQ_MASK. 5442*1c42de6dSgd78059 */ 5443*1c42de6dSgd78059 pat = ssp->pat_seq++; 5444*1c42de6dSgd78059 pat &= EBUS_WDOG_NB_PAT_SEQ_MASK; 5445*1c42de6dSgd78059 5446*1c42de6dSgd78059 /* Set top nibble to indicate a pat */ 5447*1c42de6dSgd78059 pat |= EBUS_WDOG_NB_PAT; 5448*1c42de6dSgd78059 5449*1c42de6dSgd78059 /* 5450*1c42de6dSgd78059 * Now pat the dog. This exercises a special protocol in the 5451*1c42de6dSgd78059 * bus nexus that offers : non-blocking IO, and timely delivery, 5452*1c42de6dSgd78059 * callable from high-level interrupt context. The requirement 5453*1c42de6dSgd78059 * on us is that the channel is not shared for any other use. 5454*1c42de6dSgd78059 * This means for chan_wdogpat, nothing may use channel[chan].regs 5455*1c42de6dSgd78059 * or channel.[chan].handle. 5456*1c42de6dSgd78059 */ 5457*1c42de6dSgd78059 5458*1c42de6dSgd78059 ddi_put8(ssp->channel[chan_wdogpat].handle, 5459*1c42de6dSgd78059 ssp->channel[chan_wdogpat].regs, pat); 5460*1c42de6dSgd78059 5461*1c42de6dSgd78059 bscv_trace(ssp, 'W', "bscv_wdog_pat", "patted the dog with seq %d", 5462*1c42de6dSgd78059 pat); 5463*1c42de6dSgd78059 } 5464*1c42de6dSgd78059 5465*1c42de6dSgd78059 #ifdef __sparc 5466*1c42de6dSgd78059 /* 5467*1c42de6dSgd78059 * function - bscv_wdog_pat 5468*1c42de6dSgd78059 * description - pat the watchdog 5469*1c42de6dSgd78059 * inputs - data from client driver 5470*1c42de6dSgd78059 * outputs - none. 5471*1c42de6dSgd78059 */ 5472*1c42de6dSgd78059 /*ARGSUSED*/ 5473*1c42de6dSgd78059 static boolean_t 5474*1c42de6dSgd78059 bscv_wdog_pat(struct bscv_idi_info info) 5475*1c42de6dSgd78059 { 5476*1c42de6dSgd78059 /* 5477*1c42de6dSgd78059 * This function remembers if it has ever been called with the 5478*1c42de6dSgd78059 * configure option set. 5479*1c42de6dSgd78059 */ 5480*1c42de6dSgd78059 bscv_soft_state_t *ssp; 5481*1c42de6dSgd78059 5482*1c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst); 5483*1c42de6dSgd78059 5484*1c42de6dSgd78059 if (ssp == NULL) { 5485*1c42de6dSgd78059 if (bscv_idi_err()) 5486*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_wdog_pat: cannot get ssp"); 5487*1c42de6dSgd78059 return (B_FALSE); 5488*1c42de6dSgd78059 } else if (ssp->nchannels == 0) { 5489*1c42de6dSgd78059 /* Didn't manage to map handles so ddi_{get,put}* broken */ 5490*1c42de6dSgd78059 if (bscv_idi_err()) 5491*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_wdog_pat: handle not mapped"); 5492*1c42de6dSgd78059 return (B_FALSE); 5493*1c42de6dSgd78059 } 5494*1c42de6dSgd78059 5495*1c42de6dSgd78059 bscv_wdog_do_pat(ssp); 5496*1c42de6dSgd78059 return (B_TRUE); 5497*1c42de6dSgd78059 } 5498*1c42de6dSgd78059 5499*1c42de6dSgd78059 /* 5500*1c42de6dSgd78059 * function - bscv_wdog_cfg 5501*1c42de6dSgd78059 * description - configure the watchdog 5502*1c42de6dSgd78059 * inputs - data from client driver 5503*1c42de6dSgd78059 * outputs - none. 5504*1c42de6dSgd78059 */ 5505*1c42de6dSgd78059 static boolean_t 5506*1c42de6dSgd78059 bscv_wdog_cfg(struct bscv_idi_info info) 5507*1c42de6dSgd78059 { 5508*1c42de6dSgd78059 bscv_soft_state_t *ssp; 5509*1c42de6dSgd78059 5510*1c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst); 5511*1c42de6dSgd78059 5512*1c42de6dSgd78059 if (ssp == NULL) { 5513*1c42de6dSgd78059 if (bscv_idi_err()) 5514*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_wdog_cfg: cannot get ssp"); 5515*1c42de6dSgd78059 return (B_FALSE); 5516*1c42de6dSgd78059 } else if (ssp->nchannels == 0) { 5517*1c42de6dSgd78059 /* Didn't manage to map handles so ddi_{get,put}* broken */ 5518*1c42de6dSgd78059 if (bscv_idi_err()) 5519*1c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_wdog_cfg: handle not mapped"); 5520*1c42de6dSgd78059 return (B_FALSE); 5521*1c42de6dSgd78059 } 5522*1c42de6dSgd78059 5523*1c42de6dSgd78059 if (sizeof (bscv_wdog_t) != info.size) { 5524*1c42de6dSgd78059 bscv_trace(ssp, 'W', "bscv_wdog_set", "data passed in is size" 5525*1c42de6dSgd78059 " %d instead of %d", info.size, 5526*1c42de6dSgd78059 sizeof (bscv_wdog_t)); 5527*1c42de6dSgd78059 return (B_FALSE); 5528*1c42de6dSgd78059 } 5529*1c42de6dSgd78059 5530*1c42de6dSgd78059 bscv_trace(ssp, 'W', "bscv_wdog_cfg", "enable_wdog %s, " 5531*1c42de6dSgd78059 "wdog_timeout_s %d, reset_system_on_timeout %s", 5532*1c42de6dSgd78059 ((bscv_wdog_t *)info.data)->enable_wdog ? "enabled" : "disabled", 5533*1c42de6dSgd78059 ((bscv_wdog_t *)info.data)->wdog_timeout_s, 5534*1c42de6dSgd78059 ((bscv_wdog_t *)info.data)->reset_system_on_timeout ? "yes" : "no"); 5535*1c42de6dSgd78059 bscv_write_wdog_cfg(ssp, 5536*1c42de6dSgd78059 ((bscv_wdog_t *)info.data)->wdog_timeout_s, 5537*1c42de6dSgd78059 ((bscv_wdog_t *)info.data)->enable_wdog, 5538*1c42de6dSgd78059 ((bscv_wdog_t *)info.data)->reset_system_on_timeout); 5539*1c42de6dSgd78059 return (B_TRUE); 5540*1c42de6dSgd78059 } 5541*1c42de6dSgd78059 #endif /* __sparc */ 5542*1c42de6dSgd78059 5543*1c42de6dSgd78059 static void 5544*1c42de6dSgd78059 bscv_write_wdog_cfg(bscv_soft_state_t *ssp, 5545*1c42de6dSgd78059 uint_t wdog_timeout_s, 5546*1c42de6dSgd78059 boolean_t enable_wdog, 5547*1c42de6dSgd78059 uint8_t reset_system_on_timeout) 5548*1c42de6dSgd78059 { 5549*1c42de6dSgd78059 uint8_t cfg = EBUS_WDOG_NB_CFG; 5550*1c42de6dSgd78059 5551*1c42de6dSgd78059 /* 5552*1c42de6dSgd78059 * Configure the timeout value (1 to 127 seconds). 5553*1c42de6dSgd78059 * Note that a policy is implemented at the bsc/ssp which bounds 5554*1c42de6dSgd78059 * the value further. The bounding here is to fit the timeout value 5555*1c42de6dSgd78059 * into the 7 bits the bsc uses. 5556*1c42de6dSgd78059 */ 5557*1c42de6dSgd78059 if (wdog_timeout_s < 1) 5558*1c42de6dSgd78059 ssp->watchdog_timeout = 1; 5559*1c42de6dSgd78059 else if (wdog_timeout_s > 127) 5560*1c42de6dSgd78059 ssp->watchdog_timeout = 127; 5561*1c42de6dSgd78059 else 5562*1c42de6dSgd78059 ssp->watchdog_timeout = wdog_timeout_s; 5563*1c42de6dSgd78059 5564*1c42de6dSgd78059 /* 5565*1c42de6dSgd78059 * Configure the watchdog on or off. 5566*1c42de6dSgd78059 */ 5567*1c42de6dSgd78059 if (enable_wdog) 5568*1c42de6dSgd78059 cfg |= EBUS_WDOG_NB_CFG_ENB; 5569*1c42de6dSgd78059 else 5570*1c42de6dSgd78059 cfg &= ~EBUS_WDOG_NB_CFG_ENB; 5571*1c42de6dSgd78059 5572*1c42de6dSgd78059 /* 5573*1c42de6dSgd78059 * Configure whether the microcontroller should reset the system when 5574*1c42de6dSgd78059 * the watchdog expires. 5575*1c42de6dSgd78059 */ 5576*1c42de6dSgd78059 ssp->watchdog_reset_on_timeout = reset_system_on_timeout; 5577*1c42de6dSgd78059 5578*1c42de6dSgd78059 ddi_put8(ssp->channel[chan_wdogpat].handle, 5579*1c42de6dSgd78059 ssp->channel[chan_wdogpat].regs, cfg); 5580*1c42de6dSgd78059 5581*1c42de6dSgd78059 /* have the event daemon set the timeout value and whether to reset */ 5582*1c42de6dSgd78059 ssp->watchdog_change = B_TRUE; 5583*1c42de6dSgd78059 5584*1c42de6dSgd78059 bscv_trace(ssp, 'W', "bscv_wdog_cfg", 5585*1c42de6dSgd78059 "configured the dog with cfg 0x%x", cfg); 5586*1c42de6dSgd78059 } 5587*1c42de6dSgd78059 5588*1c42de6dSgd78059 /* 5589*1c42de6dSgd78059 * function - bscv_setup_watchdog 5590*1c42de6dSgd78059 * description - setup the bsc watchdog 5591*1c42de6dSgd78059 * inputs - soft state ptr 5592*1c42de6dSgd78059 * outputs - 5593*1c42de6dSgd78059 */ 5594*1c42de6dSgd78059 static void bscv_setup_watchdog(bscv_soft_state_t *ssp) 5595*1c42de6dSgd78059 { 5596*1c42de6dSgd78059 uint8_t set = 0; 5597*1c42de6dSgd78059 uint8_t clear = 0; 5598*1c42de6dSgd78059 #ifdef __sparc 5599*1c42de6dSgd78059 extern int watchdog_activated; 5600*1c42de6dSgd78059 #endif /* __sparc */ 5601*1c42de6dSgd78059 5602*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 5603*1c42de6dSgd78059 5604*1c42de6dSgd78059 /* Set the timeout */ 5605*1c42de6dSgd78059 bscv_put8(ssp, chan_general, 5606*1c42de6dSgd78059 EBUS_IDX_WDOG_TIME, ssp->watchdog_timeout); 5607*1c42de6dSgd78059 5608*1c42de6dSgd78059 /* Set whether to reset the system on timeout */ 5609*1c42de6dSgd78059 if (ssp->watchdog_reset_on_timeout) { 5610*1c42de6dSgd78059 set |= EBUS_WDOG_RST; 5611*1c42de6dSgd78059 } else { 5612*1c42de6dSgd78059 clear |= EBUS_WDOG_RST; 5613*1c42de6dSgd78059 } 5614*1c42de6dSgd78059 5615*1c42de6dSgd78059 if (watchdog_activated) { 5616*1c42de6dSgd78059 set |= EBUS_WDOG_ENABLE; 5617*1c42de6dSgd78059 } else { 5618*1c42de6dSgd78059 clear |= EBUS_WDOG_ENABLE; 5619*1c42de6dSgd78059 } 5620*1c42de6dSgd78059 5621*1c42de6dSgd78059 /* Set other host defaults */ 5622*1c42de6dSgd78059 clear |= (EBUS_WDOG_BREAK_DISABLE | EBUS_WDOG_AL3_FANPSU 5623*1c42de6dSgd78059 | EBUS_WDOG_AL3_WDOG); 5624*1c42de6dSgd78059 5625*1c42de6dSgd78059 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_WDOG_CTRL, 5626*1c42de6dSgd78059 set, clear); 5627*1c42de6dSgd78059 5628*1c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 5629*1c42de6dSgd78059 /* start the cyclic based watchdog patter */ 5630*1c42de6dSgd78059 mutex_enter(&cpu_lock); 5631*1c42de6dSgd78059 bscv_watchdog_cyclic_add(ssp); 5632*1c42de6dSgd78059 mutex_exit(&cpu_lock); 5633*1c42de6dSgd78059 #endif /* __i386 || __amd64 */ 5634*1c42de6dSgd78059 ssp->progress |= BSCV_WDOG_CFG; 5635*1c42de6dSgd78059 } 5636*1c42de6dSgd78059 5637*1c42de6dSgd78059 5638*1c42de6dSgd78059 /* 5639*1c42de6dSgd78059 * function - bscv_setup_hostname 5640*1c42de6dSgd78059 * description - setup the lom hostname if different from the nodename 5641*1c42de6dSgd78059 * inputs - soft state ptr 5642*1c42de6dSgd78059 * outputs - none 5643*1c42de6dSgd78059 */ 5644*1c42de6dSgd78059 5645*1c42de6dSgd78059 static void bscv_setup_hostname(bscv_soft_state_t *ssp) 5646*1c42de6dSgd78059 { 5647*1c42de6dSgd78059 char host_nodename[128]; 5648*1c42de6dSgd78059 char lom_nodename[128]; 5649*1c42de6dSgd78059 size_t hostlen; 5650*1c42de6dSgd78059 size_t nodelen; 5651*1c42de6dSgd78059 5652*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 5653*1c42de6dSgd78059 5654*1c42de6dSgd78059 /* 5655*1c42de6dSgd78059 * Check machine label is the same as the 5656*1c42de6dSgd78059 * system nodename. 5657*1c42de6dSgd78059 */ 5658*1c42de6dSgd78059 (void) strncpy(host_nodename, utsname.nodename, 5659*1c42de6dSgd78059 sizeof (host_nodename)); 5660*1c42de6dSgd78059 5661*1c42de6dSgd78059 /* read in lom hostname */ 5662*1c42de6dSgd78059 bscv_read_hostname(ssp, lom_nodename); 5663*1c42de6dSgd78059 5664*1c42de6dSgd78059 /* Enforce null termination */ 5665*1c42de6dSgd78059 host_nodename[sizeof (host_nodename) - 1] = '\0'; 5666*1c42de6dSgd78059 lom_nodename[sizeof (lom_nodename) - 1] = '\0'; 5667*1c42de6dSgd78059 5668*1c42de6dSgd78059 hostlen = (size_t)bscv_get8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH); 5669*1c42de6dSgd78059 nodelen = (size_t)strlen(host_nodename); 5670*1c42de6dSgd78059 if ((nodelen > 0) && 5671*1c42de6dSgd78059 ((hostlen != nodelen) || (strcmp((const char *)&lom_nodename, 5672*1c42de6dSgd78059 (const char *)&host_nodename)) || 5673*1c42de6dSgd78059 (hostlen == 0))) { 5674*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_setup_hostname", 5675*1c42de6dSgd78059 "nodename(%s,%d) != bsc label(%s,%d)", 5676*1c42de6dSgd78059 host_nodename, nodelen, lom_nodename, hostlen); 5677*1c42de6dSgd78059 5678*1c42de6dSgd78059 /* Write new label into LOM EEPROM */ 5679*1c42de6dSgd78059 bscv_write_hostname(ssp, 5680*1c42de6dSgd78059 host_nodename, 5681*1c42de6dSgd78059 (uint8_t)strlen(host_nodename)); 5682*1c42de6dSgd78059 } 5683*1c42de6dSgd78059 5684*1c42de6dSgd78059 ssp->progress |= BSCV_HOSTNAME_DONE; 5685*1c42de6dSgd78059 } 5686*1c42de6dSgd78059 5687*1c42de6dSgd78059 /* 5688*1c42de6dSgd78059 * function - bscv_read_hostname 5689*1c42de6dSgd78059 * description - read the current hostname from the lom 5690*1c42de6dSgd78059 * inputs - soft state pointer and buffer to store the hostname in. 5691*1c42de6dSgd78059 * outputs - none 5692*1c42de6dSgd78059 */ 5693*1c42de6dSgd78059 5694*1c42de6dSgd78059 static void 5695*1c42de6dSgd78059 bscv_read_hostname(bscv_soft_state_t *ssp, char *lom_nodename) 5696*1c42de6dSgd78059 { 5697*1c42de6dSgd78059 int num_failures; 5698*1c42de6dSgd78059 boolean_t needretry; 5699*1c42de6dSgd78059 int length; 5700*1c42de6dSgd78059 int i; 5701*1c42de6dSgd78059 5702*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 5703*1c42de6dSgd78059 5704*1c42de6dSgd78059 /* 5705*1c42de6dSgd78059 * We have a special failure case here because a retry of a read 5706*1c42de6dSgd78059 * causes data to be lost. Thus we handle the retries ourselves 5707*1c42de6dSgd78059 * and are also responsible for detemining if the lom is faulty 5708*1c42de6dSgd78059 */ 5709*1c42de6dSgd78059 for (num_failures = 0; 5710*1c42de6dSgd78059 num_failures < BSC_FAILURE_RETRY_LIMIT; 5711*1c42de6dSgd78059 num_failures++) { 5712*1c42de6dSgd78059 bscv_clear_fault(ssp); 5713*1c42de6dSgd78059 length = bscv_get8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH); 5714*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 5715*1c42de6dSgd78059 needretry = 1; 5716*1c42de6dSgd78059 } else { 5717*1c42de6dSgd78059 needretry = 0; 5718*1c42de6dSgd78059 for (i = 0; i < length; i++) { 5719*1c42de6dSgd78059 lom_nodename[i] = bscv_get8_once(ssp, 5720*1c42de6dSgd78059 chan_general, EBUS_IDX_HNAME_CHAR); 5721*1c42de6dSgd78059 /* Retry on any error */ 5722*1c42de6dSgd78059 if (bscv_retcode(ssp) != 0) { 5723*1c42de6dSgd78059 needretry = 1; 5724*1c42de6dSgd78059 break; 5725*1c42de6dSgd78059 } 5726*1c42de6dSgd78059 } 5727*1c42de6dSgd78059 /* null terminate for strcmp later */ 5728*1c42de6dSgd78059 lom_nodename[length] = '\0'; 5729*1c42de6dSgd78059 } 5730*1c42de6dSgd78059 if (!needretry) { 5731*1c42de6dSgd78059 break; 5732*1c42de6dSgd78059 } 5733*1c42de6dSgd78059 /* Force the nodename to be empty */ 5734*1c42de6dSgd78059 lom_nodename[0] = '\0'; 5735*1c42de6dSgd78059 } 5736*1c42de6dSgd78059 5737*1c42de6dSgd78059 if (needretry) { 5738*1c42de6dSgd78059 /* Failure - we ran out of retries */ 5739*1c42de6dSgd78059 cmn_err(CE_WARN, 5740*1c42de6dSgd78059 "bscv_read_hostname: retried %d times, giving up", 5741*1c42de6dSgd78059 num_failures); 5742*1c42de6dSgd78059 ssp->had_fault = B_TRUE; 5743*1c42de6dSgd78059 } else if (num_failures > 0) { 5744*1c42de6dSgd78059 bscv_trace(ssp, 'R', "bscv_read_hostname", 5745*1c42de6dSgd78059 "retried %d times, succeeded", num_failures); 5746*1c42de6dSgd78059 } 5747*1c42de6dSgd78059 } 5748*1c42de6dSgd78059 5749*1c42de6dSgd78059 /* 5750*1c42de6dSgd78059 * function - bscv_write_hostname 5751*1c42de6dSgd78059 * description - write a new hostname to the lom 5752*1c42de6dSgd78059 * inputs - soft state pointer, pointer to new name, name length 5753*1c42de6dSgd78059 * outputs - none 5754*1c42de6dSgd78059 */ 5755*1c42de6dSgd78059 static void 5756*1c42de6dSgd78059 bscv_write_hostname(bscv_soft_state_t *ssp, 5757*1c42de6dSgd78059 char *host_nodename, uint8_t length) 5758*1c42de6dSgd78059 { 5759*1c42de6dSgd78059 int num_failures; 5760*1c42de6dSgd78059 boolean_t needretry; 5761*1c42de6dSgd78059 int i; 5762*1c42de6dSgd78059 5763*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 5764*1c42de6dSgd78059 5765*1c42de6dSgd78059 /* 5766*1c42de6dSgd78059 * We have a special failure case here because a retry of a read 5767*1c42de6dSgd78059 * causes data to be lost. Thus we handle the retries ourselves 5768*1c42de6dSgd78059 * and are also responsible for detemining if the lom is faulty 5769*1c42de6dSgd78059 */ 5770*1c42de6dSgd78059 for (num_failures = 0; 5771*1c42de6dSgd78059 num_failures < BSC_FAILURE_RETRY_LIMIT; 5772*1c42de6dSgd78059 num_failures++) { 5773*1c42de6dSgd78059 bscv_clear_fault(ssp); 5774*1c42de6dSgd78059 bscv_put8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH, length); 5775*1c42de6dSgd78059 if (bscv_faulty(ssp)) { 5776*1c42de6dSgd78059 needretry = 1; 5777*1c42de6dSgd78059 } else { 5778*1c42de6dSgd78059 needretry = 0; 5779*1c42de6dSgd78059 for (i = 0; i < length; i++) { 5780*1c42de6dSgd78059 bscv_put8_once(ssp, chan_general, 5781*1c42de6dSgd78059 EBUS_IDX_HNAME_CHAR, host_nodename[i]); 5782*1c42de6dSgd78059 /* Retry on any error */ 5783*1c42de6dSgd78059 if (bscv_retcode(ssp) != 0) { 5784*1c42de6dSgd78059 needretry = 1; 5785*1c42de6dSgd78059 break; 5786*1c42de6dSgd78059 } 5787*1c42de6dSgd78059 } 5788*1c42de6dSgd78059 } 5789*1c42de6dSgd78059 if (!needretry) { 5790*1c42de6dSgd78059 break; 5791*1c42de6dSgd78059 } 5792*1c42de6dSgd78059 } 5793*1c42de6dSgd78059 5794*1c42de6dSgd78059 if (needretry) { 5795*1c42de6dSgd78059 /* Failure - we ran out of retries */ 5796*1c42de6dSgd78059 cmn_err(CE_WARN, 5797*1c42de6dSgd78059 "bscv_write_hostname: retried %d times, giving up", 5798*1c42de6dSgd78059 num_failures); 5799*1c42de6dSgd78059 ssp->had_fault = B_TRUE; 5800*1c42de6dSgd78059 } else if (num_failures > 0) { 5801*1c42de6dSgd78059 bscv_trace(ssp, 'R', "bscv_write_hostname", 5802*1c42de6dSgd78059 "retried %d times, succeeded", num_failures); 5803*1c42de6dSgd78059 } 5804*1c42de6dSgd78059 } 5805*1c42de6dSgd78059 5806*1c42de6dSgd78059 /* 5807*1c42de6dSgd78059 * function - bscv_setup_static_info 5808*1c42de6dSgd78059 * description - read in static information from the lom at attach time. 5809*1c42de6dSgd78059 * inputs - soft state ptr 5810*1c42de6dSgd78059 * outputs - none 5811*1c42de6dSgd78059 */ 5812*1c42de6dSgd78059 5813*1c42de6dSgd78059 static void 5814*1c42de6dSgd78059 bscv_setup_static_info(bscv_soft_state_t *ssp) 5815*1c42de6dSgd78059 { 5816*1c42de6dSgd78059 uint8_t addr_space_ptr; 5817*1c42de6dSgd78059 uint16_t mask; 5818*1c42de6dSgd78059 uint8_t fanspeed; 5819*1c42de6dSgd78059 int oldtemps[MAX_TEMPS]; 5820*1c42de6dSgd78059 int8_t temp; 5821*1c42de6dSgd78059 int i; 5822*1c42de6dSgd78059 5823*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 5824*1c42de6dSgd78059 5825*1c42de6dSgd78059 /* 5826*1c42de6dSgd78059 * Finally read in some static info like device names, 5827*1c42de6dSgd78059 * shutdown enabled, etc before the queue starts. 5828*1c42de6dSgd78059 */ 5829*1c42de6dSgd78059 5830*1c42de6dSgd78059 /* 5831*1c42de6dSgd78059 * To get the volts static info we need address space 2 5832*1c42de6dSgd78059 */ 5833*1c42de6dSgd78059 bzero(&ssp->volts, sizeof (lom_volts_t)); 5834*1c42de6dSgd78059 ssp->volts.num = EBUS_CONFIG2_NSUPPLY_DEC( 5835*1c42de6dSgd78059 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG2)); 5836*1c42de6dSgd78059 if (ssp->volts.num > MAX_VOLTS) { 5837*1c42de6dSgd78059 cmn_err(CE_WARN, 5838*1c42de6dSgd78059 "lom: firmware reported too many voltage lines. "); 5839*1c42de6dSgd78059 cmn_err(CE_CONT, "Reported %d, maximum is %d", 5840*1c42de6dSgd78059 ssp->volts.num, MAX_VOLTS); 5841*1c42de6dSgd78059 ssp->volts.num = MAX_VOLTS; 5842*1c42de6dSgd78059 } 5843*1c42de6dSgd78059 5844*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_setup_static_info", 5845*1c42de6dSgd78059 "num volts %d", ssp->volts.num); 5846*1c42de6dSgd78059 (void) bscv_read_env_name(ssp, 5847*1c42de6dSgd78059 EBUS_CMD_SPACE2, 5848*1c42de6dSgd78059 EBUS_IDX2_SUPPLY_NAME_START, 5849*1c42de6dSgd78059 EBUS_IDX2_SUPPLY_NAME_END, 5850*1c42de6dSgd78059 ssp->volts.name, 5851*1c42de6dSgd78059 ssp->volts.num); 5852*1c42de6dSgd78059 5853*1c42de6dSgd78059 mask = bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE2, 5854*1c42de6dSgd78059 EBUS_IDX2_SUPPLY_FATAL_MASK1)) << 8; 5855*1c42de6dSgd78059 mask |= bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE2, 5856*1c42de6dSgd78059 EBUS_IDX2_SUPPLY_FATAL_MASK2)); 5857*1c42de6dSgd78059 5858*1c42de6dSgd78059 for (i = 0; i < ssp->volts.num; i++) { 5859*1c42de6dSgd78059 ssp->volts.shutdown_enabled[i] = 5860*1c42de6dSgd78059 (((mask >> i) & 1) == 0) ? 0 : 1; 5861*1c42de6dSgd78059 } 5862*1c42de6dSgd78059 5863*1c42de6dSgd78059 /* 5864*1c42de6dSgd78059 * Get the temperature static info and populate initial temperatures. 5865*1c42de6dSgd78059 * Do not destroy old temperature values if the new value is not 5866*1c42de6dSgd78059 * known i.e. if the device is inaccessible. 5867*1c42de6dSgd78059 */ 5868*1c42de6dSgd78059 bcopy(ssp->temps.temp, oldtemps, sizeof (oldtemps)); 5869*1c42de6dSgd78059 5870*1c42de6dSgd78059 bzero(&ssp->temps, sizeof (lom_temp_t)); 5871*1c42de6dSgd78059 ssp->temps.num = EBUS_CONFIG2_NTEMP_DEC( 5872*1c42de6dSgd78059 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG2)); 5873*1c42de6dSgd78059 if (ssp->temps.num > MAX_TEMPS) { 5874*1c42de6dSgd78059 cmn_err(CE_WARN, 5875*1c42de6dSgd78059 "lom: firmware reported too many temperatures being " 5876*1c42de6dSgd78059 "monitored."); 5877*1c42de6dSgd78059 cmn_err(CE_CONT, "Reported %d, maximum is %d", 5878*1c42de6dSgd78059 ssp->temps.num, MAX_TEMPS); 5879*1c42de6dSgd78059 ssp->temps.num = MAX_TEMPS; 5880*1c42de6dSgd78059 } 5881*1c42de6dSgd78059 ssp->temps.num_ov = EBUS_CONFIG3_NOTEMP_DEC( 5882*1c42de6dSgd78059 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG3)); 5883*1c42de6dSgd78059 if (ssp->temps.num_ov > MAX_TEMPS) { 5884*1c42de6dSgd78059 cmn_err(CE_WARN, 5885*1c42de6dSgd78059 "lom: firmware reported too many over temperatures being " 5886*1c42de6dSgd78059 "monitored."); 5887*1c42de6dSgd78059 cmn_err(CE_CONT, "Reported %d, maximum is %d", 5888*1c42de6dSgd78059 ssp->temps.num_ov, MAX_TEMPS); 5889*1c42de6dSgd78059 ssp->temps.num_ov = MAX_TEMPS; 5890*1c42de6dSgd78059 } 5891*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_setup_static_info", 5892*1c42de6dSgd78059 "num temps %d, over temps %d", 5893*1c42de6dSgd78059 ssp->temps.num, ssp->temps.num_ov); 5894*1c42de6dSgd78059 5895*1c42de6dSgd78059 addr_space_ptr = bscv_read_env_name(ssp, 5896*1c42de6dSgd78059 EBUS_CMD_SPACE4, 5897*1c42de6dSgd78059 EBUS_IDX4_TEMP_NAME_START, 5898*1c42de6dSgd78059 EBUS_IDX4_TEMP_NAME_END, 5899*1c42de6dSgd78059 ssp->temps.name, 5900*1c42de6dSgd78059 ssp->temps.num); 5901*1c42de6dSgd78059 5902*1c42de6dSgd78059 for (i = 0; i < ssp->temps.num; i++) { 5903*1c42de6dSgd78059 ssp->temps.warning[i] = (int8_t)bscv_get8(ssp, chan_general, 5904*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE4, EBUS_IDX4_TEMP_WARN1 + i)); 5905*1c42de6dSgd78059 5906*1c42de6dSgd78059 /* 5907*1c42de6dSgd78059 * If shutdown is not enabled then set it as zero so 5908*1c42de6dSgd78059 * it is not displayed by the utility. 5909*1c42de6dSgd78059 */ 5910*1c42de6dSgd78059 if ((bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE4, 5911*1c42de6dSgd78059 EBUS_IDX4_TEMP_FATAL_MASK)) >> i) & 0x01) { 5912*1c42de6dSgd78059 ssp->temps.shutdown[i] = (int8_t)bscv_get8(ssp, 5913*1c42de6dSgd78059 chan_general, 5914*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE4, EBUS_IDX4_TEMP_SDOWN1 + i)); 5915*1c42de6dSgd78059 } else { 5916*1c42de6dSgd78059 ssp->temps.shutdown[i] = 0; 5917*1c42de6dSgd78059 } 5918*1c42de6dSgd78059 } 5919*1c42de6dSgd78059 5920*1c42de6dSgd78059 for (i = 0; i < ssp->temps.num; i++) { 5921*1c42de6dSgd78059 temp = bscv_get8(ssp, chan_general, EBUS_IDX_TEMP1 + i); 5922*1c42de6dSgd78059 if ((temp <= LOM_TEMP_MAX_VALUE) || 5923*1c42de6dSgd78059 (temp == LOM_TEMP_STATE_NOT_PRESENT)) { 5924*1c42de6dSgd78059 ssp->temps.temp[i] = temp; 5925*1c42de6dSgd78059 } else { 5926*1c42de6dSgd78059 /* New value is not known - use old value */ 5927*1c42de6dSgd78059 ssp->temps.temp[i] = oldtemps[i]; 5928*1c42de6dSgd78059 } 5929*1c42de6dSgd78059 } 5930*1c42de6dSgd78059 5931*1c42de6dSgd78059 /* 5932*1c42de6dSgd78059 * Check for and skip a single 0xff character between the 5933*1c42de6dSgd78059 * temperature and over temperature names 5934*1c42de6dSgd78059 */ 5935*1c42de6dSgd78059 if (bscv_get8(ssp, chan_general, 5936*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE4, addr_space_ptr)) == 0xff) { 5937*1c42de6dSgd78059 addr_space_ptr++; 5938*1c42de6dSgd78059 } 5939*1c42de6dSgd78059 5940*1c42de6dSgd78059 (void) bscv_read_env_name(ssp, 5941*1c42de6dSgd78059 EBUS_CMD_SPACE4, 5942*1c42de6dSgd78059 addr_space_ptr, 5943*1c42de6dSgd78059 EBUS_IDX4_TEMP_NAME_END, 5944*1c42de6dSgd78059 ssp->temps.name_ov, 5945*1c42de6dSgd78059 ssp->temps.num_ov); 5946*1c42de6dSgd78059 5947*1c42de6dSgd78059 /* 5948*1c42de6dSgd78059 * To get the CB static info we need address space 3 5949*1c42de6dSgd78059 */ 5950*1c42de6dSgd78059 bzero(&ssp->sflags, sizeof (lom_sflags_t)); 5951*1c42de6dSgd78059 ssp->sflags.num = EBUS_CONFIG3_NBREAKERS_DEC(bscv_get8(ssp, 5952*1c42de6dSgd78059 chan_general, EBUS_IDX_CONFIG3)); 5953*1c42de6dSgd78059 if (ssp->sflags.num > MAX_STATS) { 5954*1c42de6dSgd78059 cmn_err(CE_WARN, 5955*1c42de6dSgd78059 "lom: firmware reported too many status flags."); 5956*1c42de6dSgd78059 cmn_err(CE_CONT, 5957*1c42de6dSgd78059 "Reported %d, maximum is %d", 5958*1c42de6dSgd78059 ssp->sflags.num, MAX_STATS); 5959*1c42de6dSgd78059 ssp->sflags.num = MAX_STATS; 5960*1c42de6dSgd78059 } 5961*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_setup_static_info", 5962*1c42de6dSgd78059 "num sflags %d", ssp->sflags.num); 5963*1c42de6dSgd78059 5964*1c42de6dSgd78059 (void) bscv_read_env_name(ssp, 5965*1c42de6dSgd78059 EBUS_CMD_SPACE3, 5966*1c42de6dSgd78059 EBUS_IDX3_BREAKER_NAME_START, 5967*1c42de6dSgd78059 EBUS_IDX3_BREAKER_NAME_END, 5968*1c42de6dSgd78059 ssp->sflags.name, 5969*1c42de6dSgd78059 ssp->sflags.num); 5970*1c42de6dSgd78059 5971*1c42de6dSgd78059 5972*1c42de6dSgd78059 /* 5973*1c42de6dSgd78059 * To get the fan static info we need address space 5 5974*1c42de6dSgd78059 */ 5975*1c42de6dSgd78059 ssp->num_fans = EBUS_CONFIG_NFAN_DEC( 5976*1c42de6dSgd78059 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG)); 5977*1c42de6dSgd78059 if (ssp->num_fans > MAX_FANS) { 5978*1c42de6dSgd78059 cmn_err(CE_WARN, 5979*1c42de6dSgd78059 "lom: firmware reported too many fans. "); 5980*1c42de6dSgd78059 cmn_err(CE_CONT, 5981*1c42de6dSgd78059 "Reported %d, maximum is %d", 5982*1c42de6dSgd78059 ssp->num_fans, MAX_FANS); 5983*1c42de6dSgd78059 ssp->num_fans = MAX_FANS; 5984*1c42de6dSgd78059 } 5985*1c42de6dSgd78059 5986*1c42de6dSgd78059 for (i = 0; i < ssp->num_fans; i++) { 5987*1c42de6dSgd78059 fanspeed = bscv_get8(ssp, chan_general, 5988*1c42de6dSgd78059 EBUS_IDX_FAN1_SPEED + i); 5989*1c42de6dSgd78059 if ((fanspeed <= LOM_FAN_MAX_SPEED) || 5990*1c42de6dSgd78059 (fanspeed == LOM_FAN_NOT_PRESENT)) { 5991*1c42de6dSgd78059 /* 5992*1c42de6dSgd78059 * Do not destroy previous values unless the 5993*1c42de6dSgd78059 * value is definitive. 5994*1c42de6dSgd78059 */ 5995*1c42de6dSgd78059 ssp->fanspeed[i] = fanspeed; 5996*1c42de6dSgd78059 } 5997*1c42de6dSgd78059 } 5998*1c42de6dSgd78059 5999*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_setup_static_info", 6000*1c42de6dSgd78059 "num fans %d", ssp->num_fans); 6001*1c42de6dSgd78059 6002*1c42de6dSgd78059 (void) bscv_read_env_name(ssp, 6003*1c42de6dSgd78059 EBUS_CMD_SPACE5, 6004*1c42de6dSgd78059 EBUS_IDX5_FAN_NAME_START, 6005*1c42de6dSgd78059 EBUS_IDX5_FAN_NAME_END, 6006*1c42de6dSgd78059 ssp->fan_names, 6007*1c42de6dSgd78059 ssp->num_fans); 6008*1c42de6dSgd78059 6009*1c42de6dSgd78059 /* Get led static information from address space 10 */ 6010*1c42de6dSgd78059 6011*1c42de6dSgd78059 (void) bscv_read_env_name(ssp, 6012*1c42de6dSgd78059 EBUS_CMD_SPACE_LEDS, 6013*1c42de6dSgd78059 EBUS_IDX10_LED_NAME_START, 6014*1c42de6dSgd78059 EBUS_IDX10_LED_NAME_END, 6015*1c42de6dSgd78059 ssp->led_names, 6016*1c42de6dSgd78059 MAX_LED_ID); 6017*1c42de6dSgd78059 } 6018*1c42de6dSgd78059 6019*1c42de6dSgd78059 /* 6020*1c42de6dSgd78059 * function - bscv_read_env_name 6021*1c42de6dSgd78059 * description - read in static environment names 6022*1c42de6dSgd78059 * warning changes address space and the caller relies 6023*1c42de6dSgd78059 * on this behaviour. 6024*1c42de6dSgd78059 * inputs - soft state ptr, chosen address space, 6025*1c42de6dSgd78059 * start of name data, end of name data, 6026*1c42de6dSgd78059 * name storage, number of names. 6027*1c42de6dSgd78059 * outputs - next address for reading name data. 6028*1c42de6dSgd78059 */ 6029*1c42de6dSgd78059 6030*1c42de6dSgd78059 static uint8_t 6031*1c42de6dSgd78059 bscv_read_env_name(bscv_soft_state_t *ssp, 6032*1c42de6dSgd78059 uint8_t addr_space, 6033*1c42de6dSgd78059 uint8_t addr_start, 6034*1c42de6dSgd78059 uint8_t addr_end, 6035*1c42de6dSgd78059 char namebuf[][MAX_LOM2_NAME_STR], 6036*1c42de6dSgd78059 int numnames) 6037*1c42de6dSgd78059 { 6038*1c42de6dSgd78059 int i; 6039*1c42de6dSgd78059 int nameidx; 6040*1c42de6dSgd78059 int namemax; 6041*1c42de6dSgd78059 unsigned int addr_space_ptr; 6042*1c42de6dSgd78059 uint8_t this_char; 6043*1c42de6dSgd78059 6044*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 6045*1c42de6dSgd78059 6046*1c42de6dSgd78059 bscv_trace(ssp, 'A', "bscv_read_env_name", 6047*1c42de6dSgd78059 "bscv_read_env_name, space %d, start 0x%x, end 0x%x, numnames %d", 6048*1c42de6dSgd78059 addr_space, addr_start, addr_end, numnames); 6049*1c42de6dSgd78059 6050*1c42de6dSgd78059 addr_space_ptr = addr_start; 6051*1c42de6dSgd78059 6052*1c42de6dSgd78059 for (i = 0; i < numnames; i++) { 6053*1c42de6dSgd78059 nameidx = 0; 6054*1c42de6dSgd78059 namemax = sizeof (namebuf[i]); 6055*1c42de6dSgd78059 bzero(namebuf[i], namemax); 6056*1c42de6dSgd78059 6057*1c42de6dSgd78059 while (addr_space_ptr <= addr_end) { 6058*1c42de6dSgd78059 /* 6059*1c42de6dSgd78059 * Read the current character. 6060*1c42de6dSgd78059 */ 6061*1c42de6dSgd78059 this_char = bscv_get8(ssp, chan_general, 6062*1c42de6dSgd78059 BSCVA(addr_space, addr_space_ptr)); 6063*1c42de6dSgd78059 6064*1c42de6dSgd78059 if (this_char == 0xff) { 6065*1c42de6dSgd78059 /* 6066*1c42de6dSgd78059 * Ran out of names - this must 6067*1c42de6dSgd78059 * be the end of the name. 6068*1c42de6dSgd78059 * This is really an error because 6069*1c42de6dSgd78059 * we have just seen either a non-NUL 6070*1c42de6dSgd78059 * terminated string or the number of 6071*1c42de6dSgd78059 * strings did not match what was 6072*1c42de6dSgd78059 * reported. 6073*1c42de6dSgd78059 */ 6074*1c42de6dSgd78059 break; 6075*1c42de6dSgd78059 } 6076*1c42de6dSgd78059 /* 6077*1c42de6dSgd78059 * We increment the buffer pointer now so that 6078*1c42de6dSgd78059 * it is ready for the next read 6079*1c42de6dSgd78059 */ 6080*1c42de6dSgd78059 addr_space_ptr++; 6081*1c42de6dSgd78059 6082*1c42de6dSgd78059 if (this_char == '\0') { 6083*1c42de6dSgd78059 /* Found end of string - done */ 6084*1c42de6dSgd78059 break; 6085*1c42de6dSgd78059 } 6086*1c42de6dSgd78059 if (nameidx < (namemax - 1)) { 6087*1c42de6dSgd78059 /* 6088*1c42de6dSgd78059 * Buffer not full - record character 6089*1c42de6dSgd78059 * NOTE we always leave room for the NUL 6090*1c42de6dSgd78059 * terminator. 6091*1c42de6dSgd78059 */ 6092*1c42de6dSgd78059 namebuf[i][nameidx++] = this_char; 6093*1c42de6dSgd78059 } 6094*1c42de6dSgd78059 } 6095*1c42de6dSgd78059 /* Ensure null termination */ 6096*1c42de6dSgd78059 namebuf[i][nameidx] = '\0'; 6097*1c42de6dSgd78059 } 6098*1c42de6dSgd78059 /* Clamp addr_space_ptr to 0xff because we return uint8_t */ 6099*1c42de6dSgd78059 if (addr_space_ptr > 0xff) { 6100*1c42de6dSgd78059 addr_space_ptr = 0xff; 6101*1c42de6dSgd78059 } 6102*1c42de6dSgd78059 return (addr_space_ptr); 6103*1c42de6dSgd78059 } 6104*1c42de6dSgd78059 6105*1c42de6dSgd78059 /* 6106*1c42de6dSgd78059 * function - bscv_setup_events 6107*1c42de6dSgd78059 * description - initialise the event reporting code 6108*1c42de6dSgd78059 * inputs - soft state ptr 6109*1c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 6110*1c42de6dSgd78059 */ 6111*1c42de6dSgd78059 6112*1c42de6dSgd78059 static void 6113*1c42de6dSgd78059 bscv_setup_events(bscv_soft_state_t *ssp) 6114*1c42de6dSgd78059 { 6115*1c42de6dSgd78059 uint8_t bits2set; 6116*1c42de6dSgd78059 uint8_t bits2clear; 6117*1c42de6dSgd78059 6118*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 6119*1c42de6dSgd78059 6120*1c42de6dSgd78059 /* 6121*1c42de6dSgd78059 * deal with event reporting - cover all cases 6122*1c42de6dSgd78059 */ 6123*1c42de6dSgd78059 6124*1c42de6dSgd78059 bits2set = 0; 6125*1c42de6dSgd78059 bits2clear = 0; 6126*1c42de6dSgd78059 if (ssp->serial_reporting == LOM_SER_EVENTS_ON) { 6127*1c42de6dSgd78059 bits2clear |= EBUS_ALARM_NOEVENTS; 6128*1c42de6dSgd78059 } else if (ssp->serial_reporting == LOM_SER_EVENTS_OFF) { 6129*1c42de6dSgd78059 bits2set |= EBUS_ALARM_NOEVENTS; 6130*1c42de6dSgd78059 } else if (ssp->serial_reporting == LOM_SER_EVENTS_DEF) { 6131*1c42de6dSgd78059 bits2set |= EBUS_ALARM_NOEVENTS; 6132*1c42de6dSgd78059 } 6133*1c42de6dSgd78059 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_ALARM, 6134*1c42de6dSgd78059 bits2set, bits2clear); 6135*1c42de6dSgd78059 } 6136*1c42de6dSgd78059 6137*1c42de6dSgd78059 #ifdef __sparc 6138*1c42de6dSgd78059 /* 6139*1c42de6dSgd78059 * function - bscv_write_sig 6140*1c42de6dSgd78059 * description - write out a signature, taking care to deal with any strange 6141*1c42de6dSgd78059 * values for CPU ID 6142*1c42de6dSgd78059 * inputs - soft state ptr, signature 6143*1c42de6dSgd78059 * outputs - none 6144*1c42de6dSgd78059 */ 6145*1c42de6dSgd78059 static void 6146*1c42de6dSgd78059 bscv_write_sig(bscv_soft_state_t *ssp, bscv_sig_t s) 6147*1c42de6dSgd78059 { 6148*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 6149*1c42de6dSgd78059 6150*1c42de6dSgd78059 /* Upload the signature */ 6151*1c42de6dSgd78059 bscv_put32(ssp, chan_cpusig, 6152*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_SIG_MSB), 6153*1c42de6dSgd78059 s.sig_info.signature); 6154*1c42de6dSgd78059 6155*1c42de6dSgd78059 /* 6156*1c42de6dSgd78059 * We always write the CPU ID last because this tells the firmware 6157*1c42de6dSgd78059 * that the signature is fully uploaded and therefore to consume the 6158*1c42de6dSgd78059 * data. This is required since the signature is > 1 byte in size 6159*1c42de6dSgd78059 * and we transmit data in single bytes. 6160*1c42de6dSgd78059 */ 6161*1c42de6dSgd78059 if (s.cpu == ~0) { 6162*1c42de6dSgd78059 /* ~0 means the signature applies to any CPU. */ 6163*1c42de6dSgd78059 bscv_put8(ssp, chan_cpusig, 6164*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_ID), 6165*1c42de6dSgd78059 EBUS_ANY_CPU_ID); 6166*1c42de6dSgd78059 } else { 6167*1c42de6dSgd78059 if (s.cpu > 255) { 6168*1c42de6dSgd78059 /* 6169*1c42de6dSgd78059 * The CPU ID supplied is unexpectedly large. Lets 6170*1c42de6dSgd78059 * just use the bottom bits, in case other high order 6171*1c42de6dSgd78059 * bits are being used for special meaning. 6172*1c42de6dSgd78059 */ 6173*1c42de6dSgd78059 cmn_err(CE_WARN, "CPU Signature ID 0x%x > 255", s.cpu); 6174*1c42de6dSgd78059 s.cpu %= 256; 6175*1c42de6dSgd78059 cmn_err(CE_CONT, "using ID 0x%x instead ", s.cpu); 6176*1c42de6dSgd78059 } 6177*1c42de6dSgd78059 bscv_put8(ssp, chan_cpusig, 6178*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_ID), 6179*1c42de6dSgd78059 (uint8_t)s.cpu); 6180*1c42de6dSgd78059 } 6181*1c42de6dSgd78059 6182*1c42de6dSgd78059 ssp->last_sig = s; 6183*1c42de6dSgd78059 ssp->progress |= BSCV_SIG_SENT; 6184*1c42de6dSgd78059 } 6185*1c42de6dSgd78059 #endif /* __sparc */ 6186*1c42de6dSgd78059 6187*1c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 6188*1c42de6dSgd78059 6189*1c42de6dSgd78059 /* 6190*1c42de6dSgd78059 * function - bscv_inform_bsc 6191*1c42de6dSgd78059 * description - inform bsc of driver state for logging purposes 6192*1c42de6dSgd78059 * inputs - driver soft state, state 6193*1c42de6dSgd78059 * outputs - none 6194*1c42de6dSgd78059 * 6195*1c42de6dSgd78059 */ 6196*1c42de6dSgd78059 static void 6197*1c42de6dSgd78059 bscv_inform_bsc(bscv_soft_state_t *ssp, uint32_t state) 6198*1c42de6dSgd78059 { 6199*1c42de6dSgd78059 ASSERT(bscv_held(ssp)); 6200*1c42de6dSgd78059 6201*1c42de6dSgd78059 bscv_trace(ssp, 'X', "bscv_inform_bsc", 6202*1c42de6dSgd78059 "bscv_inform_bsc: state=%d", state); 6203*1c42de6dSgd78059 6204*1c42de6dSgd78059 bscv_put32(ssp, chan_general, 6205*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_SIG_MSB), state); 6206*1c42de6dSgd78059 bscv_put8(ssp, chan_cpusig, 6207*1c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_ID), EBUS_ANY_CPU_ID); 6208*1c42de6dSgd78059 } 6209*1c42de6dSgd78059 6210*1c42de6dSgd78059 /* 6211*1c42de6dSgd78059 * function - bscv_watchdog_pat_request 6212*1c42de6dSgd78059 * description - request a heartbeat pat 6213*1c42de6dSgd78059 * inputs - timeout value in seconds 6214*1c42de6dSgd78059 * outputs - none 6215*1c42de6dSgd78059 */ 6216*1c42de6dSgd78059 static void 6217*1c42de6dSgd78059 bscv_watchdog_pat_request(void *arg) 6218*1c42de6dSgd78059 { 6219*1c42de6dSgd78059 bscv_soft_state_t *ssp = (bscv_soft_state_t *)arg; 6220*1c42de6dSgd78059 6221*1c42de6dSgd78059 bscv_wdog_do_pat(ssp); 6222*1c42de6dSgd78059 } 6223*1c42de6dSgd78059 6224*1c42de6dSgd78059 /* 6225*1c42de6dSgd78059 * function - bscv_watchdog_cfg_request 6226*1c42de6dSgd78059 * description - request configuration of the bsc hardware watchdog 6227*1c42de6dSgd78059 * inputs - new state (0=disabled, 1=enabled) 6228*1c42de6dSgd78059 * outputs - one if successful, zero if unsuccesful 6229*1c42de6dSgd78059 */ 6230*1c42de6dSgd78059 static void 6231*1c42de6dSgd78059 bscv_watchdog_cfg_request(bscv_soft_state_t *ssp, uint8_t new_state) 6232*1c42de6dSgd78059 { 6233*1c42de6dSgd78059 ASSERT(new_state == WDOG_ON || new_state == WDOG_OFF); 6234*1c42de6dSgd78059 6235*1c42de6dSgd78059 watchdog_activated = new_state; 6236*1c42de6dSgd78059 bscv_trace(ssp, 'X', "bscv_watchdog_cfg_request", 6237*1c42de6dSgd78059 "watchdog_activated=%d", watchdog_activated); 6238*1c42de6dSgd78059 bscv_write_wdog_cfg(ssp, 6239*1c42de6dSgd78059 bscv_watchdog_timeout_seconds, 6240*1c42de6dSgd78059 new_state, 6241*1c42de6dSgd78059 wdog_reset_on_timeout); 6242*1c42de6dSgd78059 } 6243*1c42de6dSgd78059 6244*1c42de6dSgd78059 /* 6245*1c42de6dSgd78059 * function - bscv_set_watchdog_timer 6246*1c42de6dSgd78059 * description - setup the heartbeat timeout value 6247*1c42de6dSgd78059 * inputs - timeout value in seconds 6248*1c42de6dSgd78059 * outputs - zero if the value was not changed 6249*1c42de6dSgd78059 * otherwise the current value 6250*1c42de6dSgd78059 */ 6251*1c42de6dSgd78059 static uint_t 6252*1c42de6dSgd78059 bscv_set_watchdog_timer(bscv_soft_state_t *ssp, uint_t timeoutval) 6253*1c42de6dSgd78059 { 6254*1c42de6dSgd78059 bscv_trace(ssp, 'X', "bscv_set_watchdog_timer:", 6255*1c42de6dSgd78059 "timeout=%d", timeoutval); 6256*1c42de6dSgd78059 6257*1c42de6dSgd78059 /* 6258*1c42de6dSgd78059 * We get started during bscv_attach only 6259*1c42de6dSgd78059 * if bscv_watchdog_enable is set. 6260*1c42de6dSgd78059 */ 6261*1c42de6dSgd78059 if (bscv_watchdog_available && (!watchdog_activated || 6262*1c42de6dSgd78059 (watchdog_activated && 6263*1c42de6dSgd78059 (timeoutval != bscv_watchdog_timeout_seconds)))) { 6264*1c42de6dSgd78059 bscv_watchdog_timeout_seconds = timeoutval; 6265*1c42de6dSgd78059 bscv_watchdog_cfg_request(ssp, WDOG_ON); 6266*1c42de6dSgd78059 return (bscv_watchdog_timeout_seconds); 6267*1c42de6dSgd78059 } 6268*1c42de6dSgd78059 return (0); 6269*1c42de6dSgd78059 } 6270*1c42de6dSgd78059 6271*1c42de6dSgd78059 /* 6272*1c42de6dSgd78059 * function - bscv_clear_watchdog_timer 6273*1c42de6dSgd78059 * description - add the watchdog patter cyclic 6274*1c42de6dSgd78059 * inputs - driver soft state 6275*1c42de6dSgd78059 * outputs - value of watchdog timeout in seconds 6276*1c42de6dSgd78059 * 6277*1c42de6dSgd78059 * This function is a copy of the SPARC implementation 6278*1c42de6dSgd78059 * in the todblade clock driver. 6279*1c42de6dSgd78059 */ 6280*1c42de6dSgd78059 static void 6281*1c42de6dSgd78059 bscv_clear_watchdog_timer(bscv_soft_state_t *ssp) 6282*1c42de6dSgd78059 { 6283*1c42de6dSgd78059 bscv_trace(ssp, 'X', "bscv_clear_watchdog_timer", ""); 6284*1c42de6dSgd78059 6285*1c42de6dSgd78059 if (bscv_watchdog_available && watchdog_activated) { 6286*1c42de6dSgd78059 bscv_watchdog_enable = 0; 6287*1c42de6dSgd78059 bscv_watchdog_cfg_request(ssp, WDOG_OFF); 6288*1c42de6dSgd78059 } 6289*1c42de6dSgd78059 } 6290*1c42de6dSgd78059 6291*1c42de6dSgd78059 /* 6292*1c42de6dSgd78059 * function - bscv_panic_callback 6293*1c42de6dSgd78059 * description - called when we panic so we can disabled the watchdog 6294*1c42de6dSgd78059 * inputs - driver soft state pointer 6295*1c42de6dSgd78059 * outputs - DDI_SUCCESS 6296*1c42de6dSgd78059 */ 6297*1c42de6dSgd78059 /*ARGSUSED1*/ 6298*1c42de6dSgd78059 static boolean_t 6299*1c42de6dSgd78059 bscv_panic_callback(void *arg, int code) 6300*1c42de6dSgd78059 { 6301*1c42de6dSgd78059 bscv_soft_state_t *ssp = (bscv_soft_state_t *)arg; 6302*1c42de6dSgd78059 6303*1c42de6dSgd78059 bscv_trace(ssp, 'X', "bscv_panic_callback", 6304*1c42de6dSgd78059 "disabling watchdog"); 6305*1c42de6dSgd78059 6306*1c42de6dSgd78059 bscv_clear_watchdog_timer(ssp); 6307*1c42de6dSgd78059 /* 6308*1c42de6dSgd78059 * We dont get interrupts during the panic callback. But bscbus 6309*1c42de6dSgd78059 * takes care of all this 6310*1c42de6dSgd78059 */ 6311*1c42de6dSgd78059 bscv_full_stop(ssp); 6312*1c42de6dSgd78059 return (DDI_SUCCESS); 6313*1c42de6dSgd78059 } 6314*1c42de6dSgd78059 6315*1c42de6dSgd78059 /* 6316*1c42de6dSgd78059 * function - bscv_watchdog_cyclic_add 6317*1c42de6dSgd78059 * description - add the watchdog patter cyclic 6318*1c42de6dSgd78059 * inputs - driver soft state 6319*1c42de6dSgd78059 * outputs - none 6320*1c42de6dSgd78059 */ 6321*1c42de6dSgd78059 static void 6322*1c42de6dSgd78059 bscv_watchdog_cyclic_add(bscv_soft_state_t *ssp) 6323*1c42de6dSgd78059 { 6324*1c42de6dSgd78059 cyc_handler_t hdlr; 6325*1c42de6dSgd78059 cyc_time_t when; 6326*1c42de6dSgd78059 6327*1c42de6dSgd78059 ASSERT(MUTEX_HELD(&cpu_lock)); /* for cyclic_add */ 6328*1c42de6dSgd78059 6329*1c42de6dSgd78059 if (ssp->cyclic_id != CYCLIC_NONE) { 6330*1c42de6dSgd78059 return; 6331*1c42de6dSgd78059 } 6332*1c42de6dSgd78059 6333*1c42de6dSgd78059 hdlr.cyh_level = CY_LOCK_LEVEL; 6334*1c42de6dSgd78059 hdlr.cyh_func = (cyc_func_t)bscv_watchdog_pat_request; 6335*1c42de6dSgd78059 hdlr.cyh_arg = (void *)ssp; 6336*1c42de6dSgd78059 6337*1c42de6dSgd78059 when.cyt_when = 0; 6338*1c42de6dSgd78059 when.cyt_interval = WATCHDOG_PAT_INTERVAL; 6339*1c42de6dSgd78059 6340*1c42de6dSgd78059 ssp->cyclic_id = cyclic_add(&hdlr, &when); 6341*1c42de6dSgd78059 6342*1c42de6dSgd78059 bscv_trace(ssp, 'X', "bscv_watchdog_cyclic_add:", 6343*1c42de6dSgd78059 "cyclic added"); 6344*1c42de6dSgd78059 } 6345*1c42de6dSgd78059 6346*1c42de6dSgd78059 /* 6347*1c42de6dSgd78059 * function - bscv_watchdog_cyclic_remove 6348*1c42de6dSgd78059 * description - remove the watchdog patter cyclic 6349*1c42de6dSgd78059 * inputs - soft state ptr 6350*1c42de6dSgd78059 * outputs - none 6351*1c42de6dSgd78059 */ 6352*1c42de6dSgd78059 static void 6353*1c42de6dSgd78059 bscv_watchdog_cyclic_remove(bscv_soft_state_t *ssp) 6354*1c42de6dSgd78059 { 6355*1c42de6dSgd78059 ASSERT(MUTEX_HELD(&cpu_lock)); /* for cyclic_remove */ 6356*1c42de6dSgd78059 6357*1c42de6dSgd78059 if (ssp->cyclic_id == CYCLIC_NONE) { 6358*1c42de6dSgd78059 return; 6359*1c42de6dSgd78059 } 6360*1c42de6dSgd78059 6361*1c42de6dSgd78059 cyclic_remove(ssp->cyclic_id); 6362*1c42de6dSgd78059 ssp->cyclic_id = CYCLIC_NONE; 6363*1c42de6dSgd78059 bscv_trace(ssp, 'X', "bscv_watchdog_cyclic_remove:", 6364*1c42de6dSgd78059 "cyclic removed"); 6365*1c42de6dSgd78059 } 6366*1c42de6dSgd78059 #endif /* __i386 || __amd64 */ 6367*1c42de6dSgd78059 6368*1c42de6dSgd78059 6369*1c42de6dSgd78059 /* 6370*1c42de6dSgd78059 * General utility routines ... 6371*1c42de6dSgd78059 */ 6372*1c42de6dSgd78059 6373*1c42de6dSgd78059 #ifdef DEBUG 6374*1c42de6dSgd78059 6375*1c42de6dSgd78059 static void 6376*1c42de6dSgd78059 bscv_trace(bscv_soft_state_t *ssp, char code, const char *caller, 6377*1c42de6dSgd78059 const char *fmt, ...) 6378*1c42de6dSgd78059 { 6379*1c42de6dSgd78059 char buf[256]; 6380*1c42de6dSgd78059 char *p; 6381*1c42de6dSgd78059 va_list va; 6382*1c42de6dSgd78059 6383*1c42de6dSgd78059 if (ssp->debug & (1 << (code-'@'))) { 6384*1c42de6dSgd78059 p = buf; 6385*1c42de6dSgd78059 (void) snprintf(p, sizeof (buf) - (p - buf), 6386*1c42de6dSgd78059 "%s/%s: ", MYNAME, caller); 6387*1c42de6dSgd78059 p += strlen(p); 6388*1c42de6dSgd78059 6389*1c42de6dSgd78059 va_start(va, fmt); 6390*1c42de6dSgd78059 (void) vsnprintf(p, sizeof (buf) - (p - buf), fmt, va); 6391*1c42de6dSgd78059 va_end(va); 6392*1c42de6dSgd78059 6393*1c42de6dSgd78059 buf[sizeof (buf) - 1] = '\0'; 6394*1c42de6dSgd78059 (void) strlog((short)ssp->majornum, (short)ssp->minornum, code, 6395*1c42de6dSgd78059 SL_TRACE, buf); 6396*1c42de6dSgd78059 } 6397*1c42de6dSgd78059 } 6398*1c42de6dSgd78059 6399*1c42de6dSgd78059 #else /* DEBUG */ 6400*1c42de6dSgd78059 6401*1c42de6dSgd78059 _NOTE(ARGSUSED(0)) 6402*1c42de6dSgd78059 static void 6403*1c42de6dSgd78059 bscv_trace(bscv_soft_state_t *ssp, char code, const char *caller, 6404*1c42de6dSgd78059 const char *fmt, ...) 6405*1c42de6dSgd78059 { 6406*1c42de6dSgd78059 } 6407*1c42de6dSgd78059 6408*1c42de6dSgd78059 #endif /* DEBUG */ 6409