11c42de6dSgd78059 /* 21c42de6dSgd78059 * CDDL HEADER START 31c42de6dSgd78059 * 41c42de6dSgd78059 * The contents of this file are subject to the terms of the 51c42de6dSgd78059 * Common Development and Distribution License (the "License"). 61c42de6dSgd78059 * You may not use this file except in compliance with the License. 71c42de6dSgd78059 * 81c42de6dSgd78059 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91c42de6dSgd78059 * or http://www.opensolaris.org/os/licensing. 101c42de6dSgd78059 * See the License for the specific language governing permissions 111c42de6dSgd78059 * and limitations under the License. 121c42de6dSgd78059 * 131c42de6dSgd78059 * When distributing Covered Code, include this CDDL HEADER in each 141c42de6dSgd78059 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151c42de6dSgd78059 * If applicable, add the following below this CDDL HEADER, with the 161c42de6dSgd78059 * fields enclosed by brackets "[]" replaced with your own identifying 171c42de6dSgd78059 * information: Portions Copyright [yyyy] [name of copyright owner] 181c42de6dSgd78059 * 191c42de6dSgd78059 * CDDL HEADER END 201c42de6dSgd78059 */ 211c42de6dSgd78059 /* 22*1af83355Sandrew.rutz@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 231c42de6dSgd78059 * Use is subject to license terms. 241c42de6dSgd78059 */ 251c42de6dSgd78059 261c42de6dSgd78059 271c42de6dSgd78059 /* 281c42de6dSgd78059 * bscv.c - multi-threaded lom driver for the Stiletto platform. 291c42de6dSgd78059 */ 301c42de6dSgd78059 311c42de6dSgd78059 /* 321c42de6dSgd78059 * Included files. 331c42de6dSgd78059 */ 341c42de6dSgd78059 351c42de6dSgd78059 #include <sys/note.h> 361c42de6dSgd78059 #include <sys/types.h> 371c42de6dSgd78059 #include <sys/param.h> 381c42de6dSgd78059 #include <sys/uio.h> 391c42de6dSgd78059 #include <sys/open.h> 401c42de6dSgd78059 #include <sys/cred.h> 411c42de6dSgd78059 #include <sys/stream.h> 421c42de6dSgd78059 #include <sys/systm.h> 431c42de6dSgd78059 #include <sys/conf.h> 441c42de6dSgd78059 #include <sys/reboot.h> 451c42de6dSgd78059 #include <sys/modctl.h> 461c42de6dSgd78059 #include <sys/mkdev.h> 471c42de6dSgd78059 #include <sys/errno.h> 481c42de6dSgd78059 #include <sys/debug.h> 491c42de6dSgd78059 #include <sys/kmem.h> 501c42de6dSgd78059 #include <sys/consdev.h> 511c42de6dSgd78059 #include <sys/file.h> 521c42de6dSgd78059 #include <sys/stat.h> 531c42de6dSgd78059 #include <sys/disp.h> 541c42de6dSgd78059 #include <sys/ddi.h> 551c42de6dSgd78059 #include <sys/sunddi.h> 561c42de6dSgd78059 #include <sys/stream.h> 571c42de6dSgd78059 #include <sys/strlog.h> 581c42de6dSgd78059 #include <sys/log.h> 591c42de6dSgd78059 #include <sys/utsname.h> 601c42de6dSgd78059 #include <sys/callb.h> 611c42de6dSgd78059 #include <sys/sysevent.h> 621c42de6dSgd78059 #include <sys/nvpair.h> 631c42de6dSgd78059 #include <sys/sysevent/eventdefs.h> 641c42de6dSgd78059 #include <sys/sysevent/domain.h> 651c42de6dSgd78059 #include <sys/sysevent/env.h> 661c42de6dSgd78059 #include <sys/sysevent/dr.h> 671c42de6dSgd78059 681c42de6dSgd78059 #include <sys/lom_io.h> 691c42de6dSgd78059 #include <sys/bscbus.h> 701c42de6dSgd78059 #include <sys/bscv_impl.h> 711c42de6dSgd78059 721c42de6dSgd78059 /* 731c42de6dSgd78059 * Variables defined here and visible internally only 741c42de6dSgd78059 */ 751c42de6dSgd78059 761c42de6dSgd78059 static void *bscv_statep = NULL; 771c42de6dSgd78059 781c42de6dSgd78059 /* 791c42de6dSgd78059 * Forward declarations 801c42de6dSgd78059 */ 811c42de6dSgd78059 821c42de6dSgd78059 static int bscv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 831c42de6dSgd78059 static int bscv_attach(dev_info_t *, ddi_attach_cmd_t); 841c42de6dSgd78059 static int bscv_detach(dev_info_t *, ddi_detach_cmd_t); 851c42de6dSgd78059 static int bscv_reset(dev_info_t *, ddi_reset_cmd_t); 8619397407SSherry Moore static int bscv_quiesce(dev_info_t *); 871c42de6dSgd78059 static int bscv_map_regs(bscv_soft_state_t *); 881c42de6dSgd78059 static void bscv_unmap_regs(bscv_soft_state_t *); 891c42de6dSgd78059 static void bscv_map_chan_logical_physical(bscv_soft_state_t *); 901c42de6dSgd78059 911c42de6dSgd78059 static int bscv_open(dev_t *, int, int, cred_t *); 921c42de6dSgd78059 static int bscv_close(dev_t, int, int, cred_t *); 931c42de6dSgd78059 static void bscv_full_stop(bscv_soft_state_t *); 941c42de6dSgd78059 951c42de6dSgd78059 static void bscv_enter(bscv_soft_state_t *); 96*1af83355Sandrew.rutz@sun.com static int bscv_tryenter(bscv_soft_state_t *ssp); 971c42de6dSgd78059 static void bscv_exit(bscv_soft_state_t *); 981c42de6dSgd78059 #ifdef DEBUG 991c42de6dSgd78059 static int bscv_held(bscv_soft_state_t *); 1001c42de6dSgd78059 #endif /* DEBUG */ 1011c42de6dSgd78059 1021c42de6dSgd78059 static void bscv_put8(bscv_soft_state_t *, int, bscv_addr_t, uint8_t); 1031c42de6dSgd78059 static void bscv_put16(bscv_soft_state_t *, int, bscv_addr_t, uint16_t); 1041c42de6dSgd78059 static void bscv_put32(bscv_soft_state_t *, int, bscv_addr_t, uint32_t); 1051c42de6dSgd78059 static uint8_t bscv_get8(bscv_soft_state_t *, int, bscv_addr_t); 1061c42de6dSgd78059 static uint16_t bscv_get16(bscv_soft_state_t *, int, bscv_addr_t); 1071c42de6dSgd78059 static uint32_t bscv_get32(bscv_soft_state_t *, int, bscv_addr_t); 1081c42de6dSgd78059 static void bscv_setclear8(bscv_soft_state_t *, int, 1091c42de6dSgd78059 bscv_addr_t, uint8_t, uint8_t); 1101c42de6dSgd78059 static void bscv_setclear8_volatile(bscv_soft_state_t *, int, 1111c42de6dSgd78059 bscv_addr_t, uint8_t, uint8_t); 1121c42de6dSgd78059 static void bscv_rep_rw8(bscv_soft_state_t *, int, 1131c42de6dSgd78059 uint8_t *, bscv_addr_t, size_t, uint_t, boolean_t); 1141c42de6dSgd78059 static uint8_t bscv_get8_cached(bscv_soft_state_t *, bscv_addr_t); 1151c42de6dSgd78059 1161c42de6dSgd78059 static uint8_t bscv_get8_locked(bscv_soft_state_t *, int, bscv_addr_t, int *); 1171c42de6dSgd78059 static void bscv_rep_get8_locked(bscv_soft_state_t *, int, 1181c42de6dSgd78059 uint8_t *, bscv_addr_t, size_t, uint_t, int *); 1191c42de6dSgd78059 1201c42de6dSgd78059 static boolean_t bscv_faulty(bscv_soft_state_t *); 1211c42de6dSgd78059 static void bscv_clear_fault(bscv_soft_state_t *); 1221c42de6dSgd78059 static void bscv_set_fault(bscv_soft_state_t *); 1231c42de6dSgd78059 static boolean_t bscv_session_error(bscv_soft_state_t *); 1241c42de6dSgd78059 static int bscv_retcode(bscv_soft_state_t *); 1251c42de6dSgd78059 static int bscv_should_retry(bscv_soft_state_t *); 1261c42de6dSgd78059 static void bscv_locked_result(bscv_soft_state_t *, int *); 1271c42de6dSgd78059 1281c42de6dSgd78059 static void bscv_put8_once(bscv_soft_state_t *, int, bscv_addr_t, uint8_t); 1291c42de6dSgd78059 static uint8_t bscv_get8_once(bscv_soft_state_t *, int, bscv_addr_t); 1301c42de6dSgd78059 static uint32_t bscv_probe(bscv_soft_state_t *, int, uint32_t *); 1311c42de6dSgd78059 static void bscv_resync_comms(bscv_soft_state_t *, int); 1321c42de6dSgd78059 1331c42de6dSgd78059 static boolean_t bscv_window_setup(bscv_soft_state_t *); 1341c42de6dSgd78059 static int bscv_eerw(bscv_soft_state_t *, uint32_t, uint8_t *, 1351c42de6dSgd78059 unsigned, boolean_t); 1361c42de6dSgd78059 1371c42de6dSgd78059 static int bscv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1381c42de6dSgd78059 static int bscv_ioc_dogstate(bscv_soft_state_t *, intptr_t, int); 1391c42de6dSgd78059 static int bscv_ioc_psustate(bscv_soft_state_t *, intptr_t, int); 1401c42de6dSgd78059 static int bscv_ioc_fanstate(bscv_soft_state_t *, intptr_t, int); 1411c42de6dSgd78059 static int bscv_ioc_fledstate(bscv_soft_state_t *, intptr_t, int); 1421c42de6dSgd78059 static int bscv_ioc_ledstate(bscv_soft_state_t *, intptr_t, int); 1431c42de6dSgd78059 static int bscv_ioc_info(bscv_soft_state_t *, intptr_t, int); 1441c42de6dSgd78059 static int bscv_ioc_mread(bscv_soft_state_t *, intptr_t, int); 1451c42de6dSgd78059 static int bscv_ioc_volts(bscv_soft_state_t *, intptr_t, int); 1461c42de6dSgd78059 static int bscv_ioc_stats(bscv_soft_state_t *, intptr_t, int); 1471c42de6dSgd78059 static int bscv_ioc_temp(bscv_soft_state_t *, intptr_t, int); 1481c42de6dSgd78059 static int bscv_ioc_cons(bscv_soft_state_t *, intptr_t, int); 1491c42de6dSgd78059 static int bscv_ioc_eventlog2(bscv_soft_state_t *, intptr_t, int); 1501c42de6dSgd78059 static int bscv_ioc_info2(bscv_soft_state_t *, intptr_t, int); 1511c42de6dSgd78059 static int bscv_ioc_test(bscv_soft_state_t *, intptr_t, int); 1521c42de6dSgd78059 static int bscv_ioc_mprog2(bscv_soft_state_t *, intptr_t, int); 1531c42de6dSgd78059 static int bscv_ioc_mread2(bscv_soft_state_t *, intptr_t, int); 1541c42de6dSgd78059 1551c42de6dSgd78059 static void bscv_event_daemon(void *); 1561c42de6dSgd78059 static void bscv_start_event_daemon(bscv_soft_state_t *); 1571c42de6dSgd78059 static int bscv_stop_event_daemon(bscv_soft_state_t *); 1581c42de6dSgd78059 static int bscv_pause_event_daemon(bscv_soft_state_t *); 1591c42de6dSgd78059 static void bscv_resume_event_daemon(bscv_soft_state_t *); 1601c42de6dSgd78059 static void bscv_event_process(bscv_soft_state_t *ssp, boolean_t); 1611c42de6dSgd78059 static int bscv_event_validate(bscv_soft_state_t *, uint32_t, uint8_t); 1621c42de6dSgd78059 static void bscv_event_process_one(bscv_soft_state_t *, lom_event_t *); 1631c42de6dSgd78059 static void bscv_build_eventstring(bscv_soft_state_t *, 1641c42de6dSgd78059 lom_event_t *, char *, char *); 1651c42de6dSgd78059 static int bscv_level_of_event(lom_event_t *); 1661c42de6dSgd78059 static void bscv_status(bscv_soft_state_t *, uint8_t, uint8_t); 1671c42de6dSgd78059 char *bscv_get_label(char [][MAX_LOM2_NAME_STR], int, int); 1681c42de6dSgd78059 static void bscv_generic_sysevent(bscv_soft_state_t *, char *, char *, char *, 1691c42de6dSgd78059 char *, int32_t, char *); 1701c42de6dSgd78059 static void bscv_sysevent(bscv_soft_state_t *, lom_event_t *); 1711c42de6dSgd78059 1721c42de6dSgd78059 static int bscv_prog(bscv_soft_state_t *, intptr_t, int); 1731c42de6dSgd78059 static int bscv_prog_image(bscv_soft_state_t *, boolean_t, 1741c42de6dSgd78059 uint8_t *, int, uint32_t); 1751c42de6dSgd78059 static int bscv_prog_receive_image(bscv_soft_state_t *, lom_prog_t *, 1761c42de6dSgd78059 uint8_t *, int); 1771c42de6dSgd78059 static void bscv_leave_programming_mode(bscv_soft_state_t *, boolean_t); 1781c42de6dSgd78059 static int bscv_prog_stop_lom(bscv_soft_state_t *); 1791c42de6dSgd78059 static int bscv_prog_start_lom(bscv_soft_state_t *); 1801c42de6dSgd78059 1811c42de6dSgd78059 static int bscv_attach_common(bscv_soft_state_t *); 1821c42de6dSgd78059 static int bscv_cleanup(bscv_soft_state_t *); 1831c42de6dSgd78059 static void bscv_setup_capability(bscv_soft_state_t *); 1841c42de6dSgd78059 static int bscv_probe_check(bscv_soft_state_t *); 1851c42de6dSgd78059 static void bscv_setup_hostname(bscv_soft_state_t *); 1861c42de6dSgd78059 static void bscv_read_hostname(bscv_soft_state_t *, char *); 1871c42de6dSgd78059 static void bscv_write_hostname(bscv_soft_state_t *, char *, uint8_t); 1881c42de6dSgd78059 static void bscv_setup_static_info(bscv_soft_state_t *); 1891c42de6dSgd78059 static uint8_t bscv_read_env_name(bscv_soft_state_t *, uint8_t, 1901c42de6dSgd78059 uint8_t, uint8_t, char [][MAX_LOM2_NAME_STR], int); 1911c42de6dSgd78059 static void bscv_setup_events(bscv_soft_state_t *); 1921c42de6dSgd78059 1931c42de6dSgd78059 static void bscv_trace(bscv_soft_state_t *, char, const char *, 1941c42de6dSgd78059 const char *, ...); 1951c42de6dSgd78059 1961c42de6dSgd78059 #ifdef __sparc 1971c42de6dSgd78059 static void bscv_idi_init(); 1981c42de6dSgd78059 static void bscv_idi_fini(); 1991c42de6dSgd78059 static void bscv_idi_new_instance(dev_info_t *dip); 2001c42de6dSgd78059 static void bscv_idi_clear_err(); 2011c42de6dSgd78059 void bscv_idi_set(struct bscv_idi_info info); 2021c42de6dSgd78059 static boolean_t bscv_idi_err(); 2031c42de6dSgd78059 static boolean_t bscv_nodename_set(struct bscv_idi_info info); 2041c42de6dSgd78059 static boolean_t bscv_sig_set(struct bscv_idi_info info); 2051c42de6dSgd78059 static boolean_t bscv_wdog_pat(struct bscv_idi_info info); 2061c42de6dSgd78059 static boolean_t bscv_wdog_cfg(struct bscv_idi_info info); 2071c42de6dSgd78059 static void bscv_write_sig(bscv_soft_state_t *ssp, bscv_sig_t s); 2081c42de6dSgd78059 #endif /* __sparc */ 2091c42de6dSgd78059 2101c42de6dSgd78059 static void bscv_setup_watchdog(bscv_soft_state_t *ssp); 2111c42de6dSgd78059 static void bscv_write_wdog_cfg(bscv_soft_state_t *, 2121c42de6dSgd78059 uint_t, boolean_t, uint8_t); 2131c42de6dSgd78059 2141c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 2151c42de6dSgd78059 static void bscv_inform_bsc(bscv_soft_state_t *, uint32_t); 2161c42de6dSgd78059 static void bscv_watchdog_pat_request(void *); 2171c42de6dSgd78059 static void bscv_watchdog_cfg_request(bscv_soft_state_t *, uint8_t); 2181c42de6dSgd78059 static uint_t bscv_set_watchdog_timer(bscv_soft_state_t *, uint_t); 2191c42de6dSgd78059 static void bscv_clear_watchdog_timer(bscv_soft_state_t *); 2201c42de6dSgd78059 2211c42de6dSgd78059 static boolean_t bscv_panic_callback(void *, int); 2221c42de6dSgd78059 static void bscv_watchdog_cyclic_add(bscv_soft_state_t *); 2231c42de6dSgd78059 static void bscv_watchdog_cyclic_remove(bscv_soft_state_t *); 2241c42de6dSgd78059 2251c42de6dSgd78059 static uint8_t wdog_reset_on_timeout = 1; 2261c42de6dSgd78059 2271c42de6dSgd78059 #define WDOG_ON 1 2281c42de6dSgd78059 #define WDOG_OFF 0 2291c42de6dSgd78059 #define CLK_WATCHDOG_DEFAULT 10 /* 10 seconds */ 2301c42de6dSgd78059 #define WATCHDOG_PAT_INTERVAL 1000000000 /* 1 second */ 2311c42de6dSgd78059 2321c42de6dSgd78059 static int bscv_watchdog_enable; 2331c42de6dSgd78059 static int bscv_watchdog_available; 2341c42de6dSgd78059 static int watchdog_activated; 2351c42de6dSgd78059 static uint_t bscv_watchdog_timeout_seconds; 2361c42de6dSgd78059 #endif /* __i386 || __amd64 */ 2371c42de6dSgd78059 2381c42de6dSgd78059 #ifdef __sparc 2391c42de6dSgd78059 struct bscv_idi_callout bscv_idi_callout_table[] = { 2401c42de6dSgd78059 {BSCV_IDI_NODENAME, &bscv_nodename_set }, 2411c42de6dSgd78059 {BSCV_IDI_SIG, &bscv_sig_set }, 2421c42de6dSgd78059 {BSCV_IDI_WDOG_PAT, &bscv_wdog_pat }, 2431c42de6dSgd78059 {BSCV_IDI_WDOG_CFG, &bscv_wdog_cfg }, 2441c42de6dSgd78059 {BSCV_IDI_NULL, NULL } 2451c42de6dSgd78059 }; 2461c42de6dSgd78059 2471c42de6dSgd78059 static struct bscv_idi_callout_mgr bscv_idi_mgr; 2481c42de6dSgd78059 #endif /* __sparc */ 2491c42de6dSgd78059 2501c42de6dSgd78059 /* 2511c42de6dSgd78059 * Local Definitions 2521c42de6dSgd78059 */ 2531c42de6dSgd78059 #define STATUS_READ_LIMIT 8 /* Read up to 8 status changes at a time */ 2541c42de6dSgd78059 #define MYNAME "bscv" 2551c42de6dSgd78059 #define BSCV_INST_TO_MINOR(i) (i) 2561c42de6dSgd78059 #define BSCV_MINOR_TO_INST(m) (m) 2571c42de6dSgd78059 2581c42de6dSgd78059 /* 2591c42de6dSgd78059 * Strings for daemon event reporting 2601c42de6dSgd78059 */ 2611c42de6dSgd78059 2621c42de6dSgd78059 static char *eventSubsysStrings[] = 2631c42de6dSgd78059 { "", /* 00 */ 2641c42de6dSgd78059 "Alarm ", /* 01 */ 2651c42de6dSgd78059 "temperature sensor ", /* 02 */ 2661c42de6dSgd78059 "overheat sensor ", /* 03 */ 2671c42de6dSgd78059 "Fan ", /* 04 */ 2681c42de6dSgd78059 "supply rail ", /* 05 */ 2691c42de6dSgd78059 "circuit breaker ", /* 06 */ 2701c42de6dSgd78059 "PSU ", /* 07 */ 2711c42de6dSgd78059 "user ", /* 08 */ 2721c42de6dSgd78059 "phonehome ", /* 09; unutilized */ 2731c42de6dSgd78059 "LOM ", /* 0a */ 2741c42de6dSgd78059 "host ", /* 0b */ 2751c42de6dSgd78059 "event log ", /* 0c */ 2761c42de6dSgd78059 "", /* 0d; EVENT_SUBSYS_EXTRA unutilized */ 2771c42de6dSgd78059 "LED ", /* 0e */ 2781c42de6dSgd78059 }; 2791c42de6dSgd78059 2801c42de6dSgd78059 static char *eventTypeStrings[] = 2811c42de6dSgd78059 { 2821c42de6dSgd78059 "[null event]", /* 00 */ 2831c42de6dSgd78059 "ON", /* 01 */ 2841c42de6dSgd78059 "OFF", /* 02 */ 2851c42de6dSgd78059 "state change", /* 03 */ 2861c42de6dSgd78059 "power on", /* 04 */ 2871c42de6dSgd78059 "power off", /* 05 */ 2881c42de6dSgd78059 "powered off unexpectedly", /* 06 */ 2891c42de6dSgd78059 "reset unexpectedly", /* 07 */ 2901c42de6dSgd78059 "booted", /* 08 */ 2911c42de6dSgd78059 "watchdog enabled", /* 09 */ 2921c42de6dSgd78059 "watchdog disabled", /* 0a */ 2931c42de6dSgd78059 "watchdog triggered", /* 0b */ 2941c42de6dSgd78059 "failed", /* 0c */ 2951c42de6dSgd78059 "recovered", /* 0d */ 2961c42de6dSgd78059 "reset", /* 0e */ 2971c42de6dSgd78059 "XIR reset", /* 0f */ 2981c42de6dSgd78059 "console selected", /* 10 */ 2991c42de6dSgd78059 "time reference", /* 11 */ 3001c42de6dSgd78059 "script failure", /* 12 */ 3011c42de6dSgd78059 "modem access failure", /* 13 */ 3021c42de6dSgd78059 "modem dialing failure", /* 14 */ 3031c42de6dSgd78059 "bad checksum", /* 15 */ 3041c42de6dSgd78059 "added", /* 16 */ 3051c42de6dSgd78059 "removed", /* 17 */ 3061c42de6dSgd78059 "changed", /* 18 */ 3071c42de6dSgd78059 "login", /* 19 */ 3081c42de6dSgd78059 "password changed", /* 1a */ 3091c42de6dSgd78059 "login failed", /* 1b */ 3101c42de6dSgd78059 "logout", /* 1c */ 3111c42de6dSgd78059 "flash download", /* 1d */ 3121c42de6dSgd78059 "data lost", /* 1e */ 3131c42de6dSgd78059 "device busy", /* 1f */ 3141c42de6dSgd78059 "fault led state", /* 20 */ 3151c42de6dSgd78059 "overheat", /* 21 */ 3161c42de6dSgd78059 "severe overheat", /* 22 */ 3171c42de6dSgd78059 "no overheat", /* 23 */ 3181c42de6dSgd78059 "SCC", /* 24 */ 3191c42de6dSgd78059 "device inaccessible", /* 25 */ 3201c42de6dSgd78059 "Hostname change", /* 26 */ 3211c42de6dSgd78059 "CPU signature timeout", /* 27 */ 3221c42de6dSgd78059 "Bootmode change", /* 28 */ 3231c42de6dSgd78059 "Watchdog change policy", /* 29 */ 3241c42de6dSgd78059 "Watchdog change timeout", /* 2a */ 3251c42de6dSgd78059 }; 3261c42de6dSgd78059 3271c42de6dSgd78059 /* 3281c42de6dSgd78059 * These store to mapping between the logical service, e.g. chan_prog for 3291c42de6dSgd78059 * programming, and the actual Xbus channel which carries that traffic. 3301c42de6dSgd78059 * Any services can be shared on the same channel apart from chan_wdogpat. 3311c42de6dSgd78059 */ 3321c42de6dSgd78059 static int chan_general; /* General Traffic */ 3331c42de6dSgd78059 static int chan_wdogpat; /* Watchdog Patting */ 3341c42de6dSgd78059 static int chan_cpusig; /* CPU signatures */ 3351c42de6dSgd78059 static int chan_eeprom; /* EEPROM I/O */ 3361c42de6dSgd78059 static int chan_prog; /* Programming */ 3371c42de6dSgd78059 3381c42de6dSgd78059 /* 3391c42de6dSgd78059 * cb_ops structure defining the driver entry points 3401c42de6dSgd78059 */ 3411c42de6dSgd78059 3421c42de6dSgd78059 static struct cb_ops bscv_cb_ops = { 3431c42de6dSgd78059 bscv_open, /* open */ 3441c42de6dSgd78059 bscv_close, /* close */ 3451c42de6dSgd78059 nodev, /* strategy */ 3461c42de6dSgd78059 nodev, /* print */ 3471c42de6dSgd78059 nodev, /* dump */ 3481c42de6dSgd78059 nodev, /* read */ 3491c42de6dSgd78059 nodev, /* write */ 3501c42de6dSgd78059 bscv_ioctl, /* ioctl */ 3511c42de6dSgd78059 nodev, /* devmap */ 3521c42de6dSgd78059 nodev, /* mmap */ 3531c42de6dSgd78059 nodev, /* segmap */ 3541c42de6dSgd78059 nochpoll, /* poll */ 3551c42de6dSgd78059 ddi_prop_op, /* prop op */ 3561c42de6dSgd78059 NULL, /* ! STREAMS */ 3571c42de6dSgd78059 D_NEW | D_MP /* MT/MP Safe */ 3581c42de6dSgd78059 }; 3591c42de6dSgd78059 3601c42de6dSgd78059 /* 3611c42de6dSgd78059 * dev_ops structure defining autoconfiguration driver autoconfiguration 3621c42de6dSgd78059 * routines 3631c42de6dSgd78059 */ 3641c42de6dSgd78059 3651c42de6dSgd78059 static struct dev_ops bscv_dev_ops = { 3661c42de6dSgd78059 DEVO_REV, /* devo_rev */ 3671c42de6dSgd78059 0, /* devo_refcnt */ 3681c42de6dSgd78059 bscv_getinfo, /* devo_getinfo */ 3691c42de6dSgd78059 nulldev, /* devo_identify */ 3701c42de6dSgd78059 nulldev, /* devo_probe */ 3711c42de6dSgd78059 bscv_attach, /* devo_attach */ 3721c42de6dSgd78059 bscv_detach, /* devo_detach */ 3731c42de6dSgd78059 bscv_reset, /* devo_reset */ 3741c42de6dSgd78059 &bscv_cb_ops, /* devo_cb_ops */ 37519397407SSherry Moore (struct bus_ops *)0, /* devo_bus_ops */ 37619397407SSherry Moore NULL, /* devo_power */ 37719397407SSherry Moore bscv_quiesce, /* devo_quiesce */ 3781c42de6dSgd78059 }; 3791c42de6dSgd78059 3801c42de6dSgd78059 /* 3811c42de6dSgd78059 * module configuration section 3821c42de6dSgd78059 */ 3831c42de6dSgd78059 3841c42de6dSgd78059 #ifdef DEBUG 38519397407SSherry Moore #define BSCV_VERSION_STRING "bscv driver - Debug" 3861c42de6dSgd78059 #else /* DEBUG */ 38719397407SSherry Moore #define BSCV_VERSION_STRING "bscv driver" 3881c42de6dSgd78059 #endif /* DEBUG */ 3891c42de6dSgd78059 3901c42de6dSgd78059 static struct modldrv modldrv = { 3911c42de6dSgd78059 &mod_driverops, 3921c42de6dSgd78059 BSCV_VERSION_STRING, 3931c42de6dSgd78059 &bscv_dev_ops, 3941c42de6dSgd78059 }; 3951c42de6dSgd78059 3961c42de6dSgd78059 static struct modlinkage modlinkage = { 3971c42de6dSgd78059 MODREV_1, 3981c42de6dSgd78059 &modldrv, 3991c42de6dSgd78059 NULL 4001c42de6dSgd78059 }; 4011c42de6dSgd78059 402*1af83355Sandrew.rutz@sun.com #ifdef DEBUG 403*1af83355Sandrew.rutz@sun.com /* Tracing is enabled if value is non-zero. */ 404*1af83355Sandrew.rutz@sun.com static int bscv_trace_flag = 1; 405*1af83355Sandrew.rutz@sun.com 406*1af83355Sandrew.rutz@sun.com #define BSCV_TRACE if (bscv_trace_flag != 0) bscv_trace 407*1af83355Sandrew.rutz@sun.com #else 408*1af83355Sandrew.rutz@sun.com #define BSCV_TRACE 409*1af83355Sandrew.rutz@sun.com #endif 410*1af83355Sandrew.rutz@sun.com 4111c42de6dSgd78059 /* 4121c42de6dSgd78059 * kernel accessible routines. These routines are necessarily global so the 4131c42de6dSgd78059 * driver can be loaded, and unloaded successfully 4141c42de6dSgd78059 */ 4151c42de6dSgd78059 4161c42de6dSgd78059 /* 4171c42de6dSgd78059 * function - _init 4181c42de6dSgd78059 * description - initializes the driver state structure and installs the 4191c42de6dSgd78059 * driver module into the kernel 4201c42de6dSgd78059 * inputs - none 4211c42de6dSgd78059 * outputs - success or failure of module installation 4221c42de6dSgd78059 */ 4231c42de6dSgd78059 4241c42de6dSgd78059 int 4251c42de6dSgd78059 _init(void) 4261c42de6dSgd78059 { 4271c42de6dSgd78059 register int e; 4281c42de6dSgd78059 4291c42de6dSgd78059 if ((e = ddi_soft_state_init(&bscv_statep, 4301c42de6dSgd78059 sizeof (bscv_soft_state_t), 1)) != 0) { 4311c42de6dSgd78059 return (e); 4321c42de6dSgd78059 } 4331c42de6dSgd78059 4341c42de6dSgd78059 if ((e = mod_install(&modlinkage)) != 0) { 4351c42de6dSgd78059 ddi_soft_state_fini(&bscv_statep); 4361c42de6dSgd78059 } 4371c42de6dSgd78059 4381c42de6dSgd78059 #ifdef __sparc 4391c42de6dSgd78059 if (e == 0) bscv_idi_init(); 4401c42de6dSgd78059 #endif /* __sparc */ 4411c42de6dSgd78059 return (e); 4421c42de6dSgd78059 } 4431c42de6dSgd78059 4441c42de6dSgd78059 /* 4451c42de6dSgd78059 * function - _info 4461c42de6dSgd78059 * description - provide information about a kernel loaded module 4471c42de6dSgd78059 * inputs - module infomation 4481c42de6dSgd78059 * outputs - success or failure of information request 4491c42de6dSgd78059 */ 4501c42de6dSgd78059 4511c42de6dSgd78059 int 4521c42de6dSgd78059 _info(struct modinfo *modinfop) 4531c42de6dSgd78059 { 4541c42de6dSgd78059 return (mod_info(&modlinkage, modinfop)); 4551c42de6dSgd78059 } 4561c42de6dSgd78059 4571c42de6dSgd78059 /* 4581c42de6dSgd78059 * function - _fini 4591c42de6dSgd78059 * description - removes a module from the kernel and frees the driver soft 4601c42de6dSgd78059 * state memory 4611c42de6dSgd78059 * inputs - none 4621c42de6dSgd78059 * outputs - success or failure of module removal 4631c42de6dSgd78059 */ 4641c42de6dSgd78059 4651c42de6dSgd78059 int 4661c42de6dSgd78059 _fini(void) 4671c42de6dSgd78059 { 4681c42de6dSgd78059 register int e; 4691c42de6dSgd78059 4701c42de6dSgd78059 if ((e = mod_remove(&modlinkage)) != 0) { 4711c42de6dSgd78059 return (e); 4721c42de6dSgd78059 } 4731c42de6dSgd78059 4741c42de6dSgd78059 #ifdef __sparc 4751c42de6dSgd78059 bscv_idi_fini(); 4761c42de6dSgd78059 #endif /* __sparc */ 4771c42de6dSgd78059 ddi_soft_state_fini(&bscv_statep); 4781c42de6dSgd78059 4791c42de6dSgd78059 return (e); 4801c42de6dSgd78059 } 4811c42de6dSgd78059 4821c42de6dSgd78059 /* 4831c42de6dSgd78059 * function - bscv_getinfo 4841c42de6dSgd78059 * description - routine used to provide information on the driver 4851c42de6dSgd78059 * inputs - device information structure, command, command arg, storage 4861c42de6dSgd78059 * area for the result 4871c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 4881c42de6dSgd78059 */ 4891c42de6dSgd78059 4901c42de6dSgd78059 /*ARGSUSED*/ 4911c42de6dSgd78059 static int 4921c42de6dSgd78059 bscv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 4931c42de6dSgd78059 { 4941c42de6dSgd78059 bscv_soft_state_t *ssp; 4951c42de6dSgd78059 dev_t dev = (dev_t)arg; 4961c42de6dSgd78059 int instance; 4971c42de6dSgd78059 int error; 4981c42de6dSgd78059 4991c42de6dSgd78059 instance = DEVICETOINSTANCE(dev); 5001c42de6dSgd78059 5011c42de6dSgd78059 switch (cmd) { 5021c42de6dSgd78059 case DDI_INFO_DEVT2INSTANCE: 5031c42de6dSgd78059 *result = (void *)(uintptr_t)instance; 5041c42de6dSgd78059 error = DDI_SUCCESS; 5051c42de6dSgd78059 break; 5061c42de6dSgd78059 5071c42de6dSgd78059 case DDI_INFO_DEVT2DEVINFO: 5081c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, instance); 5091c42de6dSgd78059 if (ssp == NULL) 5101c42de6dSgd78059 return (DDI_FAILURE); 5111c42de6dSgd78059 *result = (void *) ssp->dip; 5121c42de6dSgd78059 error = DDI_SUCCESS; 5131c42de6dSgd78059 break; 5141c42de6dSgd78059 5151c42de6dSgd78059 default: 5161c42de6dSgd78059 error = DDI_FAILURE; 5171c42de6dSgd78059 break; 5181c42de6dSgd78059 } 5191c42de6dSgd78059 5201c42de6dSgd78059 return (error); 5211c42de6dSgd78059 } 5221c42de6dSgd78059 5231c42de6dSgd78059 #ifdef __sparc 5241c42de6dSgd78059 void 5251c42de6dSgd78059 bscv_idi_init() 5261c42de6dSgd78059 { 5271c42de6dSgd78059 bscv_idi_mgr.valid_inst = (uint32_t)~0; /* No valid instances */ 5281c42de6dSgd78059 bscv_idi_mgr.tbl = bscv_idi_callout_table; 5291c42de6dSgd78059 bscv_idi_mgr.errs = 0; 5301c42de6dSgd78059 5311c42de6dSgd78059 /* 5321c42de6dSgd78059 * Now that all fields are initialized, set the magic flag. This is 5331c42de6dSgd78059 * a kind of integrity check for the data structure. 5341c42de6dSgd78059 */ 5351c42de6dSgd78059 bscv_idi_mgr.magic = BSCV_IDI_CALLOUT_MAGIC; 5361c42de6dSgd78059 } 5371c42de6dSgd78059 5381c42de6dSgd78059 static void 5391c42de6dSgd78059 bscv_idi_clear_err() 5401c42de6dSgd78059 { 5411c42de6dSgd78059 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC); 5421c42de6dSgd78059 5431c42de6dSgd78059 bscv_idi_mgr.errs = 0; 5441c42de6dSgd78059 } 5451c42de6dSgd78059 5461c42de6dSgd78059 /* 5471c42de6dSgd78059 * function - bscv_idi_err 5481c42de6dSgd78059 * description - error messaging service which throttles the number of error 5491c42de6dSgd78059 * messages to avoid overflowing storage 5501c42de6dSgd78059 * inputs - none 5511c42de6dSgd78059 * returns - boolean to indicate whether a message should be reported 5521c42de6dSgd78059 * side-effects - updates the error number counter 5531c42de6dSgd78059 */ 5541c42de6dSgd78059 static boolean_t 5551c42de6dSgd78059 bscv_idi_err() 5561c42de6dSgd78059 { 5571c42de6dSgd78059 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC); 5581c42de6dSgd78059 5591c42de6dSgd78059 bscv_idi_mgr.errs++; 5601c42de6dSgd78059 5611c42de6dSgd78059 if (bscv_idi_mgr.errs++ < BSCV_IDI_ERR_MSG_THRESHOLD) 5621c42de6dSgd78059 return (B_TRUE); 5631c42de6dSgd78059 5641c42de6dSgd78059 return (B_FALSE); 5651c42de6dSgd78059 } 5661c42de6dSgd78059 5671c42de6dSgd78059 void 5681c42de6dSgd78059 bscv_idi_new_instance(dev_info_t *dip) 5691c42de6dSgd78059 { 5701c42de6dSgd78059 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC); 5711c42de6dSgd78059 5721c42de6dSgd78059 /* 5731c42de6dSgd78059 * We don't care how many instances we have, or their value, so long 5741c42de6dSgd78059 * as we have at least one valid value. This is so service routines 5751c42de6dSgd78059 * can get any required locks via a soft state pointer. 5761c42de6dSgd78059 */ 5771c42de6dSgd78059 if (bscv_idi_mgr.valid_inst == (uint32_t)~0) { 5781c42de6dSgd78059 bscv_idi_mgr.valid_inst = ddi_get_instance(dip); 5791c42de6dSgd78059 } 5801c42de6dSgd78059 } 5811c42de6dSgd78059 5821c42de6dSgd78059 void 5831c42de6dSgd78059 bscv_idi_fini() 5841c42de6dSgd78059 { 5851c42de6dSgd78059 bscv_idi_mgr.valid_inst = (uint32_t)~0; /* No valid instances */ 5861c42de6dSgd78059 bscv_idi_mgr.tbl = NULL; 5871c42de6dSgd78059 } 5881c42de6dSgd78059 #endif /* __sparc */ 5891c42de6dSgd78059 5901c42de6dSgd78059 /* 5911c42de6dSgd78059 * function - bscv_attach 5921c42de6dSgd78059 * description - this routine is responsible for setting aside memory for the 5931c42de6dSgd78059 * driver data structures, initialising the mutexes and creating 5941c42de6dSgd78059 * the device minor nodes. Additionally, this routine calls the 5951c42de6dSgd78059 * the callback routine. 5961c42de6dSgd78059 * inputs - device information structure, DDI_ATTACH command 5971c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 5981c42de6dSgd78059 */ 5991c42de6dSgd78059 6001c42de6dSgd78059 int 6011c42de6dSgd78059 bscv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 6021c42de6dSgd78059 { 6031c42de6dSgd78059 bscv_soft_state_t *ssp; 6041c42de6dSgd78059 int instance; 6051c42de6dSgd78059 6061c42de6dSgd78059 switch (cmd) { 6071c42de6dSgd78059 case DDI_ATTACH: 6081c42de6dSgd78059 6091c42de6dSgd78059 instance = ddi_get_instance(dip); 6101c42de6dSgd78059 6111c42de6dSgd78059 if (ddi_soft_state_zalloc(bscv_statep, instance) != 6121c42de6dSgd78059 DDI_SUCCESS) { 6131c42de6dSgd78059 return (DDI_FAILURE); 6141c42de6dSgd78059 } 6151c42de6dSgd78059 6161c42de6dSgd78059 6171c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, instance); 6181c42de6dSgd78059 6191c42de6dSgd78059 ssp->progress = 0; 6201c42de6dSgd78059 6211c42de6dSgd78059 ssp->dip = dip; 6221c42de6dSgd78059 ssp->instance = instance; 6231c42de6dSgd78059 ssp->event_waiting = B_FALSE; 6241c42de6dSgd78059 ssp->status_change = B_FALSE; 6251c42de6dSgd78059 ssp->nodename_change = B_FALSE; 6261c42de6dSgd78059 ssp->cap0 = 0; 6271c42de6dSgd78059 ssp->cap1 = 0; 6281c42de6dSgd78059 ssp->cap2 = 0; 6291c42de6dSgd78059 ssp->prog_mode_only = B_FALSE; 6301c42de6dSgd78059 ssp->programming = B_FALSE; 6311c42de6dSgd78059 ssp->cssp_prog = B_FALSE; 6321c42de6dSgd78059 ssp->task_flags = 0; 6331c42de6dSgd78059 ssp->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 6341c42de6dSgd78059 DDI_PROP_DONTPASS, "debug", 0); 6351c42de6dSgd78059 ssp->majornum = ddi_driver_major(dip); 6361c42de6dSgd78059 ssp->minornum = BSCV_INST_TO_MINOR(instance); 6371c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 6381c42de6dSgd78059 ssp->last_nodename[0] = '\0'; 6391c42de6dSgd78059 #endif /* __i386 || __amd64 */ 6401c42de6dSgd78059 6411c42de6dSgd78059 /* 6421c42de6dSgd78059 * initialise the mutexes 6431c42de6dSgd78059 */ 6441c42de6dSgd78059 6451c42de6dSgd78059 mutex_init(&ssp->cmd_mutex, NULL, MUTEX_DRIVER, NULL); 6461c42de6dSgd78059 6471c42de6dSgd78059 mutex_init(&ssp->task_mu, NULL, MUTEX_DRIVER, NULL); 6481c42de6dSgd78059 cv_init(&ssp->task_cv, NULL, CV_DRIVER, NULL); 6491c42de6dSgd78059 cv_init(&ssp->task_evnt_cv, NULL, CV_DRIVER, NULL); 6501c42de6dSgd78059 mutex_init(&ssp->prog_mu, NULL, MUTEX_DRIVER, NULL); 6511c42de6dSgd78059 ssp->progress |= BSCV_LOCKS; 6521c42de6dSgd78059 653*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_attach", 6541c42de6dSgd78059 "bscv_attach: mutexes and condition vars initialised"); 6551c42de6dSgd78059 6561c42de6dSgd78059 /* Map in physical communication channels */ 6571c42de6dSgd78059 6581c42de6dSgd78059 if (bscv_map_regs(ssp) != DDI_SUCCESS) { 6591c42de6dSgd78059 (void) bscv_cleanup(ssp); 6601c42de6dSgd78059 return (DDI_FAILURE); 6611c42de6dSgd78059 } 6621c42de6dSgd78059 ssp->progress |= BSCV_MAPPED_REGS; 6631c42de6dSgd78059 6641c42de6dSgd78059 /* Associate logical channels to physical channels */ 6651c42de6dSgd78059 6661c42de6dSgd78059 bscv_map_chan_logical_physical(ssp); 6671c42de6dSgd78059 6681c42de6dSgd78059 bscv_enter(ssp); 6691c42de6dSgd78059 6701c42de6dSgd78059 bscv_leave_programming_mode(ssp, B_FALSE); 6711c42de6dSgd78059 6721c42de6dSgd78059 if (bscv_attach_common(ssp) == DDI_FAILURE) { 6731c42de6dSgd78059 bscv_exit(ssp); 6741c42de6dSgd78059 (void) bscv_cleanup(ssp); 6751c42de6dSgd78059 return (DDI_FAILURE); 6761c42de6dSgd78059 } 6771c42de6dSgd78059 6781c42de6dSgd78059 #ifdef __sparc 6791c42de6dSgd78059 /* 6801c42de6dSgd78059 * At this point the inter-driver-interface is made available. 6811c42de6dSgd78059 * The IDI uses the event thread service which 6821c42de6dSgd78059 * bscv_attach_common() sets up. 6831c42de6dSgd78059 */ 6841c42de6dSgd78059 bscv_idi_new_instance(dip); 6851c42de6dSgd78059 #endif /* __sparc */ 6861c42de6dSgd78059 6871c42de6dSgd78059 bscv_exit(ssp); 6881c42de6dSgd78059 6891c42de6dSgd78059 /* 6901c42de6dSgd78059 * now create the minor nodes 6911c42de6dSgd78059 */ 6921c42de6dSgd78059 if (ddi_create_minor_node(ssp->dip, "lom", S_IFCHR, 6931c42de6dSgd78059 BSCV_INST_TO_MINOR(instance), 6941c42de6dSgd78059 DDI_PSEUDO, 0) != DDI_SUCCESS) { 6951c42de6dSgd78059 (void) bscv_cleanup(ssp); 6961c42de6dSgd78059 return (DDI_FAILURE); 6971c42de6dSgd78059 } 698*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_attach", 6991c42de6dSgd78059 "bscv_attach: device minor nodes created"); 7001c42de6dSgd78059 ssp->progress |= BSCV_NODES; 7011c42de6dSgd78059 7021c42de6dSgd78059 if (!ssp->prog_mode_only) 7031c42de6dSgd78059 bscv_start_event_daemon(ssp); 7041c42de6dSgd78059 7051c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 7061c42de6dSgd78059 bscv_watchdog_enable = 1; 7071c42de6dSgd78059 bscv_watchdog_available = 1; 7081c42de6dSgd78059 watchdog_activated = 0; 7091c42de6dSgd78059 bscv_watchdog_timeout_seconds = CLK_WATCHDOG_DEFAULT; 7101c42de6dSgd78059 7111c42de6dSgd78059 if (bscv_watchdog_enable && (boothowto & RB_DEBUG)) { 7121c42de6dSgd78059 bscv_watchdog_available = 0; 7131c42de6dSgd78059 cmn_err(CE_WARN, "bscv: kernel debugger " 7141c42de6dSgd78059 "detected: hardware watchdog disabled"); 7151c42de6dSgd78059 } 7161c42de6dSgd78059 7171c42de6dSgd78059 /* 7181c42de6dSgd78059 * Before we enable the watchdog - register the panic 7191c42de6dSgd78059 * callback so that we get called to stop the watchdog 7201c42de6dSgd78059 * in the case of a panic. 7211c42de6dSgd78059 */ 7221c42de6dSgd78059 ssp->callb_id = callb_add(bscv_panic_callback, 7231c42de6dSgd78059 (void *)ssp, CB_CL_PANIC, ""); 7241c42de6dSgd78059 7251c42de6dSgd78059 if (bscv_watchdog_available) { 7261c42de6dSgd78059 (void) bscv_set_watchdog_timer(ssp, 7271c42de6dSgd78059 CLK_WATCHDOG_DEFAULT); 7281c42de6dSgd78059 bscv_enter(ssp); 7291c42de6dSgd78059 bscv_setup_watchdog(ssp); /* starts cyclic callback */ 7301c42de6dSgd78059 bscv_exit(ssp); 7311c42de6dSgd78059 } 7321c42de6dSgd78059 #endif /* __i386 || __amd64 */ 7331c42de6dSgd78059 ddi_report_dev(dip); 7341c42de6dSgd78059 return (DDI_SUCCESS); 7351c42de6dSgd78059 default: 7361c42de6dSgd78059 return (DDI_FAILURE); 7371c42de6dSgd78059 } 7381c42de6dSgd78059 } 7391c42de6dSgd78059 7401c42de6dSgd78059 /* 7411c42de6dSgd78059 * function - bscv_detach 7421c42de6dSgd78059 * description - routine that prepares a module to be unloaded. It undoes all 7431c42de6dSgd78059 * the work done by the bscv_attach)() routine. This is 7441c42de6dSgd78059 * facilitated by the use of the progress indicator 7451c42de6dSgd78059 * inputs - device information structure, DDI_DETACH command 7461c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 7471c42de6dSgd78059 */ 7481c42de6dSgd78059 7491c42de6dSgd78059 /*ARGSUSED*/ 7501c42de6dSgd78059 static int 7511c42de6dSgd78059 bscv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 7521c42de6dSgd78059 { 7531c42de6dSgd78059 return (DDI_FAILURE); 7541c42de6dSgd78059 } 7551c42de6dSgd78059 7561c42de6dSgd78059 /* 7571c42de6dSgd78059 * function - bscv_reset 758*1af83355Sandrew.rutz@sun.com * description - routine that implements the obsolete devo_reset entry point. 759*1af83355Sandrew.rutz@sun.com * MAN page declares that devo_quiesce subsumes devo_reset 760*1af83355Sandrew.rutz@sun.com * functionality. 7611c42de6dSgd78059 * inputs - device information structure, DDI_RESET command 7621c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 7631c42de6dSgd78059 */ 7641c42de6dSgd78059 static int 7651c42de6dSgd78059 bscv_reset(dev_info_t *dip, ddi_reset_cmd_t cmd) 7661c42de6dSgd78059 { 7671c42de6dSgd78059 switch (cmd) { 7681c42de6dSgd78059 case DDI_RESET_FORCE: 769*1af83355Sandrew.rutz@sun.com return (bscv_quiesce(dip)); 7701c42de6dSgd78059 default: 7711c42de6dSgd78059 return (DDI_FAILURE); 7721c42de6dSgd78059 } 7731c42de6dSgd78059 } 7741c42de6dSgd78059 7751c42de6dSgd78059 /* 77619397407SSherry Moore * quiesce(9E) entry point. 77719397407SSherry Moore * 77819397407SSherry Moore * This function is called when the system is single-threaded at high 77919397407SSherry Moore * PIL with preemption disabled. Therefore, this function must not be 78019397407SSherry Moore * blocked. 78119397407SSherry Moore * 78219397407SSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 78319397407SSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen. 78419397407SSherry Moore */ 78519397407SSherry Moore static int 78619397407SSherry Moore bscv_quiesce(dev_info_t *dip) 78719397407SSherry Moore { 78819397407SSherry Moore bscv_soft_state_t *ssp; 78919397407SSherry Moore int instance; 79019397407SSherry Moore 79119397407SSherry Moore 79219397407SSherry Moore instance = ddi_get_instance(dip); 79319397407SSherry Moore ssp = ddi_get_soft_state(bscv_statep, instance); 79419397407SSherry Moore if (ssp == NULL) { 79519397407SSherry Moore return (DDI_FAILURE); 79619397407SSherry Moore } 797*1af83355Sandrew.rutz@sun.com #ifdef DEBUG 798*1af83355Sandrew.rutz@sun.com /* Disable tracing, as we are executing at High-Interrupt level */ 799*1af83355Sandrew.rutz@sun.com bscv_trace_flag = 0; 800*1af83355Sandrew.rutz@sun.com #endif 801*1af83355Sandrew.rutz@sun.com /* quiesce the device */ 80219397407SSherry Moore bscv_full_stop(ssp); 803*1af83355Sandrew.rutz@sun.com 80419397407SSherry Moore return (DDI_SUCCESS); 80519397407SSherry Moore } 80619397407SSherry Moore 80719397407SSherry Moore /* 8081c42de6dSgd78059 * cb_ops routines 8091c42de6dSgd78059 */ 8101c42de6dSgd78059 8111c42de6dSgd78059 /* 8121c42de6dSgd78059 * function - bscv_open 8131c42de6dSgd78059 * description - routine to provide association between user fd and device 8141c42de6dSgd78059 * minor number. This routine is necessarily simple since a 8151c42de6dSgd78059 * read/write interface is not provided. Additionally, the 8161c42de6dSgd78059 * driver does not enforce exclusive access (FEXCL) or 8171c42de6dSgd78059 * non-blocking during an open (FNDELAY). Deferred attach is 8181c42de6dSgd78059 * supported. 8191c42de6dSgd78059 * inputs - device number, flag specifying open type, device type, 8201c42de6dSgd78059 * permissions 8211c42de6dSgd78059 * outputs - success or failure of operation 8221c42de6dSgd78059 */ 8231c42de6dSgd78059 8241c42de6dSgd78059 /*ARGSUSED*/ 8251c42de6dSgd78059 static int 8261c42de6dSgd78059 bscv_open(dev_t *devp, int flag, int otype, cred_t *cred) 8271c42de6dSgd78059 { 8281c42de6dSgd78059 bscv_soft_state_t *ssp; 8291c42de6dSgd78059 int instance; 8301c42de6dSgd78059 8311c42de6dSgd78059 instance = DEVICETOINSTANCE(*devp); 8321c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, instance); 8331c42de6dSgd78059 if (ssp == NULL) { 8341c42de6dSgd78059 return (ENXIO); /* not attached yet */ 8351c42de6dSgd78059 } 836*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'O', "bscv_open", "instance 0x%x", instance); 8371c42de6dSgd78059 8381c42de6dSgd78059 if (otype != OTYP_CHR) { 8391c42de6dSgd78059 return (EINVAL); 8401c42de6dSgd78059 } 8411c42de6dSgd78059 8421c42de6dSgd78059 return (0); 8431c42de6dSgd78059 } 8441c42de6dSgd78059 8451c42de6dSgd78059 /* 8461c42de6dSgd78059 * function - bscv_close 8471c42de6dSgd78059 * description - routine to perform the final close on the device. As per the 8481c42de6dSgd78059 * open routine, neither FEXCL or FNDELAY accesses are enforced 8491c42de6dSgd78059 * by the driver. 8501c42de6dSgd78059 * inputs - device number,flag specifying open type, device type, 8511c42de6dSgd78059 * permissions 8521c42de6dSgd78059 * outputs - success or failure of operation 8531c42de6dSgd78059 */ 8541c42de6dSgd78059 8551c42de6dSgd78059 /*ARGSUSED1*/ 8561c42de6dSgd78059 static int 8571c42de6dSgd78059 bscv_close(dev_t dev, int flag, int otype, cred_t *cred) 8581c42de6dSgd78059 { 8591c42de6dSgd78059 bscv_soft_state_t *ssp; 8601c42de6dSgd78059 int instance; 8611c42de6dSgd78059 8621c42de6dSgd78059 instance = DEVICETOINSTANCE(dev); 8631c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, instance); 8641c42de6dSgd78059 if (ssp == NULL) { 8651c42de6dSgd78059 return (ENXIO); 8661c42de6dSgd78059 } 867*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'O', "bscv_close", "instance 0x%x", instance); 8681c42de6dSgd78059 8691c42de6dSgd78059 return (0); 8701c42de6dSgd78059 } 8711c42de6dSgd78059 8721c42de6dSgd78059 static int 8731c42de6dSgd78059 bscv_map_regs(bscv_soft_state_t *ssp) 8741c42de6dSgd78059 { 8751c42de6dSgd78059 int i; 8761c42de6dSgd78059 int retval; 8771c42de6dSgd78059 int *props; 8781c42de6dSgd78059 unsigned int nelements; 8791c42de6dSgd78059 8801c42de6dSgd78059 ASSERT(ssp); 8811c42de6dSgd78059 8821c42de6dSgd78059 ssp->nchannels = 0; 8831c42de6dSgd78059 8841c42de6dSgd78059 /* 8851c42de6dSgd78059 * Work out how many channels are available by looking at the number 8861c42de6dSgd78059 * of elements of the regs property array. 8871c42de6dSgd78059 */ 8881c42de6dSgd78059 retval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ssp->dip, 8891c42de6dSgd78059 DDI_PROP_DONTPASS, "reg", &props, &nelements); 8901c42de6dSgd78059 8911c42de6dSgd78059 /* We don't need props anymore. Free memory if it was allocated */ 8921c42de6dSgd78059 if (retval == DDI_PROP_SUCCESS) 8931c42de6dSgd78059 ddi_prop_free(props); 8941c42de6dSgd78059 8951c42de6dSgd78059 /* Check for sanity of nelements */ 8961c42de6dSgd78059 if (retval != DDI_PROP_SUCCESS) { 897*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_map_regs", "lookup reg returned" 8981c42de6dSgd78059 " 0x%x", retval); 8991c42de6dSgd78059 goto cleanup_exit; 9001c42de6dSgd78059 } else if (nelements % LOMBUS_REGSPEC_SIZE != 0) { 901*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_map_regs", "nelements %d not" 9021c42de6dSgd78059 " a multiple of %d", nelements, LOMBUS_REGSPEC_SIZE); 9031c42de6dSgd78059 goto cleanup_exit; 9041c42de6dSgd78059 } else if (nelements > BSCV_MAXCHANNELS * LOMBUS_REGSPEC_SIZE) { 905*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_map_regs", "nelements %d too large" 9061c42de6dSgd78059 ", probably a misconfiguration", nelements); 9071c42de6dSgd78059 goto cleanup_exit; 9081c42de6dSgd78059 } else if (nelements < BSCV_MINCHANNELS * LOMBUS_REGSPEC_SIZE) { 909*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_map_regs", "nelements %d too small" 9101c42de6dSgd78059 ", need to have at least a general and a wdog channel", 9111c42de6dSgd78059 nelements); 9121c42de6dSgd78059 goto cleanup_exit; 9131c42de6dSgd78059 } 9141c42de6dSgd78059 9151c42de6dSgd78059 ssp->nchannels = nelements / LOMBUS_REGSPEC_SIZE; 9161c42de6dSgd78059 9171c42de6dSgd78059 ssp->attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 9181c42de6dSgd78059 ssp->attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 9191c42de6dSgd78059 ssp->attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 9201c42de6dSgd78059 9211c42de6dSgd78059 for (i = 0; i < ssp->nchannels; i++) { 9221c42de6dSgd78059 retval = ddi_regs_map_setup(ssp->dip, i, 9231c42de6dSgd78059 (caddr_t *)&ssp->channel[i].regs, 9241c42de6dSgd78059 0, 0, &ssp->attr, &ssp->channel[i].handle); 9251c42de6dSgd78059 if (retval != DDI_SUCCESS) { 926*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_map_regs", "map failure" 9271c42de6dSgd78059 " 0x%x on space %d", retval, i); 9281c42de6dSgd78059 9291c42de6dSgd78059 /* Rewind all current mappings - avoiding failed one */ 9301c42de6dSgd78059 i--; 9311c42de6dSgd78059 for (; i >= 0; i--) { 9321c42de6dSgd78059 ddi_regs_map_free(&ssp->channel[i].handle); 9331c42de6dSgd78059 } 9341c42de6dSgd78059 9351c42de6dSgd78059 goto cleanup_exit; 9361c42de6dSgd78059 } 9371c42de6dSgd78059 } 9381c42de6dSgd78059 9391c42de6dSgd78059 return (DDI_SUCCESS); 9401c42de6dSgd78059 9411c42de6dSgd78059 cleanup_exit: 9421c42de6dSgd78059 /* 9431c42de6dSgd78059 * It is important to set nchannels to 0 even if, say, only one of 9441c42de6dSgd78059 * the two required handles was mapped. If we cannot achieve our 9451c42de6dSgd78059 * minimum config its not safe to do any IO; this keeps our failure 9461c42de6dSgd78059 * mode handling simpler. 9471c42de6dSgd78059 */ 9481c42de6dSgd78059 ssp->nchannels = 0; 9491c42de6dSgd78059 return (DDI_FAILURE); 9501c42de6dSgd78059 } 9511c42de6dSgd78059 9521c42de6dSgd78059 static void 9531c42de6dSgd78059 bscv_unmap_regs(bscv_soft_state_t *ssp) 9541c42de6dSgd78059 { 9551c42de6dSgd78059 int i; 9561c42de6dSgd78059 9571c42de6dSgd78059 ASSERT(ssp); 9581c42de6dSgd78059 9591c42de6dSgd78059 for (i = 0; i < ssp->nchannels; i++) { 9601c42de6dSgd78059 ddi_regs_map_free(&ssp->channel[i].handle); 9611c42de6dSgd78059 } 9621c42de6dSgd78059 } 9631c42de6dSgd78059 9641c42de6dSgd78059 /* 9651c42de6dSgd78059 * Map logical services onto physical XBus channels. 9661c42de6dSgd78059 */ 9671c42de6dSgd78059 static void 9681c42de6dSgd78059 bscv_map_chan_logical_physical(bscv_soft_state_t *ssp) 9691c42de6dSgd78059 { 9701c42de6dSgd78059 ASSERT(ssp); 9711c42de6dSgd78059 9721c42de6dSgd78059 /* 9731c42de6dSgd78059 * We can assert that there will always be at least two channels, 9741c42de6dSgd78059 * to allow watchdog pats to be segregated from all other traffic. 9751c42de6dSgd78059 */ 9761c42de6dSgd78059 chan_general = 0; 9771c42de6dSgd78059 chan_wdogpat = 1; 9781c42de6dSgd78059 9791c42de6dSgd78059 /* 9801c42de6dSgd78059 * By default move all other services onto the generic channel unless 9811c42de6dSgd78059 * the hardware supports additional channels. 9821c42de6dSgd78059 */ 9831c42de6dSgd78059 9841c42de6dSgd78059 chan_cpusig = chan_eeprom = chan_prog = chan_general; 9851c42de6dSgd78059 9861c42de6dSgd78059 if (ssp->nchannels > 2) 9871c42de6dSgd78059 chan_cpusig = 2; 9881c42de6dSgd78059 if (ssp->nchannels > 3) 9891c42de6dSgd78059 chan_eeprom = 3; 9901c42de6dSgd78059 if (ssp->nchannels > 4) 9911c42de6dSgd78059 chan_prog = 4; 9921c42de6dSgd78059 } 9931c42de6dSgd78059 9941c42de6dSgd78059 9951c42de6dSgd78059 /* 9961c42de6dSgd78059 * function - bscv_full_stop 9971c42de6dSgd78059 * description - gracefully shut the lom down during panic or reboot. 998*1af83355Sandrew.rutz@sun.com * Disables the watchdog and sets up serial event reporting. 9991c42de6dSgd78059 * inputs - soft state pointer 10001c42de6dSgd78059 * outputs - none 10011c42de6dSgd78059 */ 10021c42de6dSgd78059 void 10031c42de6dSgd78059 bscv_full_stop(bscv_soft_state_t *ssp) 10041c42de6dSgd78059 { 10051c42de6dSgd78059 uint8_t bits2set = 0; 10061c42de6dSgd78059 uint8_t bits2clear = 0; 1007*1af83355Sandrew.rutz@sun.com int obtained_lock; 10081c42de6dSgd78059 1009*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'W', "bscv_full_stop", 10101c42de6dSgd78059 "turning off watchdog"); 10111c42de6dSgd78059 1012*1af83355Sandrew.rutz@sun.com /* 1013*1af83355Sandrew.rutz@sun.com * Obtain the softstate lock only if it is not already owned, 1014*1af83355Sandrew.rutz@sun.com * as this function can be called from a High-level interrupt 1015*1af83355Sandrew.rutz@sun.com * context. As a result, our thread cannot sleep. 1016*1af83355Sandrew.rutz@sun.com * At end of function, our thread releases the lock only if 1017*1af83355Sandrew.rutz@sun.com * it acquired the lock. 1018*1af83355Sandrew.rutz@sun.com */ 1019*1af83355Sandrew.rutz@sun.com obtained_lock = (bscv_tryenter(ssp) != 0); 10201c42de6dSgd78059 10211c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 10221c42de6dSgd78059 if (ddi_in_panic()) { 10231c42de6dSgd78059 bscv_inform_bsc(ssp, BSC_INFORM_PANIC); 10241c42de6dSgd78059 } else { 10251c42de6dSgd78059 bscv_inform_bsc(ssp, BSC_INFORM_OFFLINE); 10261c42de6dSgd78059 } 10271c42de6dSgd78059 #endif /* __i386 || __amd64 */ 10281c42de6dSgd78059 10291c42de6dSgd78059 /* set serial event reporting */ 10301c42de6dSgd78059 switch (ssp->serial_reporting) { 10311c42de6dSgd78059 case LOM_SER_EVENTS_ON: 10321c42de6dSgd78059 case LOM_SER_EVENTS_DEF: 10331c42de6dSgd78059 /* Make sure serial event reporting is on */ 10341c42de6dSgd78059 bits2clear = EBUS_ALARM_NOEVENTS; 10351c42de6dSgd78059 break; 10361c42de6dSgd78059 case LOM_SER_EVENTS_OFF: 10371c42de6dSgd78059 /* Make sure serial event reporting is on */ 10381c42de6dSgd78059 bits2set = EBUS_ALARM_NOEVENTS; 10391c42de6dSgd78059 break; 10401c42de6dSgd78059 default: 10411c42de6dSgd78059 break; 10421c42de6dSgd78059 } 10431c42de6dSgd78059 bscv_setclear8_volatile(ssp, chan_general, 10441c42de6dSgd78059 EBUS_IDX_ALARM, bits2set, bits2clear); 10451c42de6dSgd78059 1046*1af83355Sandrew.rutz@sun.com /* Do not free the lock if our thread did not obtain it. */ 1047*1af83355Sandrew.rutz@sun.com if (obtained_lock != 0) { 10481c42de6dSgd78059 bscv_exit(ssp); 10491c42de6dSgd78059 } 1050*1af83355Sandrew.rutz@sun.com } 10511c42de6dSgd78059 10521c42de6dSgd78059 /* 10531c42de6dSgd78059 * LOM I/O routines. 10541c42de6dSgd78059 * 10551c42de6dSgd78059 * locking 10561c42de6dSgd78059 * 10571c42de6dSgd78059 * Two sets of routines are provided: 10581c42de6dSgd78059 * normal - must be called after acquiring an appropriate lock. 10591c42de6dSgd78059 * locked - perform all the locking required and return any error 10601c42de6dSgd78059 * code in the supplied 'res' argument. If there is no 10611c42de6dSgd78059 * error 'res' is not changed. 10621c42de6dSgd78059 * The locked routines are designed for use in ioctl commands where 10631c42de6dSgd78059 * only a single operation needs to be performed and the overhead of 10641c42de6dSgd78059 * locking and result checking adds significantly to code complexity. 10651c42de6dSgd78059 * 10661c42de6dSgd78059 * locking primitives 10671c42de6dSgd78059 * 10681c42de6dSgd78059 * bscv_enter() - acquires an I/O lock for the calling thread. 1069*1af83355Sandrew.rutz@sun.com * bscv_tryenter() - conditionally acquires an I/O lock for calling thread. 10701c42de6dSgd78059 * bscv_exit() - releases an I/O lock acquired by bscv_enter(). 10711c42de6dSgd78059 * bscv_held() - used to assert ownership of an I/O lock. 10721c42de6dSgd78059 * 10731c42de6dSgd78059 * normal I/O routines 10741c42de6dSgd78059 * 10751c42de6dSgd78059 * Note bscv_{put|get}{16|32} routines are big-endian. This assumes that 10761c42de6dSgd78059 * the firmware works that way too. 10771c42de6dSgd78059 * 10781c42de6dSgd78059 * bscv_put8(), bscv_put16, bscv_put32 - write values to the LOM 10791c42de6dSgd78059 * and handle any retries if necessary. 10801c42de6dSgd78059 * 16 and 32 bit values are big-endian. 10811c42de6dSgd78059 * bscv_get8(), bscv_get16, bscv_get32 - read values from the LOM 10821c42de6dSgd78059 * and handle any retries if necessary. 10831c42de6dSgd78059 * 16 and 32 bit values are big-endian. 10841c42de6dSgd78059 * bscv_setclear8() - set or clear the specified bits in the register 10851c42de6dSgd78059 * at the supplied address. 10861c42de6dSgd78059 * bscv_setclear8_volatile() - set or clear the specified bits in the 10871c42de6dSgd78059 * register at the supplied address. If the lom reports 10881c42de6dSgd78059 * that the registers has changed since the last read 10891c42de6dSgd78059 * re-read and apply the set or clear to the new bits. 10901c42de6dSgd78059 * bscv_get8_cached() - Return a cached register value (addr < 0x80). 10911c42de6dSgd78059 * Does not access the hardware. A read of the hardware 10921c42de6dSgd78059 * automatically updates this cache. 10931c42de6dSgd78059 * 10941c42de6dSgd78059 * locked I/O routines 10951c42de6dSgd78059 * 10961c42de6dSgd78059 * bscv_get8_locked(), bscv_rep_get8_locked(). 10971c42de6dSgd78059 * 10981c42de6dSgd78059 * Call the indicated function from above, but wrapping it with 10991c42de6dSgd78059 * bscv_enter()/bscv_exit(). 11001c42de6dSgd78059 * 11011c42de6dSgd78059 * 11021c42de6dSgd78059 * Fault management 11031c42de6dSgd78059 * 11041c42de6dSgd78059 * LOM communications fault are grouped into three categories: 11051c42de6dSgd78059 * 1) Faulty - the LOM is not responding and no attempt to communicate 11061c42de6dSgd78059 * with it should be made. 11071c42de6dSgd78059 * 2) Transient fault - something which might recover after a retry 11081c42de6dSgd78059 * but which doesn't affect our ability to perform other 11091c42de6dSgd78059 * commands. 11101c42de6dSgd78059 * 3) Command error - an inappropriate command was executed. A retry 11111c42de6dSgd78059 * will not fix it but the command failed. 11121c42de6dSgd78059 * 11131c42de6dSgd78059 * The current implementation of the bscv driver is not very good at 11141c42de6dSgd78059 * noticing command errors due to the structure of the original code 11151c42de6dSgd78059 * that it is based on. It is possible to extend the driver to do this 11161c42de6dSgd78059 * and would probably involve having a concept of a "session error" 11171c42de6dSgd78059 * which is less severe than a fault but means that a sequence of 11181c42de6dSgd78059 * commands had some fault which cannot be recovered. 11191c42de6dSgd78059 * 11201c42de6dSgd78059 * 11211c42de6dSgd78059 * faults 11221c42de6dSgd78059 * 11231c42de6dSgd78059 * bscv_faulty() - returns B_TRUE if the LOM (communications) have been 11241c42de6dSgd78059 * declared faulty. 11251c42de6dSgd78059 * bscv_clear_fault() - marks the LOM as not faulty. 11261c42de6dSgd78059 * bscv_set_fault() - marks the LOM as being faulty. 11271c42de6dSgd78059 * 11281c42de6dSgd78059 * bscv_clear_fault and bscv_set_fault should generally not be called 11291c42de6dSgd78059 * directly. 11301c42de6dSgd78059 * 11311c42de6dSgd78059 * command errors/transient faults 11321c42de6dSgd78059 * 11331c42de6dSgd78059 * bscv_retcode() - returns the actual error code of the last operation. 11341c42de6dSgd78059 * bscv_should_retry() - determines if last operation may suceed if 11351c42de6dSgd78059 * retried. 11361c42de6dSgd78059 * bscv_locked_result() - Set the result of a locked register access. 11371c42de6dSgd78059 * 11381c42de6dSgd78059 * low level I/O primitives 11391c42de6dSgd78059 * 11401c42de6dSgd78059 * These are generally not called directly. These perform a single 11411c42de6dSgd78059 * access to the LOM device. They do not handle retries. 11421c42de6dSgd78059 * 11431c42de6dSgd78059 * bscv_put8_once() 11441c42de6dSgd78059 * bscv_get8_once() 11451c42de6dSgd78059 * bscv_probe() - perform a probe (NOP) operation to check out lom comms. 11461c42de6dSgd78059 * bscv_resync_comms() - resynchronise communications after a transient fault. 11471c42de6dSgd78059 */ 11481c42de6dSgd78059 11491c42de6dSgd78059 static void 11501c42de6dSgd78059 bscv_enter(bscv_soft_state_t *ssp) 11511c42de6dSgd78059 { 1152*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_enter", ""); 11531c42de6dSgd78059 mutex_enter(&ssp->cmd_mutex); 11541c42de6dSgd78059 ssp->had_session_error = B_FALSE; 11551c42de6dSgd78059 } 11561c42de6dSgd78059 1157*1af83355Sandrew.rutz@sun.com static int 1158*1af83355Sandrew.rutz@sun.com bscv_tryenter(bscv_soft_state_t *ssp) 1159*1af83355Sandrew.rutz@sun.com { 1160*1af83355Sandrew.rutz@sun.com int rv; 1161*1af83355Sandrew.rutz@sun.com 1162*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_tryenter", ""); 1163*1af83355Sandrew.rutz@sun.com if ((rv = mutex_tryenter(&ssp->cmd_mutex)) != 0) { 1164*1af83355Sandrew.rutz@sun.com ssp->had_session_error = B_FALSE; 1165*1af83355Sandrew.rutz@sun.com } 1166*1af83355Sandrew.rutz@sun.com return (rv); 1167*1af83355Sandrew.rutz@sun.com } 1168*1af83355Sandrew.rutz@sun.com 11691c42de6dSgd78059 static void 11701c42de6dSgd78059 bscv_exit(bscv_soft_state_t *ssp) 11711c42de6dSgd78059 { 11721c42de6dSgd78059 mutex_exit(&ssp->cmd_mutex); 1173*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_exit", ""); 11741c42de6dSgd78059 } 11751c42de6dSgd78059 11761c42de6dSgd78059 #ifdef DEBUG 11771c42de6dSgd78059 static int 11781c42de6dSgd78059 bscv_held(bscv_soft_state_t *ssp) 11791c42de6dSgd78059 { 11801c42de6dSgd78059 return (mutex_owned(&ssp->cmd_mutex)); 11811c42de6dSgd78059 } 11821c42de6dSgd78059 #endif /* DEBUG */ 11831c42de6dSgd78059 11841c42de6dSgd78059 static void 11851c42de6dSgd78059 bscv_put8(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint8_t val) 11861c42de6dSgd78059 { 11871c42de6dSgd78059 boolean_t needretry; 11881c42de6dSgd78059 int num_failures; 11891c42de6dSgd78059 11901c42de6dSgd78059 ASSERT(bscv_held(ssp)); 11911c42de6dSgd78059 11921c42de6dSgd78059 if (bscv_faulty(ssp)) { 11931c42de6dSgd78059 return; 11941c42de6dSgd78059 } 11951c42de6dSgd78059 1196*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_put8", 11971c42de6dSgd78059 "addr 0x%x.%02x <= 0x%02x", addr >> 8, addr & 0xff, val); 11981c42de6dSgd78059 11991c42de6dSgd78059 for (num_failures = 0; 12001c42de6dSgd78059 num_failures < BSC_FAILURE_RETRY_LIMIT; 12011c42de6dSgd78059 num_failures++) { 12021c42de6dSgd78059 bscv_put8_once(ssp, chan, addr, val); 12031c42de6dSgd78059 needretry = bscv_should_retry(ssp); 12041c42de6dSgd78059 if (!needretry) { 12051c42de6dSgd78059 break; 12061c42de6dSgd78059 } 12071c42de6dSgd78059 } 12081c42de6dSgd78059 if (ssp->command_error != 0) { 12091c42de6dSgd78059 ssp->had_session_error = B_TRUE; 12101c42de6dSgd78059 } 12111c42de6dSgd78059 12121c42de6dSgd78059 if (needretry) { 12131c42de6dSgd78059 /* Failure - we ran out of retries */ 12141c42de6dSgd78059 cmn_err(CE_WARN, "bscv_put8: addr 0x%x.%02x retried " 12151c42de6dSgd78059 "write %d times, giving up", 12161c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 12171c42de6dSgd78059 bscv_set_fault(ssp); 12181c42de6dSgd78059 } else if (num_failures > 0) { 1219*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'R', "bscv_put8", 12201c42de6dSgd78059 "addr 0x%x.%02x retried write %d times, succeeded", 12211c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 12221c42de6dSgd78059 } 12231c42de6dSgd78059 } 12241c42de6dSgd78059 12251c42de6dSgd78059 static void 12261c42de6dSgd78059 bscv_put16(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint16_t val) 12271c42de6dSgd78059 { 12281c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1229*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_put16", 12301c42de6dSgd78059 "addr 0x%x.%02x <= %04x", addr >> 8, addr & 0xff, val); 12311c42de6dSgd78059 bscv_put8(ssp, chan, addr, val >> 8); 12321c42de6dSgd78059 bscv_put8(ssp, chan, addr + 1, val & 0xff); 12331c42de6dSgd78059 } 12341c42de6dSgd78059 12351c42de6dSgd78059 static void 12361c42de6dSgd78059 bscv_put32(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint32_t val) 12371c42de6dSgd78059 { 12381c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1239*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_put32", 12401c42de6dSgd78059 "addr 0x%x.%02x <= %08x", addr >> 8, addr & 0xff, val); 12411c42de6dSgd78059 bscv_put8(ssp, chan, addr, (val >> 24) & 0xff); 12421c42de6dSgd78059 bscv_put8(ssp, chan, addr + 1, (val >> 16) & 0xff); 12431c42de6dSgd78059 bscv_put8(ssp, chan, addr + 2, (val >> 8) & 0xff); 12441c42de6dSgd78059 bscv_put8(ssp, chan, addr + 3, val & 0xff); 12451c42de6dSgd78059 } 12461c42de6dSgd78059 12471c42de6dSgd78059 static uint8_t 12481c42de6dSgd78059 bscv_get8(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr) 12491c42de6dSgd78059 { 12501c42de6dSgd78059 uint8_t retval; 12511c42de6dSgd78059 boolean_t needretry; 12521c42de6dSgd78059 int num_failures; 12531c42de6dSgd78059 12541c42de6dSgd78059 ASSERT(bscv_held(ssp)); 12551c42de6dSgd78059 12561c42de6dSgd78059 if (bscv_faulty(ssp)) { 12571c42de6dSgd78059 return (0); 12581c42de6dSgd78059 } 12591c42de6dSgd78059 12601c42de6dSgd78059 for (num_failures = 0; 12611c42de6dSgd78059 num_failures < BSC_FAILURE_RETRY_LIMIT; 12621c42de6dSgd78059 num_failures++) { 12631c42de6dSgd78059 retval = bscv_get8_once(ssp, chan, addr); 12641c42de6dSgd78059 needretry = bscv_should_retry(ssp); 12651c42de6dSgd78059 if (!needretry) { 12661c42de6dSgd78059 break; 12671c42de6dSgd78059 } 12681c42de6dSgd78059 } 12691c42de6dSgd78059 if (ssp->command_error != 0) { 12701c42de6dSgd78059 ssp->had_session_error = B_TRUE; 12711c42de6dSgd78059 } 12721c42de6dSgd78059 12731c42de6dSgd78059 if (needretry) { 12741c42de6dSgd78059 /* Failure */ 12751c42de6dSgd78059 cmn_err(CE_WARN, "bscv_get8: addr 0x%x.%02x retried " 12761c42de6dSgd78059 "read %d times, giving up", 12771c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 12781c42de6dSgd78059 bscv_set_fault(ssp); 12791c42de6dSgd78059 } else if (num_failures > 0) { 1280*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'R', "bscv_get8", 12811c42de6dSgd78059 "addr 0x%x.%02x retried read %d times, succeeded", 12821c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 12831c42de6dSgd78059 } 12841c42de6dSgd78059 1285*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_get8", 12861c42de6dSgd78059 "addr 0x%x.%02x => %02x", addr >> 8, addr & 0xff, retval); 12871c42de6dSgd78059 return (retval); 12881c42de6dSgd78059 } 12891c42de6dSgd78059 12901c42de6dSgd78059 static uint16_t 12911c42de6dSgd78059 bscv_get16(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr) 12921c42de6dSgd78059 { 12931c42de6dSgd78059 uint16_t retval; 12941c42de6dSgd78059 12951c42de6dSgd78059 ASSERT(bscv_held(ssp)); 12961c42de6dSgd78059 12971c42de6dSgd78059 retval = bscv_get8(ssp, chan, addr) << 8; 12981c42de6dSgd78059 retval |= bscv_get8(ssp, chan, addr + 1); 12991c42de6dSgd78059 1300*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_get16", 13011c42de6dSgd78059 "addr 0x%x.%02x => %04x", addr >> 8, addr & 0xff, retval); 13021c42de6dSgd78059 return (retval); 13031c42de6dSgd78059 } 13041c42de6dSgd78059 13051c42de6dSgd78059 static uint32_t 13061c42de6dSgd78059 bscv_get32(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr) 13071c42de6dSgd78059 { 13081c42de6dSgd78059 uint32_t retval; 13091c42de6dSgd78059 13101c42de6dSgd78059 ASSERT(bscv_held(ssp)); 13111c42de6dSgd78059 13121c42de6dSgd78059 retval = bscv_get8(ssp, chan, addr) << 24; 13131c42de6dSgd78059 retval |= bscv_get8(ssp, chan, addr + 1) << 16; 13141c42de6dSgd78059 retval |= bscv_get8(ssp, chan, addr + 2) << 8; 13151c42de6dSgd78059 retval |= bscv_get8(ssp, chan, addr + 3); 13161c42de6dSgd78059 1317*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_get32", 13181c42de6dSgd78059 "addr 0x%x.%02x => %08x", addr >> 8, addr & 0xff, retval); 13191c42de6dSgd78059 return (retval); 13201c42de6dSgd78059 } 13211c42de6dSgd78059 13221c42de6dSgd78059 static void 13231c42de6dSgd78059 bscv_setclear8(bscv_soft_state_t *ssp, int chan, 13241c42de6dSgd78059 bscv_addr_t addr, uint8_t set, uint8_t clear) 13251c42de6dSgd78059 { 13261c42de6dSgd78059 uint8_t val; 13271c42de6dSgd78059 13281c42de6dSgd78059 ASSERT(bscv_held(ssp)); 13291c42de6dSgd78059 ASSERT(addr < BSC_ADDR_CACHE_LIMIT); 13301c42de6dSgd78059 13311c42de6dSgd78059 val = ssp->lom_regs[addr] | set; 13321c42de6dSgd78059 val &= ~clear; 13331c42de6dSgd78059 1334*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_setclear8", 13351c42de6dSgd78059 "addr 0x%x.%02x, set %02x, clear %02x => %02x", 13361c42de6dSgd78059 addr >> 8, addr & 0xff, 13371c42de6dSgd78059 set, clear, val); 13381c42de6dSgd78059 13391c42de6dSgd78059 bscv_put8(ssp, chan, addr, val); 13401c42de6dSgd78059 } 13411c42de6dSgd78059 13421c42de6dSgd78059 static void 13431c42de6dSgd78059 bscv_setclear8_volatile(bscv_soft_state_t *ssp, int chan, 13441c42de6dSgd78059 bscv_addr_t addr, uint8_t set, uint8_t clear) 13451c42de6dSgd78059 { 13461c42de6dSgd78059 uint8_t val; 13471c42de6dSgd78059 boolean_t needretry; 13481c42de6dSgd78059 int num_failures; 13491c42de6dSgd78059 13501c42de6dSgd78059 ASSERT(bscv_held(ssp)); 13511c42de6dSgd78059 ASSERT(addr < BSC_ADDR_CACHE_LIMIT); 13521c42de6dSgd78059 13531c42de6dSgd78059 if (bscv_faulty(ssp)) { 13541c42de6dSgd78059 return; 13551c42de6dSgd78059 } 13561c42de6dSgd78059 1357*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_setclear8_volatile", 13581c42de6dSgd78059 "addr 0x%x.%02x => set %02x clear %02x", 13591c42de6dSgd78059 addr >> 8, addr & 0xff, set, clear); 13601c42de6dSgd78059 13611c42de6dSgd78059 val = bscv_get8_cached(ssp, addr); 13621c42de6dSgd78059 for (num_failures = 0; 13631c42de6dSgd78059 num_failures < BSC_FAILURE_RETRY_LIMIT; 13641c42de6dSgd78059 num_failures++) { 13651c42de6dSgd78059 val |= set; 13661c42de6dSgd78059 val &= ~clear; 13671c42de6dSgd78059 bscv_put8_once(ssp, chan, addr, val); 13681c42de6dSgd78059 if (ssp->command_error == EBUS_ERROR_STALEDATA) { 13691c42de6dSgd78059 /* Re-read the stale register from the lom */ 13701c42de6dSgd78059 val = bscv_get8_once(ssp, chan, addr); 13711c42de6dSgd78059 needretry = 1; 13721c42de6dSgd78059 } else { 13731c42de6dSgd78059 needretry = bscv_should_retry(ssp); 13741c42de6dSgd78059 if (!needretry) { 13751c42de6dSgd78059 break; 13761c42de6dSgd78059 } 13771c42de6dSgd78059 } 13781c42de6dSgd78059 } 13791c42de6dSgd78059 if (ssp->command_error != 0) { 13801c42de6dSgd78059 ssp->had_session_error = B_TRUE; 13811c42de6dSgd78059 } 13821c42de6dSgd78059 13831c42de6dSgd78059 if (needretry) { 13841c42de6dSgd78059 /* Failure */ 13851c42de6dSgd78059 cmn_err(CE_WARN, "bscv_setclear8_volatile: addr 0x%x.%02x " 13861c42de6dSgd78059 "retried write %d times, giving up", 13871c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 13881c42de6dSgd78059 if (ssp->command_error != EBUS_ERROR_STALEDATA) { 13891c42de6dSgd78059 bscv_set_fault(ssp); 13901c42de6dSgd78059 } 13911c42de6dSgd78059 } else if (num_failures > 0) { 1392*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'R', "bscv_setclear8_volatile", 13931c42de6dSgd78059 "addr 0x%x.%02x retried write %d times, succeeded", 13941c42de6dSgd78059 addr >> 8, addr & 0xff, num_failures); 13951c42de6dSgd78059 } 13961c42de6dSgd78059 } 13971c42de6dSgd78059 13981c42de6dSgd78059 static void 13991c42de6dSgd78059 bscv_rep_rw8(bscv_soft_state_t *ssp, int chan, uint8_t *host_addr, 14001c42de6dSgd78059 bscv_addr_t dev_addr, size_t repcount, uint_t flags, 14011c42de6dSgd78059 boolean_t is_write) 14021c42de6dSgd78059 { 14031c42de6dSgd78059 size_t inc; 14041c42de6dSgd78059 14051c42de6dSgd78059 ASSERT(bscv_held(ssp)); 14061c42de6dSgd78059 14071c42de6dSgd78059 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 14081c42de6dSgd78059 for (; repcount--; dev_addr += inc) { 14091c42de6dSgd78059 if (flags & DDI_DEV_AUTOINCR) { 14101c42de6dSgd78059 if (is_write) { 14111c42de6dSgd78059 bscv_put8(ssp, chan, dev_addr, *host_addr++); 14121c42de6dSgd78059 } else { 14131c42de6dSgd78059 *host_addr++ = bscv_get8(ssp, chan, dev_addr); 14141c42de6dSgd78059 } 14151c42de6dSgd78059 } else { 14161c42de6dSgd78059 if (is_write) { 14171c42de6dSgd78059 bscv_put8_once(ssp, chan, 14181c42de6dSgd78059 dev_addr, *host_addr++); 14191c42de6dSgd78059 } else { 14201c42de6dSgd78059 *host_addr++ = bscv_get8_once(ssp, chan, 14211c42de6dSgd78059 dev_addr); 14221c42de6dSgd78059 } 14231c42de6dSgd78059 /* We need this because _once routines don't do it */ 14241c42de6dSgd78059 if (ssp->command_error != 0) { 14251c42de6dSgd78059 ssp->had_session_error = B_TRUE; 14261c42de6dSgd78059 } 14271c42de6dSgd78059 } 14281c42de6dSgd78059 if (bscv_faulty(ssp) || bscv_session_error(ssp)) { 14291c42de6dSgd78059 /* 14301c42de6dSgd78059 * No retry here. If we were AUTOINCR then get/put 14311c42de6dSgd78059 * will have retried. For NO_AUTOINCR we cannot retry 14321c42de6dSgd78059 * because the data would be corrupted. 14331c42de6dSgd78059 */ 14341c42de6dSgd78059 break; 14351c42de6dSgd78059 } 14361c42de6dSgd78059 } 14371c42de6dSgd78059 } 14381c42de6dSgd78059 14391c42de6dSgd78059 static uint8_t 14401c42de6dSgd78059 bscv_get8_cached(bscv_soft_state_t *ssp, bscv_addr_t addr) 14411c42de6dSgd78059 { 14421c42de6dSgd78059 ASSERT(addr < BSC_ADDR_CACHE_LIMIT); 14431c42de6dSgd78059 /* Can be called with or without the lock held */ 14441c42de6dSgd78059 14451c42de6dSgd78059 return (ssp->lom_regs[addr]); 14461c42de6dSgd78059 } 14471c42de6dSgd78059 14481c42de6dSgd78059 static uint8_t 14491c42de6dSgd78059 bscv_get8_locked(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, int *res) 14501c42de6dSgd78059 { 14511c42de6dSgd78059 uint8_t retval; 14521c42de6dSgd78059 14531c42de6dSgd78059 ASSERT(addr < BSC_ADDR_CACHE_LIMIT); 14541c42de6dSgd78059 bscv_enter(ssp); 14551c42de6dSgd78059 retval = bscv_get8(ssp, chan, addr); 14561c42de6dSgd78059 bscv_locked_result(ssp, res); 14571c42de6dSgd78059 bscv_exit(ssp); 1458*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_get8_locked", 14591c42de6dSgd78059 "addr 0x%x.%02x => %02x", addr >> 8, addr & 0xff, retval); 14601c42de6dSgd78059 return (retval); 14611c42de6dSgd78059 } 14621c42de6dSgd78059 14631c42de6dSgd78059 static void 14641c42de6dSgd78059 bscv_rep_get8_locked(bscv_soft_state_t *ssp, int chan, uint8_t *host_addr, 14651c42de6dSgd78059 bscv_addr_t dev_addr, size_t repcount, uint_t flags, int *res) 14661c42de6dSgd78059 { 14671c42de6dSgd78059 bscv_enter(ssp); 14681c42de6dSgd78059 bscv_rep_rw8(ssp, chan, host_addr, dev_addr, repcount, 14691c42de6dSgd78059 flags, B_FALSE /* read */); 14701c42de6dSgd78059 bscv_locked_result(ssp, res); 14711c42de6dSgd78059 bscv_exit(ssp); 14721c42de6dSgd78059 } 14731c42de6dSgd78059 14741c42de6dSgd78059 static boolean_t 14751c42de6dSgd78059 bscv_faulty(bscv_soft_state_t *ssp) 14761c42de6dSgd78059 { 14771c42de6dSgd78059 ASSERT(bscv_held(ssp)); 14781c42de6dSgd78059 return (ssp->had_fault); 14791c42de6dSgd78059 } 14801c42de6dSgd78059 14811c42de6dSgd78059 static void 14821c42de6dSgd78059 bscv_clear_fault(bscv_soft_state_t *ssp) 14831c42de6dSgd78059 { 14841c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1485*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'J', "bscv_clear_fault", "clearing fault flag"); 14861c42de6dSgd78059 ssp->had_fault = B_FALSE; 14871c42de6dSgd78059 ssp->had_session_error = B_FALSE; 14881c42de6dSgd78059 } 14891c42de6dSgd78059 14901c42de6dSgd78059 static void 14911c42de6dSgd78059 bscv_set_fault(bscv_soft_state_t *ssp) 14921c42de6dSgd78059 { 14931c42de6dSgd78059 ASSERT(bscv_held(ssp)); 1494*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'J', "bscv_set_fault", "setting fault flag"); 14951c42de6dSgd78059 ssp->had_fault = B_TRUE; 14961c42de6dSgd78059 } 14971c42de6dSgd78059 14981c42de6dSgd78059 static boolean_t 14991c42de6dSgd78059 bscv_session_error(bscv_soft_state_t *ssp) 15001c42de6dSgd78059 { 15011c42de6dSgd78059 ASSERT(bscv_held(ssp)); 15021c42de6dSgd78059 return (ssp->had_session_error); 15031c42de6dSgd78059 } 15041c42de6dSgd78059 15051c42de6dSgd78059 static int 15061c42de6dSgd78059 bscv_retcode(bscv_soft_state_t *ssp) 15071c42de6dSgd78059 { 1508*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_retcode", 15091c42de6dSgd78059 "code 0x%x", ssp->command_error); 15101c42de6dSgd78059 return (ssp->command_error); 15111c42de6dSgd78059 } 15121c42de6dSgd78059 15131c42de6dSgd78059 static int 15141c42de6dSgd78059 bscv_should_retry(bscv_soft_state_t *ssp) 15151c42de6dSgd78059 { 15161c42de6dSgd78059 if ((ssp->command_error == EBUS_ERROR_DEVICEFAIL) || 15171c42de6dSgd78059 (ssp->command_error >= LOMBUS_ERR_BASE)) { 15181c42de6dSgd78059 /* This command is due to an I/O fault - retry might fix */ 15191c42de6dSgd78059 return (1); 15201c42de6dSgd78059 } else { 15211c42de6dSgd78059 /* 15221c42de6dSgd78059 * The command itself was bad - there is no point in fixing 15231c42de6dSgd78059 * Note. Whatever happens we should know that if we were 15241c42de6dSgd78059 * doing EBUS_IDX_SELFTEST0..EBUS_IDX_SELFTEST7 and we 15251c42de6dSgd78059 * had 0x80 set then this is a test error not a retry 15261c42de6dSgd78059 * error. 15271c42de6dSgd78059 */ 15281c42de6dSgd78059 return (0); 15291c42de6dSgd78059 } 15301c42de6dSgd78059 } 15311c42de6dSgd78059 15321c42de6dSgd78059 static void 15331c42de6dSgd78059 bscv_locked_result(bscv_soft_state_t *ssp, int *res) 15341c42de6dSgd78059 { 15351c42de6dSgd78059 if (bscv_faulty(ssp) || (bscv_retcode(ssp) != 0)) { 15361c42de6dSgd78059 *res = EIO; 15371c42de6dSgd78059 } 15381c42de6dSgd78059 } 15391c42de6dSgd78059 15401c42de6dSgd78059 static void 15411c42de6dSgd78059 bscv_put8_once(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr, uint8_t val) 15421c42de6dSgd78059 { 15431c42de6dSgd78059 uint32_t fault; 15441c42de6dSgd78059 15451c42de6dSgd78059 ASSERT(bscv_held(ssp)); 15461c42de6dSgd78059 15471c42de6dSgd78059 ssp->command_error = 0; 15481c42de6dSgd78059 15491c42de6dSgd78059 if (bscv_faulty(ssp)) { 15501c42de6dSgd78059 /* Bail out things are not working */ 15511c42de6dSgd78059 return; 15521c42de6dSgd78059 } else if (ssp->nchannels == 0) { 15531c42de6dSgd78059 /* Didn't manage to map handles so ddi_{get,put}* broken */ 1554*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_put8_once", 15551c42de6dSgd78059 "nchannels is 0x0 so cannot do IO"); 15561c42de6dSgd78059 return; 15571c42de6dSgd78059 } 15581c42de6dSgd78059 15591c42de6dSgd78059 /* Clear any pending fault */ 15601c42de6dSgd78059 ddi_put32(ssp->channel[chan].handle, 15611c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0); 15621c42de6dSgd78059 15631c42de6dSgd78059 /* Do the access and get fault code - may take a long time */ 15641c42de6dSgd78059 ddi_put8(ssp->channel[chan].handle, 15651c42de6dSgd78059 &ssp->channel[chan].regs[addr], val); 15661c42de6dSgd78059 fault = ddi_get32(ssp->channel[chan].handle, 15671c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG)); 15681c42de6dSgd78059 15691c42de6dSgd78059 ssp->command_error = fault; 15701c42de6dSgd78059 15711c42de6dSgd78059 if (fault == 0) { 15721c42de6dSgd78059 /* Things were ok - update cache entry */ 15731c42de6dSgd78059 if (addr < BSC_ADDR_CACHE_LIMIT) { 15741c42de6dSgd78059 /* Store cacheable entries */ 15751c42de6dSgd78059 ssp->lom_regs[addr] = val; 15761c42de6dSgd78059 } 15771c42de6dSgd78059 } else if (fault >= LOMBUS_ERR_BASE) { 15781c42de6dSgd78059 /* lombus problem - do a resync session */ 15791c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_put8_once: Had comms fault " 15801c42de6dSgd78059 "for address 0x%x.%02x - data 0x%x, fault 0x%x", 15811c42de6dSgd78059 addr >> 8, addr & 0xff, val, fault); 15821c42de6dSgd78059 /* Attempt to resync with the lom */ 15831c42de6dSgd78059 bscv_resync_comms(ssp, chan); 15841c42de6dSgd78059 /* 15851c42de6dSgd78059 * Note: we do not set fault status here. That 15861c42de6dSgd78059 * is done if our caller decides to give up talking to 15871c42de6dSgd78059 * the lom. The observant might notice that this means 15881c42de6dSgd78059 * that if we mend things on the last attempt we still 15891c42de6dSgd78059 * get the fault set - we just live with that! 15901c42de6dSgd78059 */ 15911c42de6dSgd78059 } 15921c42de6dSgd78059 1593*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_put8_once", 15941c42de6dSgd78059 "addr 0x%x.%02x <= 0x%02x", addr >> 8, addr & 0xff, val); 15951c42de6dSgd78059 } 15961c42de6dSgd78059 15971c42de6dSgd78059 static uint8_t 15981c42de6dSgd78059 bscv_get8_once(bscv_soft_state_t *ssp, int chan, bscv_addr_t addr) 15991c42de6dSgd78059 { 16001c42de6dSgd78059 uint8_t val; 16011c42de6dSgd78059 uint32_t fault; 16021c42de6dSgd78059 16031c42de6dSgd78059 ASSERT(bscv_held(ssp)); 16041c42de6dSgd78059 16051c42de6dSgd78059 ssp->command_error = 0; 16061c42de6dSgd78059 16071c42de6dSgd78059 if (bscv_faulty(ssp)) { 16081c42de6dSgd78059 /* Bail out things are not working */ 16091c42de6dSgd78059 return (0xff); 16101c42de6dSgd78059 } else if (ssp->nchannels == 0) { 16111c42de6dSgd78059 /* Didn't manage to map handles so ddi_{get,put}* broken */ 1612*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_get8_once", 16131c42de6dSgd78059 "nchannels is 0x0 so cannot do IO"); 16141c42de6dSgd78059 return (0xff); 16151c42de6dSgd78059 } 16161c42de6dSgd78059 16171c42de6dSgd78059 /* Clear any pending fault */ 16181c42de6dSgd78059 ddi_put32(ssp->channel[chan].handle, 16191c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0); 16201c42de6dSgd78059 16211c42de6dSgd78059 /* Do the access and get fault code - may take a long time */ 16221c42de6dSgd78059 val = ddi_get8(ssp->channel[chan].handle, 16231c42de6dSgd78059 &ssp->channel[chan].regs[addr]); 16241c42de6dSgd78059 fault = ddi_get32(ssp->channel[chan].handle, 16251c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG)); 16261c42de6dSgd78059 ssp->command_error = fault; 16271c42de6dSgd78059 16281c42de6dSgd78059 if (fault >= LOMBUS_ERR_BASE) { 16291c42de6dSgd78059 /* lombus problem - do a resync session */ 16301c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_get8_once: Had comms fault " 16311c42de6dSgd78059 "for address 0x%x.%02x - data 0x%x, fault 0x%x", 16321c42de6dSgd78059 addr >> 8, addr & 0xff, val, fault); 16331c42de6dSgd78059 /* Attempt to resync with the lom */ 16341c42de6dSgd78059 bscv_resync_comms(ssp, chan); 16351c42de6dSgd78059 /* 16361c42de6dSgd78059 * Note: we do not set fault status here. That 16371c42de6dSgd78059 * is done if our caller decides to give up talking to 16381c42de6dSgd78059 * the lom. The observant might notice that this means 16391c42de6dSgd78059 * that if we mend things on the last attempt we still 16401c42de6dSgd78059 * get the fault set - we just live with that! 16411c42de6dSgd78059 */ 16421c42de6dSgd78059 } 16431c42de6dSgd78059 /* 16441c42de6dSgd78059 * FIXME - should report error if you get 16451c42de6dSgd78059 * EBUS_ERROR_DEVICEFAIL reported from the BSC. That gets 16461c42de6dSgd78059 * logged as a failure in bscv_should_retry and may contribute 16471c42de6dSgd78059 * to a permanent failure. Reference issues seen by Mitac. 16481c42de6dSgd78059 */ 16491c42de6dSgd78059 16501c42de6dSgd78059 if (!bscv_faulty(ssp)) { 16511c42de6dSgd78059 if (addr < BSC_ADDR_CACHE_LIMIT) { 16521c42de6dSgd78059 /* Store cacheable entries */ 16531c42de6dSgd78059 ssp->lom_regs[addr] = val; 16541c42de6dSgd78059 } 16551c42de6dSgd78059 } 16561c42de6dSgd78059 1657*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_get8_once", 16581c42de6dSgd78059 "addr 0x%x.%02x => 0x%02x", addr >> 8, addr & 0xff, val); 16591c42de6dSgd78059 return (val); 16601c42de6dSgd78059 } 16611c42de6dSgd78059 16621c42de6dSgd78059 static uint32_t 16631c42de6dSgd78059 bscv_probe(bscv_soft_state_t *ssp, int chan, uint32_t *fault) 16641c42de6dSgd78059 { 16651c42de6dSgd78059 uint32_t async_reg; 16661c42de6dSgd78059 16671c42de6dSgd78059 if (ssp->nchannels == 0) { 16681c42de6dSgd78059 /* 16691c42de6dSgd78059 * Failed to map handles, so cannot do any IO. Set the 16701c42de6dSgd78059 * fault indicator and return a dummy value. 16711c42de6dSgd78059 */ 1672*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_probe", 16731c42de6dSgd78059 "nchannels is 0x0 so cannot do any IO"); 16741c42de6dSgd78059 *fault = LOMBUS_ERR_REG_NUM; 16751c42de6dSgd78059 return ((~(int8_t)0)); 16761c42de6dSgd78059 } 16771c42de6dSgd78059 16781c42de6dSgd78059 /* Clear faults */ 16791c42de6dSgd78059 ddi_put32(ssp->channel[chan].handle, 16801c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_FAULT_REG), 0); 16811c42de6dSgd78059 /* Probe and Check faults */ 16821c42de6dSgd78059 *fault = ddi_get32(ssp->channel[chan].handle, 16831c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_PROBE_REG)); 16841c42de6dSgd78059 /* Read status */ 16851c42de6dSgd78059 async_reg = ddi_get32(ssp->channel[chan].handle, 16861c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, LOMBUS_ASYNC_REG)); 16871c42de6dSgd78059 1688*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_probe", 16891c42de6dSgd78059 "async status 0x%x, fault 0x%x", async_reg, *fault); 16901c42de6dSgd78059 return (async_reg); 16911c42de6dSgd78059 } 16921c42de6dSgd78059 16931c42de6dSgd78059 static void 16941c42de6dSgd78059 bscv_resync_comms(bscv_soft_state_t *ssp, int chan) 16951c42de6dSgd78059 { 16961c42de6dSgd78059 int try; 16971c42de6dSgd78059 uint32_t command_error = ssp->command_error; 16981c42de6dSgd78059 uint32_t fault = 0; 16991c42de6dSgd78059 17001c42de6dSgd78059 if (ssp->nchannels == 0) { 17011c42de6dSgd78059 /* 17021c42de6dSgd78059 * Didn't manage to map handles so ddi_{get,put}* broken. 17031c42de6dSgd78059 * Therefore, there is no way to resync comms. 17041c42de6dSgd78059 */ 1705*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, '@', "bscv_resync_comms", 17061c42de6dSgd78059 "nchannels is 0x0 so not possible to resync comms"); 17071c42de6dSgd78059 return; 17081c42de6dSgd78059 } 17091c42de6dSgd78059 if (command_error >= LOMBUS_ERR_BASE && 17101c42de6dSgd78059 command_error != LOMBUS_ERR_REG_NUM && 17111c42de6dSgd78059 command_error != LOMBUS_ERR_REG_SIZE && 17121c42de6dSgd78059 command_error != LOMBUS_ERR_TIMEOUT) { 17131c42de6dSgd78059 /* Resync here to make sure that the lom is talking */ 17141c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_resync_comms: " 17151c42de6dSgd78059 "Attempting comms resync after comms fault 0x%x", 17161c42de6dSgd78059 command_error); 17171c42de6dSgd78059 for (try = 1; try <= 8; try++) { 17181c42de6dSgd78059 /* Probe */ 17191c42de6dSgd78059 fault = ddi_get32(ssp->channel[chan].handle, 17201c42de6dSgd78059 (uint32_t *)BSC_NEXUS_ADDR(ssp, chan, 0, 17211c42de6dSgd78059 LOMBUS_PROBE_REG)); 17221c42de6dSgd78059 17231c42de6dSgd78059 if (fault == 0) { 17241c42de6dSgd78059 break; 17251c42de6dSgd78059 } else { 17261c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_resync_comms: " 17271c42de6dSgd78059 "comms resync (probing) - try 0x%x " 17281c42de6dSgd78059 "had fault 0x%x", try, fault); 17291c42de6dSgd78059 } 17301c42de6dSgd78059 } 17311c42de6dSgd78059 if (fault != 0) { 17321c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_resync_comms: " 17331c42de6dSgd78059 "Failed to resync comms - giving up"); 17341c42de6dSgd78059 ssp->bad_resync++; 17351c42de6dSgd78059 } else { 17361c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_resync_comms: " 17371c42de6dSgd78059 "resync comms after 0x%x tries", try); 17381c42de6dSgd78059 ssp->bad_resync = 0; 17391c42de6dSgd78059 } 17401c42de6dSgd78059 } 17411c42de6dSgd78059 17421c42de6dSgd78059 } 17431c42de6dSgd78059 17441c42de6dSgd78059 17451c42de6dSgd78059 /* 17461c42de6dSgd78059 * LOMLite configuration/event eeprom access routines 17471c42de6dSgd78059 * 17481c42de6dSgd78059 * bscv_window_setup() - Read/Sanity check the eeprom parameters. 17491c42de6dSgd78059 * This must be called prior to calling bscv_eerw(). 17501c42de6dSgd78059 * bscv_eerw() - Read/write data from/to the eeprom. 17511c42de6dSgd78059 */ 17521c42de6dSgd78059 17531c42de6dSgd78059 /* 17541c42de6dSgd78059 * function - bscv_window_setup 17551c42de6dSgd78059 * description - this routine reads the eeprom parameters and sanity 17561c42de6dSgd78059 * checks them to ensure that the lom is talking sense. 17571c42de6dSgd78059 * inputs - soft state ptr 17581c42de6dSgd78059 * outputs - B_TRUE if the eeprom is ok, B_FALSE if the eeprom is not OK. 17591c42de6dSgd78059 */ 17601c42de6dSgd78059 static boolean_t 17611c42de6dSgd78059 bscv_window_setup(bscv_soft_state_t *ssp) 17621c42de6dSgd78059 { 17631c42de6dSgd78059 ASSERT(bscv_held(ssp)); 17641c42de6dSgd78059 17651c42de6dSgd78059 if (ssp->eeinfo_valid) { 17661c42de6dSgd78059 /* Already have good cached values */ 17671c42de6dSgd78059 return (ssp->eeinfo_valid); 17681c42de6dSgd78059 } 17691c42de6dSgd78059 ssp->eeprom_size = 17701c42de6dSgd78059 bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) * 1024; 17711c42de6dSgd78059 ssp->eventlog_start = bscv_get16(ssp, chan_general, 17721c42de6dSgd78059 EBUS_IDX_LOG_START_HI); 17731c42de6dSgd78059 17741c42de6dSgd78059 /* 17751c42de6dSgd78059 * The log does not run to the end of the EEPROM because it is a 17761c42de6dSgd78059 * logical partition. The last 8K partition is reserved for FRUID 17771c42de6dSgd78059 * usage. 17781c42de6dSgd78059 */ 17791c42de6dSgd78059 ssp->eventlog_size = EBUS_LOG_END - ssp->eventlog_start; 17801c42de6dSgd78059 1781*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'I', "bscv_window_setup", "eeprom size 0x%x log_start" 17821c42de6dSgd78059 " 0x%x log_size 0x%x", ssp->eeprom_size, ssp->eventlog_start, 17831c42de6dSgd78059 ssp->eventlog_size); 17841c42de6dSgd78059 17851c42de6dSgd78059 if (bscv_faulty(ssp) || bscv_session_error(ssp)) { 17861c42de6dSgd78059 ssp->eeinfo_valid = B_FALSE; 17871c42de6dSgd78059 } else if ((ssp->eeprom_size == 0) || 17881c42de6dSgd78059 (ssp->eventlog_start >= ssp->eeprom_size)) { 17891c42de6dSgd78059 /* Sanity check values */ 17901c42de6dSgd78059 cmn_err(CE_WARN, 17911c42de6dSgd78059 "!bscv_window_setup: read invalid eeprom parameters"); 17921c42de6dSgd78059 ssp->eeinfo_valid = B_FALSE; 17931c42de6dSgd78059 } else { 17941c42de6dSgd78059 ssp->eeinfo_valid = B_TRUE; 17951c42de6dSgd78059 } 17961c42de6dSgd78059 1797*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'I', "bscv_window_setup", "returning eeinfo_valid %s", 17981c42de6dSgd78059 ssp->eeinfo_valid ? "true" : "false"); 17991c42de6dSgd78059 return (ssp->eeinfo_valid); 18001c42de6dSgd78059 } 18011c42de6dSgd78059 18021c42de6dSgd78059 /* 18031c42de6dSgd78059 * function - bscv_eerw 18041c42de6dSgd78059 * description - this routine reads/write data from/to the eeprom. 18051c42de6dSgd78059 * It takes care of setting the window on the eeprom correctly. 18061c42de6dSgd78059 * inputs - soft state ptr, eeprom offset, data buffer, size, read/write 18071c42de6dSgd78059 * outputs - B_TRUE if the eeprom is ok, B_FALSE if the eeprom is not OK. 18081c42de6dSgd78059 */ 18091c42de6dSgd78059 static int 18101c42de6dSgd78059 bscv_eerw(bscv_soft_state_t *ssp, uint32_t eeoffset, uint8_t *buf, 18111c42de6dSgd78059 unsigned size, boolean_t is_write) 18121c42de6dSgd78059 { 18131c42de6dSgd78059 uint32_t blk_addr = eeoffset; 18141c42de6dSgd78059 unsigned remaining = size; 18151c42de6dSgd78059 uint8_t page_idx; 18161c42de6dSgd78059 uint8_t this_page; 18171c42de6dSgd78059 uint8_t blk_size; 18181c42de6dSgd78059 int res = 0; 18191c42de6dSgd78059 18201c42de6dSgd78059 while (remaining > 0) { 18211c42de6dSgd78059 page_idx = blk_addr & 0xff; 18221c42de6dSgd78059 if ((page_idx + remaining) > 0x100) { 18231c42de6dSgd78059 blk_size = 0x100 - page_idx; 18241c42de6dSgd78059 } else { 18251c42de6dSgd78059 blk_size = remaining; 18261c42de6dSgd78059 } 18271c42de6dSgd78059 18281c42de6dSgd78059 /* Select correct eeprom page */ 18291c42de6dSgd78059 this_page = blk_addr >> 8; 18301c42de6dSgd78059 bscv_put8(ssp, chan_eeprom, EBUS_IDX_EEPROM_PAGESEL, this_page); 18311c42de6dSgd78059 1832*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'M', "lom_eerw", 18331c42de6dSgd78059 "%s data @0x%x.%02x, size 0x%x, 0x%x bytes remaining", 18341c42de6dSgd78059 is_write ? "writing" : "reading", 18351c42de6dSgd78059 this_page, page_idx, blk_size, remaining - blk_size); 18361c42de6dSgd78059 18371c42de6dSgd78059 bscv_rep_rw8(ssp, chan_eeprom, 18381c42de6dSgd78059 buf, BSCVA(EBUS_CMD_SPACE_EEPROM, page_idx), 18391c42de6dSgd78059 blk_size, DDI_DEV_AUTOINCR, is_write); 18401c42de6dSgd78059 18411c42de6dSgd78059 if (bscv_faulty(ssp) || bscv_session_error(ssp)) { 18421c42de6dSgd78059 res = EIO; 18431c42de6dSgd78059 break; 18441c42de6dSgd78059 } 18451c42de6dSgd78059 18461c42de6dSgd78059 remaining -= blk_size; 18471c42de6dSgd78059 blk_addr += blk_size; 18481c42de6dSgd78059 buf += blk_size; 18491c42de6dSgd78059 } 18501c42de6dSgd78059 18511c42de6dSgd78059 return (res); 18521c42de6dSgd78059 } 18531c42de6dSgd78059 18541c42de6dSgd78059 static boolean_t 18551c42de6dSgd78059 bscv_is_null_event(bscv_soft_state_t *ssp, lom_event_t *e) 18561c42de6dSgd78059 { 18571c42de6dSgd78059 ASSERT(e != NULL); 18581c42de6dSgd78059 18591c42de6dSgd78059 if (EVENT_DECODE_SUBSYS(e->ev_subsys) == EVENT_SUBSYS_NONE && 18601c42de6dSgd78059 e->ev_event == EVENT_NONE) { 18611c42de6dSgd78059 /* 18621c42de6dSgd78059 * This marks a NULL event. 18631c42de6dSgd78059 */ 1864*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_is_null_event", 18651c42de6dSgd78059 "EVENT_SUBSYS_NONE/EVENT_NONE null event"); 18661c42de6dSgd78059 return (B_TRUE); 18671c42de6dSgd78059 } else if (e->ev_subsys == 0xff && e->ev_event == 0xff) { 18681c42de6dSgd78059 /* 18691c42de6dSgd78059 * Under some circumstances, we've seen all 1s to represent 18701c42de6dSgd78059 * a manually cleared event log at the BSC prompt. Only 18711c42de6dSgd78059 * a test/diagnosis environment is likely to show this. 18721c42de6dSgd78059 */ 1873*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_is_null_event", "0xffff null event"); 18741c42de6dSgd78059 return (B_TRUE); 18751c42de6dSgd78059 } else { 18761c42de6dSgd78059 /* 18771c42de6dSgd78059 * Not a NULL event. 18781c42de6dSgd78059 */ 1879*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_is_null_event", "returning False"); 18801c42de6dSgd78059 return (B_FALSE); 18811c42de6dSgd78059 } 18821c42de6dSgd78059 } 18831c42de6dSgd78059 18841c42de6dSgd78059 /* 18851c42de6dSgd78059 * ********************************************************************* 18861c42de6dSgd78059 * IOCTL Processing 18871c42de6dSgd78059 * ********************************************************************* 18881c42de6dSgd78059 */ 18891c42de6dSgd78059 18901c42de6dSgd78059 /* 18911c42de6dSgd78059 * function - bscv_ioctl 18921c42de6dSgd78059 * description - routine that acts as a high level manager for ioctls. It 18931c42de6dSgd78059 * calls the appropriate handler for ioctls on the alarm:mon and 18941c42de6dSgd78059 * alarm:ctl minor nodes respectively 18951c42de6dSgd78059 * 18961c42de6dSgd78059 * Unsupported ioctls (now deprecated) 18971c42de6dSgd78059 * LOMIOCALCTL 18981c42de6dSgd78059 * LOMIOCALSTATE 18991c42de6dSgd78059 * LOMIOCCLEARLOG 19001c42de6dSgd78059 * LOMIOCCTL 19011c42de6dSgd78059 * LOMIOCCTL2 19021c42de6dSgd78059 * LOMIOCDAEMON 19031c42de6dSgd78059 * LOMIOCDMON 19041c42de6dSgd78059 * LOMIOCDOGCTL, TSIOCDOGCTL 19051c42de6dSgd78059 * LOMIOCDOGPAT, TSIOCDOGPAT 19061c42de6dSgd78059 * LOMIOCDOGTIME, TSIOCDOGTIME 19071c42de6dSgd78059 * LOMIOCEVENTLOG 19081c42de6dSgd78059 * LOMIOCEVNT 19091c42de6dSgd78059 * LOMIOCGETMASK 19101c42de6dSgd78059 * LOMIOCMPROG 19111c42de6dSgd78059 * LOMIOCNBMON, TSIOCNBMON 19121c42de6dSgd78059 * LOMIOCSLEEP 19131c42de6dSgd78059 * LOMIOCUNLOCK, TSIOCUNLOCK 19141c42de6dSgd78059 * LOMIOCWTMON, TSIOCWTMON 19151c42de6dSgd78059 * 19161c42de6dSgd78059 * Supported ioctls 19171c42de6dSgd78059 * LOMIOCDOGSTATE, TSIOCDOGSTATE 19181c42de6dSgd78059 * LOMIOCPROG 19191c42de6dSgd78059 * LOMIOCPSUSTATE 19201c42de6dSgd78059 * LOMIOCFANSTATE 19211c42de6dSgd78059 * LOMIOCFLEDSTATE 19221c42de6dSgd78059 * LOMIOCINFO 19231c42de6dSgd78059 * LOMIOCMREAD 19241c42de6dSgd78059 * LOMIOCVOLTS 19251c42de6dSgd78059 * LOMIOCSTATS 19261c42de6dSgd78059 * LOMIOCTEMP 19271c42de6dSgd78059 * LOMIOCCONS 19281c42de6dSgd78059 * LOMIOCEVENTLOG2 19291c42de6dSgd78059 * LOMIOCINFO2 19301c42de6dSgd78059 * LOMIOCTEST 19311c42de6dSgd78059 * LOMIOCMPROG2 19321c42de6dSgd78059 * LOMIOCMREAD2 19331c42de6dSgd78059 * 19341c42de6dSgd78059 * inputs - device number, command, user space arg, filemode, user 19351c42de6dSgd78059 * credentials, return value 19361c42de6dSgd78059 * outputs - the return value propagated back by the lower level routines. 19371c42de6dSgd78059 */ 19381c42de6dSgd78059 19391c42de6dSgd78059 /*ARGSUSED*/ 19401c42de6dSgd78059 static int 19411c42de6dSgd78059 bscv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp) 19421c42de6dSgd78059 { 19431c42de6dSgd78059 bscv_soft_state_t *ssp; 19441c42de6dSgd78059 int instance; 19451c42de6dSgd78059 int res = 0; 19461c42de6dSgd78059 19471c42de6dSgd78059 instance = DEVICETOINSTANCE(dev); 19481c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, instance); 19491c42de6dSgd78059 if (ssp == NULL) { 19501c42de6dSgd78059 return (ENXIO); 19511c42de6dSgd78059 } 19521c42de6dSgd78059 19531c42de6dSgd78059 /* 19541c42de6dSgd78059 * The Combined Switch and Service Processor takes care of configuration 19551c42de6dSgd78059 * and control. The CSSP tells the BSC chip about it; therefore the 19561c42de6dSgd78059 * bscv driver doesn't send such configuration and control to the BSC. 19571c42de6dSgd78059 * Additionally Watchdog configuration is no longer done from userland 19581c42de6dSgd78059 * lom. 19591c42de6dSgd78059 */ 19601c42de6dSgd78059 switch (cmd) { 19611c42de6dSgd78059 case LOMIOCALCTL: 19621c42de6dSgd78059 case LOMIOCALSTATE: 19631c42de6dSgd78059 case LOMIOCCLEARLOG: 19641c42de6dSgd78059 case LOMIOCCTL: 19651c42de6dSgd78059 case LOMIOCCTL2: 19661c42de6dSgd78059 case LOMIOCDAEMON: 19671c42de6dSgd78059 case LOMIOCDMON: 19681c42de6dSgd78059 case LOMIOCDOGCTL: 19691c42de6dSgd78059 case LOMIOCDOGPAT: 19701c42de6dSgd78059 case LOMIOCDOGTIME: 19711c42de6dSgd78059 case LOMIOCEVENTLOG: 19721c42de6dSgd78059 case LOMIOCEVNT: 19731c42de6dSgd78059 case LOMIOCGETMASK: 19741c42de6dSgd78059 case LOMIOCMPROG: 19751c42de6dSgd78059 case LOMIOCNBMON: 19761c42de6dSgd78059 case LOMIOCSLEEP: 19771c42de6dSgd78059 case LOMIOCUNLOCK: 19781c42de6dSgd78059 case LOMIOCWTMON: 19791c42de6dSgd78059 return (ENOTSUP); 19801c42de6dSgd78059 } 19811c42de6dSgd78059 19821c42de6dSgd78059 /* 19831c42de6dSgd78059 * set the default result. 19841c42de6dSgd78059 */ 19851c42de6dSgd78059 19861c42de6dSgd78059 *rvalp = 0; 19871c42de6dSgd78059 19881c42de6dSgd78059 if (ssp->cssp_prog) { 19891c42de6dSgd78059 return (ENXIO); 19901c42de6dSgd78059 } else if ((ssp->prog_mode_only || ssp->programming) && 19911c42de6dSgd78059 cmd != LOMIOCPROG) { 19921c42de6dSgd78059 return (ENXIO); 19931c42de6dSgd78059 } 19941c42de6dSgd78059 19951c42de6dSgd78059 /* 19961c42de6dSgd78059 * Check that the caller has appropriate access permissions 19971c42de6dSgd78059 * (FWRITE set in mode) for those ioctls which change lom 19981c42de6dSgd78059 * state 19991c42de6dSgd78059 */ 20001c42de6dSgd78059 if (!(mode & FWRITE)) { 20011c42de6dSgd78059 switch (cmd) { 20021c42de6dSgd78059 case LOMIOCMPROG2: 20031c42de6dSgd78059 case LOMIOCMREAD2: 20041c42de6dSgd78059 case LOMIOCPROG: 20051c42de6dSgd78059 case LOMIOCTEST: 20061c42de6dSgd78059 return (EACCES); 20071c42de6dSgd78059 /* NOTREACHED */ 20081c42de6dSgd78059 default: 20091c42de6dSgd78059 /* Does not require write access */ 20101c42de6dSgd78059 break; 20111c42de6dSgd78059 } 20121c42de6dSgd78059 } 20131c42de6dSgd78059 20141c42de6dSgd78059 switch (cmd) { 20151c42de6dSgd78059 20161c42de6dSgd78059 case LOMIOCDOGSTATE: 20171c42de6dSgd78059 res = bscv_ioc_dogstate(ssp, arg, mode); 20181c42de6dSgd78059 break; 20191c42de6dSgd78059 20201c42de6dSgd78059 case LOMIOCPROG: 20211c42de6dSgd78059 res = bscv_prog(ssp, arg, mode); 20221c42de6dSgd78059 break; 20231c42de6dSgd78059 20241c42de6dSgd78059 case LOMIOCPSUSTATE: 20251c42de6dSgd78059 res = bscv_ioc_psustate(ssp, arg, mode); 20261c42de6dSgd78059 break; 20271c42de6dSgd78059 20281c42de6dSgd78059 case LOMIOCFANSTATE: 20291c42de6dSgd78059 res = bscv_ioc_fanstate(ssp, arg, mode); 20301c42de6dSgd78059 break; 20311c42de6dSgd78059 20321c42de6dSgd78059 case LOMIOCFLEDSTATE: 20331c42de6dSgd78059 res = bscv_ioc_fledstate(ssp, arg, mode); 20341c42de6dSgd78059 break; 20351c42de6dSgd78059 20361c42de6dSgd78059 case LOMIOCLEDSTATE: 20371c42de6dSgd78059 res = bscv_ioc_ledstate(ssp, arg, mode); 20381c42de6dSgd78059 break; 20391c42de6dSgd78059 20401c42de6dSgd78059 case LOMIOCINFO: 20411c42de6dSgd78059 res = bscv_ioc_info(ssp, arg, mode); 20421c42de6dSgd78059 break; 20431c42de6dSgd78059 20441c42de6dSgd78059 case LOMIOCMREAD: 20451c42de6dSgd78059 res = bscv_ioc_mread(ssp, arg, mode); 20461c42de6dSgd78059 break; 20471c42de6dSgd78059 20481c42de6dSgd78059 case LOMIOCVOLTS: 20491c42de6dSgd78059 res = bscv_ioc_volts(ssp, arg, mode); 20501c42de6dSgd78059 break; 20511c42de6dSgd78059 20521c42de6dSgd78059 case LOMIOCSTATS: 20531c42de6dSgd78059 res = bscv_ioc_stats(ssp, arg, mode); 20541c42de6dSgd78059 break; 20551c42de6dSgd78059 20561c42de6dSgd78059 case LOMIOCTEMP: 20571c42de6dSgd78059 res = bscv_ioc_temp(ssp, arg, mode); 20581c42de6dSgd78059 break; 20591c42de6dSgd78059 20601c42de6dSgd78059 case LOMIOCCONS: 20611c42de6dSgd78059 res = bscv_ioc_cons(ssp, arg, mode); 20621c42de6dSgd78059 break; 20631c42de6dSgd78059 20641c42de6dSgd78059 case LOMIOCEVENTLOG2: 20651c42de6dSgd78059 res = bscv_ioc_eventlog2(ssp, arg, mode); 20661c42de6dSgd78059 break; 20671c42de6dSgd78059 20681c42de6dSgd78059 case LOMIOCINFO2: 20691c42de6dSgd78059 res = bscv_ioc_info2(ssp, arg, mode); 20701c42de6dSgd78059 break; 20711c42de6dSgd78059 20721c42de6dSgd78059 case LOMIOCTEST: 20731c42de6dSgd78059 res = bscv_ioc_test(ssp, arg, mode); 20741c42de6dSgd78059 break; 20751c42de6dSgd78059 20761c42de6dSgd78059 case LOMIOCMPROG2: 20771c42de6dSgd78059 res = bscv_ioc_mprog2(ssp, arg, mode); 20781c42de6dSgd78059 break; 20791c42de6dSgd78059 20801c42de6dSgd78059 case LOMIOCMREAD2: 20811c42de6dSgd78059 res = bscv_ioc_mread2(ssp, arg, mode); 20821c42de6dSgd78059 break; 20831c42de6dSgd78059 20841c42de6dSgd78059 default: 2085*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'I', "bscv_ioctl", "Invalid IOCTL 0x%x", cmd); 20861c42de6dSgd78059 res = EINVAL; 20871c42de6dSgd78059 } 20881c42de6dSgd78059 return (res); 20891c42de6dSgd78059 } 20901c42de6dSgd78059 20911c42de6dSgd78059 /* 20921c42de6dSgd78059 * LOMIOCDOGSTATE 20931c42de6dSgd78059 * TSIOCDOGSTATE - indicate whether the alarm watchdog and reset 20941c42de6dSgd78059 * circuitry is enabled or not. 20951c42de6dSgd78059 */ 20961c42de6dSgd78059 static int 20971c42de6dSgd78059 bscv_ioc_dogstate(bscv_soft_state_t *ssp, intptr_t arg, int mode) 20981c42de6dSgd78059 { 20991c42de6dSgd78059 lom_dogstate_t dogstate; 21001c42de6dSgd78059 uint8_t dogval; 21011c42de6dSgd78059 int res = 0; 21021c42de6dSgd78059 21031c42de6dSgd78059 dogval = bscv_get8_locked(ssp, chan_general, EBUS_IDX_WDOG_CTRL, &res); 21041c42de6dSgd78059 dogstate.dog_enable = (dogval & EBUS_WDOG_ENABLE) ? 1 : 0; 21051c42de6dSgd78059 dogstate.reset_enable = (dogval & EBUS_WDOG_RST) ? 1 : 0; 21061c42de6dSgd78059 dogstate.dog_timeout = bscv_get8_locked(ssp, chan_general, 21071c42de6dSgd78059 EBUS_IDX_WDOG_TIME, &res); 21081c42de6dSgd78059 21091c42de6dSgd78059 if ((res == 0) && 21101c42de6dSgd78059 (ddi_copyout((caddr_t)&dogstate, 21111c42de6dSgd78059 (caddr_t)arg, sizeof (dogstate), mode) < 0)) { 21121c42de6dSgd78059 res = EFAULT; 21131c42de6dSgd78059 } 21141c42de6dSgd78059 return (res); 21151c42de6dSgd78059 } 21161c42de6dSgd78059 21171c42de6dSgd78059 /* 21181c42de6dSgd78059 * LOMIOCPSUSTATE - returns full information for 4 PSUs. All this 21191c42de6dSgd78059 * information is available from two bytes of LOMlite RAM, but if 21201c42de6dSgd78059 * on the first read it is noticed that two or more of the PSUs are 21211c42de6dSgd78059 * not present only 1 byte will be read subsequently. 21221c42de6dSgd78059 */ 21231c42de6dSgd78059 static int 21241c42de6dSgd78059 bscv_ioc_psustate(bscv_soft_state_t *ssp, intptr_t arg, int mode) 21251c42de6dSgd78059 { 21261c42de6dSgd78059 lom_psudata_t psudata; 21271c42de6dSgd78059 uint8_t psustat; 21281c42de6dSgd78059 int i; 21291c42de6dSgd78059 int res = 0; 21301c42de6dSgd78059 21311c42de6dSgd78059 for (i = 0; i < MAX_PSUS; i++) { 21321c42de6dSgd78059 psustat = bscv_get8_locked(ssp, chan_general, 21331c42de6dSgd78059 EBUS_IDX_PSU1_STAT + i, &res); 21341c42de6dSgd78059 psudata.fitted[i] = psustat & EBUS_PSU_PRESENT; 21351c42de6dSgd78059 psudata.output[i] = psustat & EBUS_PSU_OUTPUT; 21361c42de6dSgd78059 psudata.supplyb[i] = psustat & EBUS_PSU_INPUTB; 21371c42de6dSgd78059 psudata.supplya[i] = psustat & EBUS_PSU_INPUTA; 21381c42de6dSgd78059 psudata.standby[i] = psustat & EBUS_PSU_STANDBY; 21391c42de6dSgd78059 } 21401c42de6dSgd78059 21411c42de6dSgd78059 if (ddi_copyout((caddr_t)&psudata, (caddr_t)arg, sizeof (psudata), 21421c42de6dSgd78059 mode) < 0) { 21431c42de6dSgd78059 res = EFAULT; 21441c42de6dSgd78059 } 21451c42de6dSgd78059 return (res); 21461c42de6dSgd78059 } 21471c42de6dSgd78059 21481c42de6dSgd78059 /* 21491c42de6dSgd78059 * LOMIOCFANSTATE - returns full information including speed for 4 21501c42de6dSgd78059 * fans and the minimum and maximum operating speeds for each fan as 21511c42de6dSgd78059 * stored in the READ ONLY EEPROM data. As this EEPROM data is set 21521c42de6dSgd78059 * at manufacture time, this data should only be read by the driver 21531c42de6dSgd78059 * once and stored locally. 21541c42de6dSgd78059 */ 21551c42de6dSgd78059 static int 21561c42de6dSgd78059 bscv_ioc_fanstate(bscv_soft_state_t *ssp, intptr_t arg, int mode) 21571c42de6dSgd78059 { 21581c42de6dSgd78059 lom_fandata_t fandata; 21591c42de6dSgd78059 int numfans; 21601c42de6dSgd78059 int i; 21611c42de6dSgd78059 int res = 0; 21621c42de6dSgd78059 21631c42de6dSgd78059 bzero(&fandata, sizeof (lom_fandata_t)); 21641c42de6dSgd78059 numfans = EBUS_CONFIG_NFAN_DEC(bscv_get8_locked(ssp, 21651c42de6dSgd78059 chan_general, EBUS_IDX_CONFIG, &res)); 21661c42de6dSgd78059 for (i = 0; (i < numfans) && (res == 0); i++) { 21671c42de6dSgd78059 if (ssp->fanspeed[i] != LOM_FAN_NOT_PRESENT) { 21681c42de6dSgd78059 fandata.fitted[i] = 1; 21691c42de6dSgd78059 fandata.speed[i] = ssp->fanspeed[i]; 21701c42de6dSgd78059 fandata.minspeed[i] = bscv_get8_cached(ssp, 21711c42de6dSgd78059 EBUS_IDX_FAN1_LOW + i); 21721c42de6dSgd78059 } 21731c42de6dSgd78059 } 21741c42de6dSgd78059 21751c42de6dSgd78059 if ((res == 0) && 21761c42de6dSgd78059 (ddi_copyout((caddr_t)&fandata, (caddr_t)arg, sizeof (fandata), 21771c42de6dSgd78059 mode) < 0)) { 21781c42de6dSgd78059 res = EFAULT; 21791c42de6dSgd78059 } 21801c42de6dSgd78059 return (res); 21811c42de6dSgd78059 } 21821c42de6dSgd78059 21831c42de6dSgd78059 /* 21841c42de6dSgd78059 * LOMIOCFLEDSTATE - returns the state of the fault LED 21851c42de6dSgd78059 */ 21861c42de6dSgd78059 static int 21871c42de6dSgd78059 bscv_ioc_fledstate(bscv_soft_state_t *ssp, intptr_t arg, int mode) 21881c42de6dSgd78059 { 21891c42de6dSgd78059 lom_fled_info_t fled_info; 21901c42de6dSgd78059 uint8_t fledstate; 21911c42de6dSgd78059 int res = 0; 21921c42de6dSgd78059 21931c42de6dSgd78059 fledstate = bscv_get8_locked(ssp, chan_general, EBUS_IDX_ALARM, &res); 21941c42de6dSgd78059 21951c42de6dSgd78059 /* Decode of 0x0F is off and 0x00-0x07 is on. */ 21961c42de6dSgd78059 if (EBUS_ALARM_LED_DEC(fledstate) == 0x0F) { 21971c42de6dSgd78059 fled_info.on = 0; 21981c42de6dSgd78059 } else { 21991c42de6dSgd78059 /* has +1 here - not 2 as in the info ioctl */ 22001c42de6dSgd78059 fled_info.on = EBUS_ALARM_LED_DEC(fledstate) + 1; 22011c42de6dSgd78059 } 22021c42de6dSgd78059 if ((res == 0) && 22031c42de6dSgd78059 (ddi_copyout((caddr_t)&fled_info, (caddr_t)arg, 22041c42de6dSgd78059 sizeof (fled_info), mode) < 0)) { 22051c42de6dSgd78059 res = EFAULT; 22061c42de6dSgd78059 } 22071c42de6dSgd78059 return (res); 22081c42de6dSgd78059 } 22091c42de6dSgd78059 22101c42de6dSgd78059 /* 22111c42de6dSgd78059 * LOMIOCLEDSTATE - returns the state of the requested LED 22121c42de6dSgd78059 */ 22131c42de6dSgd78059 static int 22141c42de6dSgd78059 bscv_ioc_ledstate(bscv_soft_state_t *ssp, intptr_t arg, int mode) 22151c42de6dSgd78059 { 22161c42de6dSgd78059 lom_led_state_t led_state; 22171c42de6dSgd78059 int fw_led_state; 22181c42de6dSgd78059 int res = 0; 22191c42de6dSgd78059 22201c42de6dSgd78059 /* copy in arguments supplied */ 22211c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)&led_state, 22221c42de6dSgd78059 sizeof (lom_led_state_t), mode) < 0) { 22231c42de6dSgd78059 return (EFAULT); 22241c42de6dSgd78059 } 22251c42de6dSgd78059 22261c42de6dSgd78059 /* 22271c42de6dSgd78059 * check if led index is -1, if so set it to max value for 22281c42de6dSgd78059 * this implementation. 22291c42de6dSgd78059 */ 22301c42de6dSgd78059 if (led_state.index == -1) { 22311c42de6dSgd78059 led_state.index = MAX_LED_ID; 22321c42de6dSgd78059 } 22331c42de6dSgd78059 22341c42de6dSgd78059 /* is the index in a valid range */ 22351c42de6dSgd78059 if ((led_state.index > MAX_LED_ID) || (led_state.index < 0)) { 22361c42de6dSgd78059 led_state.state = LOM_LED_OUTOFRANGE; 22371c42de6dSgd78059 } else { 22381c42de6dSgd78059 /* read the relevant led info */ 22391c42de6dSgd78059 fw_led_state = bscv_get8_locked(ssp, chan_general, 22401c42de6dSgd78059 EBUS_IDX_LED1_STATUS + led_state.index, &res); 22411c42de6dSgd78059 22421c42de6dSgd78059 /* set the state values accordingly */ 22431c42de6dSgd78059 switch (fw_led_state) { 22441c42de6dSgd78059 case LOM_LED_STATE_OFF: 22451c42de6dSgd78059 led_state.state = LOM_LED_OFF; 22461c42de6dSgd78059 led_state.colour = LOM_LED_COLOUR_ANY; 22471c42de6dSgd78059 break; 22481c42de6dSgd78059 case LOM_LED_STATE_ON_STEADY: 22491c42de6dSgd78059 led_state.state = LOM_LED_ON; 22501c42de6dSgd78059 led_state.colour = LOM_LED_COLOUR_ANY; 22511c42de6dSgd78059 break; 22521c42de6dSgd78059 case LOM_LED_STATE_ON_FLASHING: 22531c42de6dSgd78059 case LOM_LED_STATE_ON_SLOWFLASH: 22541c42de6dSgd78059 led_state.state = LOM_LED_BLINKING; 22551c42de6dSgd78059 led_state.colour = LOM_LED_COLOUR_ANY; 22561c42de6dSgd78059 break; 22571c42de6dSgd78059 case LOM_LED_STATE_NOT_PRESENT: 22581c42de6dSgd78059 led_state.state = LOM_LED_NOT_IMPLEMENTED; 22591c42de6dSgd78059 led_state.colour = LOM_LED_COLOUR_NONE; 22601c42de6dSgd78059 break; 22611c42de6dSgd78059 case LOM_LED_STATE_INACCESSIBLE: 22621c42de6dSgd78059 case LOM_LED_STATE_STANDBY: 22631c42de6dSgd78059 default: 22641c42de6dSgd78059 led_state.state = LOM_LED_ACCESS_ERROR; 22651c42de6dSgd78059 led_state.colour = LOM_LED_COLOUR_NONE; 22661c42de6dSgd78059 break; 22671c42de6dSgd78059 } 22681c42de6dSgd78059 22691c42de6dSgd78059 /* set the label info */ 22701c42de6dSgd78059 (void) strcpy(led_state.label, 22711c42de6dSgd78059 ssp->led_names[led_state.index]); 22721c42de6dSgd78059 } 22731c42de6dSgd78059 22741c42de6dSgd78059 /* copy out lom_state */ 22751c42de6dSgd78059 if ((res == 0) && 22761c42de6dSgd78059 (ddi_copyout((caddr_t)&led_state, (caddr_t)arg, 22771c42de6dSgd78059 sizeof (lom_led_state_t), mode) < 0)) { 22781c42de6dSgd78059 res = EFAULT; 22791c42de6dSgd78059 } 22801c42de6dSgd78059 return (res); 22811c42de6dSgd78059 } 22821c42de6dSgd78059 22831c42de6dSgd78059 /* 22841c42de6dSgd78059 * LOMIOCINFO - returns with a structure containing any information 22851c42de6dSgd78059 * stored on the LOMlite which a user should not need to access but 22861c42de6dSgd78059 * may be useful for diagnostic problems. The structure contains: the 22871c42de6dSgd78059 * serial escape character, alarm3 mode, version and checksum read from 22881c42de6dSgd78059 * RAM and the Product revision and ID read from EEPROM. 22891c42de6dSgd78059 */ 22901c42de6dSgd78059 static int 22911c42de6dSgd78059 bscv_ioc_info(bscv_soft_state_t *ssp, intptr_t arg, int mode) 22921c42de6dSgd78059 { 22931c42de6dSgd78059 lom_info_t info; 22941c42de6dSgd78059 int i; 22951c42de6dSgd78059 uint16_t csum; 22961c42de6dSgd78059 int res = 0; 22971c42de6dSgd78059 22981c42de6dSgd78059 info.ser_char = bscv_get8_locked(ssp, chan_general, EBUS_IDX_ESCAPE, 22991c42de6dSgd78059 &res); 23001c42de6dSgd78059 info.a3mode = WATCHDOG; 23011c42de6dSgd78059 info.fver = bscv_get8_locked(ssp, chan_general, EBUS_IDX_FW_REV, &res); 23021c42de6dSgd78059 csum = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_HI, &res) 23031c42de6dSgd78059 << 8; 23041c42de6dSgd78059 csum |= bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_LO, &res); 23051c42de6dSgd78059 info.fchksum = csum; 23061c42de6dSgd78059 info.prod_rev = bscv_get8_locked(ssp, chan_general, EBUS_IDX_MODEL_REV, 23071c42de6dSgd78059 &res); 23081c42de6dSgd78059 for (i = 0; i < sizeof (info.prod_id); i++) { 23091c42de6dSgd78059 info.prod_id[i] = bscv_get8_locked(ssp, 23101c42de6dSgd78059 chan_general, EBUS_IDX_MODEL_ID1 + i, &res); 23111c42de6dSgd78059 } 23121c42de6dSgd78059 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_ALARM, &res) & 23131c42de6dSgd78059 EBUS_ALARM_NOEVENTS) { 23141c42de6dSgd78059 info.events = OFF; 23151c42de6dSgd78059 } else { 23161c42de6dSgd78059 info.events = ON; 23171c42de6dSgd78059 } 23181c42de6dSgd78059 23191c42de6dSgd78059 if ((res == 0) && 23201c42de6dSgd78059 (ddi_copyout((caddr_t)&info, (caddr_t)arg, sizeof (info), 23211c42de6dSgd78059 mode) < 0)) { 23221c42de6dSgd78059 res = EFAULT; 23231c42de6dSgd78059 } 23241c42de6dSgd78059 return (res); 23251c42de6dSgd78059 } 23261c42de6dSgd78059 23271c42de6dSgd78059 /* 23281c42de6dSgd78059 * LOMIOCMREAD - used to query the LOMlite configuration parameters 23291c42de6dSgd78059 */ 23301c42de6dSgd78059 static int 23311c42de6dSgd78059 bscv_ioc_mread(bscv_soft_state_t *ssp, intptr_t arg, int mode) 23321c42de6dSgd78059 { 23331c42de6dSgd78059 lom_mprog_t mprog; 23341c42de6dSgd78059 int i; 23351c42de6dSgd78059 int fanz; 23361c42de6dSgd78059 int res = 0; 23371c42de6dSgd78059 23381c42de6dSgd78059 for (i = 0; i < sizeof (mprog.mod_id); i++) { 23391c42de6dSgd78059 mprog.mod_id[i] = bscv_get8_locked(ssp, chan_general, 23401c42de6dSgd78059 EBUS_IDX_MODEL_ID1 + i, &res); 23411c42de6dSgd78059 } 23421c42de6dSgd78059 mprog.mod_rev = bscv_get8_locked(ssp, chan_general, EBUS_IDX_MODEL_REV, 23431c42de6dSgd78059 &res); 23441c42de6dSgd78059 mprog.config = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG, 23451c42de6dSgd78059 &res); 23461c42de6dSgd78059 23471c42de6dSgd78059 /* Read the fan calibration values */ 23481c42de6dSgd78059 fanz = sizeof (mprog.fanhz) / sizeof (mprog.fanhz[0]); 23491c42de6dSgd78059 for (i = 0; i < fanz; i++) { 23501c42de6dSgd78059 mprog.fanhz[i] = bscv_get8_cached(ssp, 23511c42de6dSgd78059 EBUS_IDX_FAN1_CAL + i); 23521c42de6dSgd78059 mprog.fanmin[i] = bscv_get8_cached(ssp, 23531c42de6dSgd78059 EBUS_IDX_FAN1_LOW + i); 23541c42de6dSgd78059 } 23551c42de6dSgd78059 23561c42de6dSgd78059 if ((res == 0) && 23571c42de6dSgd78059 (ddi_copyout((caddr_t)&mprog, (caddr_t)arg, sizeof (mprog), 23581c42de6dSgd78059 mode) < 0)) { 23591c42de6dSgd78059 res = EFAULT; 23601c42de6dSgd78059 } 23611c42de6dSgd78059 return (res); 23621c42de6dSgd78059 } 23631c42de6dSgd78059 23641c42de6dSgd78059 /* 23651c42de6dSgd78059 * LOMIOCVOLTS 23661c42de6dSgd78059 */ 23671c42de6dSgd78059 static int 23681c42de6dSgd78059 bscv_ioc_volts(bscv_soft_state_t *ssp, intptr_t arg, int mode) 23691c42de6dSgd78059 { 23701c42de6dSgd78059 int i; 23711c42de6dSgd78059 uint16_t supply; 23721c42de6dSgd78059 int res = 0; 23731c42de6dSgd78059 23741c42de6dSgd78059 supply = (bscv_get8_locked(ssp, chan_general, EBUS_IDX_SUPPLY_HI, &res) 23751c42de6dSgd78059 << 8) | bscv_get8_locked(ssp, chan_general, EBUS_IDX_SUPPLY_LO, 23761c42de6dSgd78059 &res); 23771c42de6dSgd78059 23781c42de6dSgd78059 for (i = 0; i < ssp->volts.num; i++) { 23791c42de6dSgd78059 ssp->volts.status[i] = (supply >> i) & 1; 23801c42de6dSgd78059 } 23811c42de6dSgd78059 23821c42de6dSgd78059 if ((res == 0) && 23831c42de6dSgd78059 (ddi_copyout((caddr_t)&ssp->volts, (caddr_t)arg, 23841c42de6dSgd78059 sizeof (ssp->volts), mode) < 0)) { 23851c42de6dSgd78059 res = EFAULT; 23861c42de6dSgd78059 } 23871c42de6dSgd78059 return (res); 23881c42de6dSgd78059 } 23891c42de6dSgd78059 23901c42de6dSgd78059 /* 23911c42de6dSgd78059 * LOMIOCSTATS 23921c42de6dSgd78059 */ 23931c42de6dSgd78059 static int 23941c42de6dSgd78059 bscv_ioc_stats(bscv_soft_state_t *ssp, intptr_t arg, int mode) 23951c42de6dSgd78059 { 23961c42de6dSgd78059 int i; 23971c42de6dSgd78059 uint8_t status; 23981c42de6dSgd78059 int res = 0; 23991c42de6dSgd78059 24001c42de6dSgd78059 status = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CBREAK_STATUS, 24011c42de6dSgd78059 &res); 24021c42de6dSgd78059 for (i = 0; i < ssp->sflags.num; i++) { 24031c42de6dSgd78059 ssp->sflags.status[i] = (int)((status >> i) & 1); 24041c42de6dSgd78059 } 24051c42de6dSgd78059 24061c42de6dSgd78059 if ((res == 0) && 24071c42de6dSgd78059 (ddi_copyout((caddr_t)&ssp->sflags, (caddr_t)arg, 24081c42de6dSgd78059 sizeof (ssp->sflags), mode) < 0)) { 24091c42de6dSgd78059 res = EFAULT; 24101c42de6dSgd78059 } 24111c42de6dSgd78059 return (res); 24121c42de6dSgd78059 } 24131c42de6dSgd78059 24141c42de6dSgd78059 /* 24151c42de6dSgd78059 * LOMIOCTEMP 24161c42de6dSgd78059 */ 24171c42de6dSgd78059 static int 24181c42de6dSgd78059 bscv_ioc_temp(bscv_soft_state_t *ssp, intptr_t arg, int mode) 24191c42de6dSgd78059 { 24201c42de6dSgd78059 int i; 24211c42de6dSgd78059 int idx; 24221c42de6dSgd78059 uint8_t status_ov; 24231c42de6dSgd78059 lom_temp_t temps; 24241c42de6dSgd78059 int res = 0; 24251c42de6dSgd78059 24261c42de6dSgd78059 bzero(&temps, sizeof (temps)); 24271c42de6dSgd78059 idx = 0; 24281c42de6dSgd78059 for (i = 0; i < ssp->temps.num; i++) { 24291c42de6dSgd78059 if (ssp->temps.temp[i] != LOM_TEMP_STATE_NOT_PRESENT) { 24301c42de6dSgd78059 temps.temp[idx] = ssp->temps.temp[i]; 24311c42de6dSgd78059 bcopy(ssp->temps.name[i], temps.name[idx], 24321c42de6dSgd78059 sizeof (temps.name[idx])); 24331c42de6dSgd78059 temps.warning[idx] = ssp->temps.warning[i]; 24341c42de6dSgd78059 temps.shutdown[idx] = ssp->temps.shutdown[i]; 24351c42de6dSgd78059 idx++; 24361c42de6dSgd78059 } 24371c42de6dSgd78059 } 24381c42de6dSgd78059 temps.num = idx; 24391c42de6dSgd78059 24401c42de6dSgd78059 bcopy(ssp->temps.name_ov, temps.name_ov, sizeof (temps.name_ov)); 24411c42de6dSgd78059 temps.num_ov = ssp->temps.num_ov; 24421c42de6dSgd78059 status_ov = bscv_get8_locked(ssp, chan_general, EBUS_IDX_OTEMP_STATUS, 24431c42de6dSgd78059 &res); 24441c42de6dSgd78059 for (i = 0; i < ssp->temps.num_ov; i++) { 24451c42de6dSgd78059 ssp->temps.status_ov[i] = (status_ov >> i) & 1; 24461c42de6dSgd78059 } 24471c42de6dSgd78059 24481c42de6dSgd78059 if ((res == 0) && 24491c42de6dSgd78059 (ddi_copyout((caddr_t)&temps, (caddr_t)arg, sizeof (temps), 24501c42de6dSgd78059 mode) < 0)) { 24511c42de6dSgd78059 res = EFAULT; 24521c42de6dSgd78059 } 24531c42de6dSgd78059 return (res); 24541c42de6dSgd78059 } 24551c42de6dSgd78059 24561c42de6dSgd78059 /* 24571c42de6dSgd78059 * LOMIOCCONS 24581c42de6dSgd78059 */ 24591c42de6dSgd78059 static int 24601c42de6dSgd78059 bscv_ioc_cons(bscv_soft_state_t *ssp, intptr_t arg, int mode) 24611c42de6dSgd78059 { 24621c42de6dSgd78059 lom_cbuf_t cbuf; 24631c42de6dSgd78059 int datasize; 24641c42de6dSgd78059 int res = 0; 24651c42de6dSgd78059 24661c42de6dSgd78059 bzero(&cbuf, sizeof (cbuf)); 24671c42de6dSgd78059 datasize = EBUS_IDX1_CONS_BUF_END - EBUS_IDX1_CONS_BUF_START + 1; 24681c42de6dSgd78059 /* Ensure that we do not overfill cbuf and that it is NUL terminated */ 24691c42de6dSgd78059 if (datasize > (sizeof (cbuf) - 1)) { 24701c42de6dSgd78059 datasize = sizeof (cbuf) - 1; 24711c42de6dSgd78059 } 24721c42de6dSgd78059 bscv_rep_get8_locked(ssp, chan_general, (uint8_t *)cbuf.lrbuf, 24731c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE1, (EBUS_IDX1_CONS_BUF_END - datasize + 1)), 24741c42de6dSgd78059 datasize, DDI_DEV_AUTOINCR, &res); 24751c42de6dSgd78059 /* This is always within the array due to the checks above */ 24761c42de6dSgd78059 cbuf.lrbuf[datasize] = '\0'; 24771c42de6dSgd78059 24781c42de6dSgd78059 if ((res == 0) && 24791c42de6dSgd78059 (ddi_copyout((caddr_t)&cbuf, (caddr_t)arg, sizeof (cbuf), 24801c42de6dSgd78059 mode) < 0)) { 24811c42de6dSgd78059 res = EFAULT; 24821c42de6dSgd78059 } 24831c42de6dSgd78059 return (res); 24841c42de6dSgd78059 } 24851c42de6dSgd78059 24861c42de6dSgd78059 /* 24871c42de6dSgd78059 * LOMIOCEVENTLOG2 24881c42de6dSgd78059 */ 24891c42de6dSgd78059 static int 24901c42de6dSgd78059 bscv_ioc_eventlog2(bscv_soft_state_t *ssp, intptr_t arg, int mode) 24911c42de6dSgd78059 { 24921c42de6dSgd78059 lom_eventlog2_t *eventlog2; 24931c42de6dSgd78059 int events_recorded; 24941c42de6dSgd78059 int level; 24951c42de6dSgd78059 uint16_t next_offset; 24961c42de6dSgd78059 lom_event_t event; 24971c42de6dSgd78059 int res = 0; 24981c42de6dSgd78059 24991c42de6dSgd78059 eventlog2 = (lom_eventlog2_t *)kmem_zalloc(sizeof (*eventlog2), 25001c42de6dSgd78059 KM_SLEEP); 25011c42de6dSgd78059 25021c42de6dSgd78059 /* 25031c42de6dSgd78059 * First get number of events and level requested. 25041c42de6dSgd78059 */ 25051c42de6dSgd78059 25061c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)eventlog2, 25071c42de6dSgd78059 sizeof (lom_eventlog2_t), mode) < 0) { 25081c42de6dSgd78059 kmem_free((void *)eventlog2, sizeof (*eventlog2)); 25091c42de6dSgd78059 return (EFAULT); 25101c42de6dSgd78059 } 25111c42de6dSgd78059 25121c42de6dSgd78059 bscv_enter(ssp); 25131c42de6dSgd78059 25141c42de6dSgd78059 /* 25151c42de6dSgd78059 * OK we have full private access to the LOM now so loop 25161c42de6dSgd78059 * over the eventlog addr spaces until we get the required 25171c42de6dSgd78059 * number of events. 25181c42de6dSgd78059 */ 25191c42de6dSgd78059 25201c42de6dSgd78059 if (!bscv_window_setup(ssp)) { 25211c42de6dSgd78059 res = EIO; 25221c42de6dSgd78059 bscv_exit(ssp); 25231c42de6dSgd78059 kmem_free((void *)eventlog2, sizeof (*eventlog2)); 25241c42de6dSgd78059 return (res); 25251c42de6dSgd78059 } 25261c42de6dSgd78059 25271c42de6dSgd78059 /* 25281c42de6dSgd78059 * Read count, next event ptr MSB,LSB. Note a read of count 25291c42de6dSgd78059 * is necessary to latch values for the next event ptr 25301c42de6dSgd78059 */ 25311c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS); 25321c42de6dSgd78059 next_offset = bscv_get16(ssp, chan_general, EBUS_IDX_LOG_PTR_HI); 2533*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "log_ptr_hi 0x%x", 25341c42de6dSgd78059 next_offset); 25351c42de6dSgd78059 25361c42de6dSgd78059 events_recorded = 0; 25371c42de6dSgd78059 25381c42de6dSgd78059 while (events_recorded < eventlog2->num) { 25391c42de6dSgd78059 /* 25401c42de6dSgd78059 * Working backwards - read an event at a time. 25411c42de6dSgd78059 * next_offset is one event on from where we want to be! 25421c42de6dSgd78059 * Decrement next_offset and maybe wrap to the end of the 25431c42de6dSgd78059 * buffer. 25441c42de6dSgd78059 * Note the unsigned arithmetic, so check values first! 25451c42de6dSgd78059 */ 25461c42de6dSgd78059 if (next_offset <= ssp->eventlog_start) { 25471c42de6dSgd78059 /* Wrap to the end of the buffer */ 25481c42de6dSgd78059 next_offset = ssp->eventlog_start + ssp->eventlog_size; 2549*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "wrapping" 25501c42de6dSgd78059 " around to end of buffer; next_offset 0x%x", 25511c42de6dSgd78059 next_offset); 25521c42de6dSgd78059 } 25531c42de6dSgd78059 next_offset -= sizeof (event); 25541c42de6dSgd78059 25551c42de6dSgd78059 if (bscv_eerw(ssp, next_offset, (uint8_t *)&event, 25561c42de6dSgd78059 sizeof (event), B_FALSE /* read */) != 0) { 25571c42de6dSgd78059 /* Fault reading data - stop */ 2558*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "read" 25591c42de6dSgd78059 " failure for offset 0x%x", next_offset); 25601c42de6dSgd78059 res = EIO; 25611c42de6dSgd78059 break; 25621c42de6dSgd78059 } 25631c42de6dSgd78059 25641c42de6dSgd78059 if (bscv_is_null_event(ssp, &event)) { 25651c42de6dSgd78059 /* 25661c42de6dSgd78059 * No more events in this log so give up. 25671c42de6dSgd78059 */ 2568*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'I', "bscv_ioc_eventlog2", "no more" 25691c42de6dSgd78059 " events left at offset 0x%x", next_offset); 25701c42de6dSgd78059 break; 25711c42de6dSgd78059 } 25721c42de6dSgd78059 25731c42de6dSgd78059 /* 25741c42de6dSgd78059 * Are we interested in this event 25751c42de6dSgd78059 */ 25761c42de6dSgd78059 25771c42de6dSgd78059 level = bscv_level_of_event(&event); 25781c42de6dSgd78059 if (level <= eventlog2->level) { 25791c42de6dSgd78059 /* Arggh why the funny byte ordering 3, 2, 0, 1 */ 25801c42de6dSgd78059 eventlog2->code[events_recorded] = 25811c42de6dSgd78059 ((unsigned)event.ev_event | 25821c42de6dSgd78059 ((unsigned)event.ev_subsys << 8) | 25831c42de6dSgd78059 ((unsigned)event.ev_resource << 16) | 25841c42de6dSgd78059 ((unsigned)event.ev_detail << 24)); 25851c42de6dSgd78059 25861c42de6dSgd78059 eventlog2->time[events_recorded] = 25871c42de6dSgd78059 ((unsigned)event.ev_data[0] | 25881c42de6dSgd78059 ((unsigned)event.ev_data[1] << 8) | 25891c42de6dSgd78059 ((unsigned)event.ev_data[3] << 16) | 25901c42de6dSgd78059 ((unsigned)event.ev_data[2] << 24)); 25911c42de6dSgd78059 25921c42de6dSgd78059 bscv_build_eventstring(ssp, 25931c42de6dSgd78059 &event, eventlog2->string[events_recorded], 25941c42de6dSgd78059 eventlog2->string[events_recorded] + 25951c42de6dSgd78059 sizeof (eventlog2->string[events_recorded])); 25961c42de6dSgd78059 events_recorded++; 25971c42de6dSgd78059 } 25981c42de6dSgd78059 } 25991c42de6dSgd78059 26001c42de6dSgd78059 eventlog2->num = events_recorded; 26011c42de6dSgd78059 26021c42de6dSgd78059 bscv_exit(ssp); 26031c42de6dSgd78059 26041c42de6dSgd78059 if ((res == 0) && 26051c42de6dSgd78059 (ddi_copyout((caddr_t)eventlog2, (caddr_t)arg, 26061c42de6dSgd78059 sizeof (lom_eventlog2_t), mode) < 0)) { 26071c42de6dSgd78059 res = EFAULT; 26081c42de6dSgd78059 } 26091c42de6dSgd78059 26101c42de6dSgd78059 kmem_free((void *)eventlog2, sizeof (lom_eventlog2_t)); 26111c42de6dSgd78059 return (res); 26121c42de6dSgd78059 } 26131c42de6dSgd78059 26141c42de6dSgd78059 /* 26151c42de6dSgd78059 * LOMIOCINFO2 26161c42de6dSgd78059 */ 26171c42de6dSgd78059 static int 26181c42de6dSgd78059 bscv_ioc_info2(bscv_soft_state_t *ssp, intptr_t arg, int mode) 26191c42de6dSgd78059 { 26201c42de6dSgd78059 lom2_info_t info2; 26211c42de6dSgd78059 int i; 26221c42de6dSgd78059 uint16_t csum; 26231c42de6dSgd78059 int res = 0; 26241c42de6dSgd78059 26251c42de6dSgd78059 bzero(&info2, sizeof (info2)); 26261c42de6dSgd78059 26271c42de6dSgd78059 (void) strncpy(info2.escape_chars, ssp->escape_chars, 26281c42de6dSgd78059 sizeof (info2.escape_chars)); 26291c42de6dSgd78059 info2.serial_events = ssp->reporting_level | ssp->serial_reporting; 26301c42de6dSgd78059 info2.a3mode = WATCHDOG; 26311c42de6dSgd78059 26321c42de6dSgd78059 info2.fver = bscv_get8_locked(ssp, chan_general, EBUS_IDX_FW_REV, &res); 26331c42de6dSgd78059 csum = bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_HI, &res) 26341c42de6dSgd78059 << 8; 26351c42de6dSgd78059 csum |= bscv_get8_locked(ssp, chan_general, EBUS_IDX_CHECK_LO, &res); 26361c42de6dSgd78059 info2.fchksum = csum; 26371c42de6dSgd78059 info2.prod_rev = bscv_get8_locked(ssp, chan_general, 26381c42de6dSgd78059 EBUS_IDX_MODEL_REV, &res); 26391c42de6dSgd78059 for (i = 0; i < sizeof (info2.prod_id); i++) { 26401c42de6dSgd78059 info2.prod_id[i] = bscv_get8_locked(ssp, chan_general, 26411c42de6dSgd78059 EBUS_IDX_MODEL_ID1 + i, &res); 26421c42de6dSgd78059 } 26431c42de6dSgd78059 info2.serial_config = bscv_get8_locked(ssp, chan_general, 26441c42de6dSgd78059 EBUS_IDX_SER_TIMEOUT, &res); 26451c42de6dSgd78059 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG_MISC, &res) & 26461c42de6dSgd78059 EBUS_CONFIG_MISC_SECURITY_ENABLED) { 26471c42de6dSgd78059 info2.serial_config |= LOM_SER_SECURITY; 26481c42de6dSgd78059 } 26491c42de6dSgd78059 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_CONFIG_MISC, &res) & 26501c42de6dSgd78059 EBUS_CONFIG_MISC_AUTO_CONSOLE) { 26511c42de6dSgd78059 info2.serial_config |= LOM_SER_RETURN; 26521c42de6dSgd78059 } 26531c42de6dSgd78059 if (bscv_get8_locked(ssp, chan_general, EBUS_IDX_WDOG_CTRL, &res) & 26541c42de6dSgd78059 EBUS_WDOG_BREAK_DISABLE) { 26551c42de6dSgd78059 info2.serial_config |= LOM_DISABLE_WDOG_BREAK; 26561c42de6dSgd78059 } 26571c42de6dSgd78059 info2.baud_rate = bscv_get8_locked(ssp, chan_general, 26581c42de6dSgd78059 EBUS_IDX_SER_BAUD, &res); 26591c42de6dSgd78059 info2.serial_hw_config = 26601c42de6dSgd78059 ((int)bscv_get8_locked(ssp, chan_general, 26611c42de6dSgd78059 EBUS_IDX_SER_CHARMODE, &res) | 26621c42de6dSgd78059 ((int)bscv_get8_locked(ssp, chan_general, 26631c42de6dSgd78059 EBUS_IDX_SER_FLOWCTL, &res) << 8) | 26641c42de6dSgd78059 ((int)bscv_get8_locked(ssp, chan_general, 26651c42de6dSgd78059 EBUS_IDX_SER_MODEMTYPE, &res) << 16)); 26661c42de6dSgd78059 26671c42de6dSgd78059 /* 26681c42de6dSgd78059 * There is no phone home support on the blade platform. We hardcode 26691c42de6dSgd78059 * FALSE and NUL for config and script respectively. 26701c42de6dSgd78059 */ 26711c42de6dSgd78059 info2.phone_home_config = B_FALSE; 26721c42de6dSgd78059 info2.phone_home_script[0] = '\0'; 26731c42de6dSgd78059 26741c42de6dSgd78059 for (i = 0; i < ssp->num_fans; i++) { 26751c42de6dSgd78059 (void) strcpy(info2.fan_names[i], ssp->fan_names[i]); 26761c42de6dSgd78059 } 26771c42de6dSgd78059 26781c42de6dSgd78059 if ((res == 0) && 26791c42de6dSgd78059 (ddi_copyout((caddr_t)&info2, (caddr_t)arg, sizeof (info2), 26801c42de6dSgd78059 mode) < 0)) { 26811c42de6dSgd78059 res = EFAULT; 26821c42de6dSgd78059 } 26831c42de6dSgd78059 return (res); 26841c42de6dSgd78059 } 26851c42de6dSgd78059 26861c42de6dSgd78059 /* 26871c42de6dSgd78059 * LOMIOCTEST 26881c42de6dSgd78059 */ 26891c42de6dSgd78059 static int 26901c42de6dSgd78059 bscv_ioc_test(bscv_soft_state_t *ssp, intptr_t arg, int mode) 26911c42de6dSgd78059 { 26921c42de6dSgd78059 uint32_t test; 26931c42de6dSgd78059 uint8_t testnum; 26941c42de6dSgd78059 uint8_t testarg; 26951c42de6dSgd78059 int res = 0; 26961c42de6dSgd78059 26971c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)&test, sizeof (test), 26981c42de6dSgd78059 mode) < 0) { 26991c42de6dSgd78059 return (EFAULT); 27001c42de6dSgd78059 } 27011c42de6dSgd78059 27021c42de6dSgd78059 /* 27031c42de6dSgd78059 * Extract num iterations. 27041c42de6dSgd78059 */ 27051c42de6dSgd78059 27061c42de6dSgd78059 testarg = (test & 0xff00) >> 8; 27071c42de6dSgd78059 testnum = test & 0xff; 27081c42de6dSgd78059 2709*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'F', "bscv_ioc_test", 27101c42de6dSgd78059 "LOMIOCTEST data 0x%x (test 0x%x, arg 0x%x)", 27111c42de6dSgd78059 test, (EBUS_IDX_SELFTEST0 + testnum), testarg); 27121c42de6dSgd78059 27131c42de6dSgd78059 switch (testnum + EBUS_IDX_SELFTEST0) { 27141c42de6dSgd78059 default: 27151c42de6dSgd78059 /* Invalid test */ 27161c42de6dSgd78059 res = EINVAL; 27171c42de6dSgd78059 break; 27181c42de6dSgd78059 27191c42de6dSgd78059 case EBUS_IDX_SELFTEST0: /* power on self-test result */ 27201c42de6dSgd78059 case EBUS_IDX_SELFTEST1: /* not used currently */ 27211c42de6dSgd78059 case EBUS_IDX_SELFTEST2: /* not used currently */ 27221c42de6dSgd78059 case EBUS_IDX_SELFTEST3: /* not used currently */ 27231c42de6dSgd78059 case EBUS_IDX_SELFTEST4: /* not used currently */ 27241c42de6dSgd78059 case EBUS_IDX_SELFTEST5: /* not used currently */ 27251c42de6dSgd78059 case EBUS_IDX_SELFTEST6: /* LED self-test */ 27261c42de6dSgd78059 case EBUS_IDX_SELFTEST7: /* platform-specific tests */ 27271c42de6dSgd78059 /* Run the test */ 27281c42de6dSgd78059 27291c42de6dSgd78059 /* Stop other things and then run the test */ 27301c42de6dSgd78059 bscv_enter(ssp); 27311c42de6dSgd78059 27321c42de6dSgd78059 /* 27331c42de6dSgd78059 * Then we simply write the argument to the relevant register 27341c42de6dSgd78059 * and wait for the return code. 27351c42de6dSgd78059 */ 27361c42de6dSgd78059 bscv_put8(ssp, chan_general, 27371c42de6dSgd78059 EBUS_IDX_SELFTEST0 + testnum, testarg); 27381c42de6dSgd78059 if (bscv_faulty(ssp)) { 27391c42de6dSgd78059 res = EIO; 27401c42de6dSgd78059 } else { 27411c42de6dSgd78059 /* Get hold of the SunVTS error code */ 27421c42de6dSgd78059 test = bscv_retcode(ssp); 27431c42de6dSgd78059 } 27441c42de6dSgd78059 27451c42de6dSgd78059 bscv_exit(ssp); 27461c42de6dSgd78059 break; 27471c42de6dSgd78059 } 27481c42de6dSgd78059 2749*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'F', "bscv_ioc_test", 27501c42de6dSgd78059 "LOMIOCTEST status 0x%x, res 0x%x", test, res); 27511c42de6dSgd78059 if ((res == 0) && 27521c42de6dSgd78059 (ddi_copyout((caddr_t)&test, (caddr_t)arg, sizeof (test), 27531c42de6dSgd78059 mode) < 0)) { 27541c42de6dSgd78059 res = EFAULT; 27551c42de6dSgd78059 } 27561c42de6dSgd78059 return (res); 27571c42de6dSgd78059 } 27581c42de6dSgd78059 27591c42de6dSgd78059 /* 27601c42de6dSgd78059 * LOMIOCMPROG2 27611c42de6dSgd78059 */ 27621c42de6dSgd78059 static int 27631c42de6dSgd78059 bscv_ioc_mprog2(bscv_soft_state_t *ssp, intptr_t arg, int mode) 27641c42de6dSgd78059 { 27651c42de6dSgd78059 lom2_mprog_t mprog2; 27661c42de6dSgd78059 uint32_t base_addr; 27671c42de6dSgd78059 uint32_t data_size; 27681c42de6dSgd78059 uint32_t eeprom_size; 27691c42de6dSgd78059 int res = 0; 27701c42de6dSgd78059 27711c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)&mprog2, sizeof (mprog2), 27721c42de6dSgd78059 mode) < 0) { 27731c42de6dSgd78059 return (EFAULT); 27741c42de6dSgd78059 } 27751c42de6dSgd78059 27761c42de6dSgd78059 /* 27771c42de6dSgd78059 * Note that originally this was accessed as 255 byte pages 27781c42de6dSgd78059 * in address spaces 240-255. We have to emulate this behaviour. 27791c42de6dSgd78059 */ 27801c42de6dSgd78059 if ((mprog2.addr_space < 240) || (mprog2.addr_space > 255)) { 27811c42de6dSgd78059 return (EINVAL); 27821c42de6dSgd78059 } 27831c42de6dSgd78059 27841c42de6dSgd78059 bscv_enter(ssp); 27851c42de6dSgd78059 27861c42de6dSgd78059 /* Calculate required data location */ 27871c42de6dSgd78059 data_size = 255; 27881c42de6dSgd78059 base_addr = (mprog2.addr_space - 240) * data_size; 27891c42de6dSgd78059 27901c42de6dSgd78059 eeprom_size = bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) * 27911c42de6dSgd78059 1024; 27921c42de6dSgd78059 27931c42de6dSgd78059 if (bscv_faulty(ssp)) { 27941c42de6dSgd78059 bscv_exit(ssp); 27951c42de6dSgd78059 return (EIO); 27961c42de6dSgd78059 } else if ((base_addr + data_size) > eeprom_size) { 2797*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'M', "bscv_ioc_mprog2", 27981c42de6dSgd78059 "Request extends past end of eeprom"); 27991c42de6dSgd78059 bscv_exit(ssp); 28001c42de6dSgd78059 return (ENXIO); 28011c42de6dSgd78059 } 28021c42de6dSgd78059 28031c42de6dSgd78059 bscv_put8(ssp, chan_general, EBUS_IDX_CMD_RES, EBUS_CMD_UNLOCK1); 28041c42de6dSgd78059 if (bscv_faulty(ssp)) { 2805*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'M', "bscv_ioc_mprog2", "ML1 Write failed"); 28061c42de6dSgd78059 bscv_exit(ssp); 28071c42de6dSgd78059 return (EIO); 28081c42de6dSgd78059 } 28091c42de6dSgd78059 28101c42de6dSgd78059 bscv_put8(ssp, chan_general, EBUS_IDX_CMD_RES, EBUS_CMD_UNLOCK2); 28111c42de6dSgd78059 if (bscv_faulty(ssp)) { 2812*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'M', "bscv_ioc_mprog2", "ML2 Write failed"); 28131c42de6dSgd78059 bscv_exit(ssp); 28141c42de6dSgd78059 return (EIO); 28151c42de6dSgd78059 } 28161c42de6dSgd78059 28171c42de6dSgd78059 if (bscv_eerw(ssp, base_addr, &mprog2.data[0], 28181c42de6dSgd78059 data_size, B_TRUE /* write */) != 0) { 28191c42de6dSgd78059 res = EIO; 28201c42de6dSgd78059 } 28211c42de6dSgd78059 28221c42de6dSgd78059 /* Read a probe key to release the lock. */ 28231c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_PROBEAA); 28241c42de6dSgd78059 28251c42de6dSgd78059 if (bscv_faulty(ssp)) { 28261c42de6dSgd78059 res = EIO; 28271c42de6dSgd78059 } 28281c42de6dSgd78059 bscv_exit(ssp); 28291c42de6dSgd78059 28301c42de6dSgd78059 return (res); 28311c42de6dSgd78059 } 28321c42de6dSgd78059 28331c42de6dSgd78059 /* 28341c42de6dSgd78059 * LOMIOCMREAD2 28351c42de6dSgd78059 */ 28361c42de6dSgd78059 static int 28371c42de6dSgd78059 bscv_ioc_mread2(bscv_soft_state_t *ssp, intptr_t arg, int mode) 28381c42de6dSgd78059 { 28391c42de6dSgd78059 lom2_mprog_t mprog2; 28401c42de6dSgd78059 uint32_t base_addr; 28411c42de6dSgd78059 uint32_t data_size; 28421c42de6dSgd78059 uint32_t eeprom_size; 28431c42de6dSgd78059 int res = 0; 28441c42de6dSgd78059 28451c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)&mprog2, sizeof (mprog2), 28461c42de6dSgd78059 mode) < 0) { 28471c42de6dSgd78059 return (EFAULT); 28481c42de6dSgd78059 } 28491c42de6dSgd78059 28501c42de6dSgd78059 /* 28511c42de6dSgd78059 * Need to stop the queue and then just read 28521c42de6dSgd78059 * the bytes blind to the relevant addresses. 28531c42de6dSgd78059 * Note that originally this was accessed as 255 byte pages 28541c42de6dSgd78059 * in address spaces 240-255. We have to emulate this behaviour. 28551c42de6dSgd78059 */ 28561c42de6dSgd78059 if ((mprog2.addr_space < 240) || (mprog2.addr_space > 255)) { 28571c42de6dSgd78059 return (EINVAL); 28581c42de6dSgd78059 } 28591c42de6dSgd78059 28601c42de6dSgd78059 bscv_enter(ssp); 28611c42de6dSgd78059 28621c42de6dSgd78059 /* Calculate required data location */ 28631c42de6dSgd78059 data_size = 255; 28641c42de6dSgd78059 base_addr = (mprog2.addr_space - 240) * data_size; 28651c42de6dSgd78059 eeprom_size = bscv_get8(ssp, chan_general, EBUS_IDX_EEPROM_SIZE_KB) * 28661c42de6dSgd78059 1024; 28671c42de6dSgd78059 28681c42de6dSgd78059 if (bscv_faulty(ssp)) { 28691c42de6dSgd78059 bscv_exit(ssp); 28701c42de6dSgd78059 return (EIO); 28711c42de6dSgd78059 } else if ((base_addr + data_size) > eeprom_size) { 2872*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'M', "bscv_ioc_mread2", 28731c42de6dSgd78059 "Request extends past end of eeprom"); 28741c42de6dSgd78059 bscv_exit(ssp); 28751c42de6dSgd78059 return (ENXIO); 28761c42de6dSgd78059 } 28771c42de6dSgd78059 28781c42de6dSgd78059 if (bscv_eerw(ssp, base_addr, &mprog2.data[0], 28791c42de6dSgd78059 data_size, B_FALSE /* read */) != 0) { 28801c42de6dSgd78059 res = EIO; 28811c42de6dSgd78059 } 28821c42de6dSgd78059 28831c42de6dSgd78059 if (bscv_faulty(ssp)) { 28841c42de6dSgd78059 res = EIO; 28851c42de6dSgd78059 } 28861c42de6dSgd78059 bscv_exit(ssp); 28871c42de6dSgd78059 28881c42de6dSgd78059 if ((res == 0) && 28891c42de6dSgd78059 (ddi_copyout((caddr_t)&mprog2, (caddr_t)arg, sizeof (mprog2), 28901c42de6dSgd78059 mode) < 0)) { 28911c42de6dSgd78059 res = EFAULT; 28921c42de6dSgd78059 } 28931c42de6dSgd78059 return (res); 28941c42de6dSgd78059 } 28951c42de6dSgd78059 28961c42de6dSgd78059 static void 28971c42de6dSgd78059 bscv_get_state_changes(bscv_soft_state_t *ssp) 28981c42de6dSgd78059 { 28991c42de6dSgd78059 int i = STATUS_READ_LIMIT; 29001c42de6dSgd78059 uint8_t change; 29011c42de6dSgd78059 uint8_t detail; 29021c42de6dSgd78059 29031c42de6dSgd78059 ASSERT(bscv_held(ssp)); 29041c42de6dSgd78059 29051c42de6dSgd78059 while (i-- && !ssp->cssp_prog) { 29061c42de6dSgd78059 /* Are there any changes to process? */ 29071c42de6dSgd78059 change = bscv_get8(ssp, chan_general, EBUS_IDX_STATE_CHNG); 29081c42de6dSgd78059 change &= EBUS_STATE_MASK; 29091c42de6dSgd78059 if (!change) 29101c42de6dSgd78059 break; 29111c42de6dSgd78059 29121c42de6dSgd78059 /* Clarify the pending change */ 29131c42de6dSgd78059 detail = bscv_get8(ssp, chan_general, EBUS_IDX_EVENT_DETAIL); 29141c42de6dSgd78059 29151c42de6dSgd78059 bscv_status(ssp, change, detail); 29161c42de6dSgd78059 } 29171c42de6dSgd78059 2918*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_get_state_changes", 29191c42de6dSgd78059 "loop index %d ssp->cssp_prog 0x%x", i, ssp->cssp_prog); 29201c42de6dSgd78059 } 29211c42de6dSgd78059 29221c42de6dSgd78059 /* 29231c42de6dSgd78059 * ********************************************************************* 29241c42de6dSgd78059 * Event Processing 29251c42de6dSgd78059 * ********************************************************************* 29261c42de6dSgd78059 */ 29271c42de6dSgd78059 29281c42de6dSgd78059 /* 29291c42de6dSgd78059 * function - bscv_event_daemon 29301c42de6dSgd78059 * description - Perform periodic lom tasks in a separate thread. 29311c42de6dSgd78059 * inputs - LOM soft state structure pointer 29321c42de6dSgd78059 * outputs - none. 29331c42de6dSgd78059 */ 29341c42de6dSgd78059 static void 29351c42de6dSgd78059 bscv_event_daemon(void *arg) 29361c42de6dSgd78059 { 29371c42de6dSgd78059 bscv_soft_state_t *ssp = (void *)arg; 29381c42de6dSgd78059 boolean_t do_events; 29391c42de6dSgd78059 boolean_t do_status; 29401c42de6dSgd78059 boolean_t do_nodename; 29411c42de6dSgd78059 boolean_t do_watchdog; 29421c42de6dSgd78059 uint32_t async_reg; 29431c42de6dSgd78059 uint32_t fault; 29441c42de6dSgd78059 clock_t poll_period = BSC_EVENT_POLL_NORMAL; 29451c42de6dSgd78059 int fault_cnt = 0; 29461c42de6dSgd78059 2947*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_event_daemon", 29481c42de6dSgd78059 "bscv_event_daemon: started"); 29491c42de6dSgd78059 29501c42de6dSgd78059 /* Acquire task daemon lock. */ 29511c42de6dSgd78059 mutex_enter(&ssp->task_mu); 29521c42de6dSgd78059 29531c42de6dSgd78059 ssp->task_flags |= TASK_ALIVE_FLG; 29541c42de6dSgd78059 29551c42de6dSgd78059 for (;;) { 29561c42de6dSgd78059 if ((ssp->task_flags & TASK_STOP_FLG) != 0) { 29571c42de6dSgd78059 /* Stop request seen - terminate */ 29581c42de6dSgd78059 break; 29591c42de6dSgd78059 } 29601c42de6dSgd78059 if ((ssp->task_flags & TASK_PAUSE_FLG) == 0) { 29611c42de6dSgd78059 /* Poll for events reported to the nexus */ 29621c42de6dSgd78059 mutex_exit(&ssp->task_mu); 29631c42de6dSgd78059 /* Probe and Check faults */ 29641c42de6dSgd78059 bscv_enter(ssp); 29651c42de6dSgd78059 async_reg = bscv_probe(ssp, chan_general, &fault); 2966*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_event_daemon", 29671c42de6dSgd78059 "process event: async_reg 0x%x, fault 0x%x", 29681c42de6dSgd78059 async_reg, fault); 29691c42de6dSgd78059 29701c42de6dSgd78059 if (!fault) { 29711c42de6dSgd78059 /* Treat non-fault conditions */ 29721c42de6dSgd78059 29731c42de6dSgd78059 if (ssp->cssp_prog || ssp->prog_mode_only) { 29741c42de6dSgd78059 /* 29751c42de6dSgd78059 * The BSC has become available again. 29761c42de6dSgd78059 */ 29771c42de6dSgd78059 fault_cnt = 0; 29781c42de6dSgd78059 ssp->cssp_prog = B_FALSE; 29791c42de6dSgd78059 ssp->prog_mode_only = B_FALSE; 29801c42de6dSgd78059 (void) bscv_attach_common(ssp); 29811c42de6dSgd78059 } else if (fault_cnt > 0) { 29821c42de6dSgd78059 /* Previous fault has cleared */ 29831c42de6dSgd78059 bscv_clear_fault(ssp); 29841c42de6dSgd78059 fault_cnt = 0; 29851c42de6dSgd78059 cmn_err(CE_WARN, 29861c42de6dSgd78059 "!bscv_event_daemon previous fault " 29871c42de6dSgd78059 "cleared."); 29881c42de6dSgd78059 } else if (bscv_faulty(ssp)) { 29891c42de6dSgd78059 /* Previous fault has cleared */ 29901c42de6dSgd78059 bscv_clear_fault(ssp); 29911c42de6dSgd78059 /* Sleep to avoid busy waiting */ 29921c42de6dSgd78059 ssp->event_sleep = B_TRUE; 29931c42de6dSgd78059 } 29941c42de6dSgd78059 poll_period = BSC_EVENT_POLL_NORMAL; 29951c42de6dSgd78059 29961c42de6dSgd78059 if (async_reg) { 29971c42de6dSgd78059 ssp->status_change = B_TRUE; 29981c42de6dSgd78059 ssp->event_waiting = B_TRUE; 29991c42de6dSgd78059 } 30001c42de6dSgd78059 } else if (ssp->cssp_prog) { 30011c42de6dSgd78059 /* 30021c42de6dSgd78059 * Expect radio silence or error values 30031c42de6dSgd78059 * when the CSSP is upgrading the BSC firmware 30041c42de6dSgd78059 * so throw away any fault indication. 30051c42de6dSgd78059 */ 30061c42de6dSgd78059 fault = B_FALSE; 30071c42de6dSgd78059 } else if (fault_cnt == BSC_PROBE_FAULT_LIMIT) { 30081c42de6dSgd78059 /* Count previous faults and maybe fail */ 30091c42de6dSgd78059 /* Declare the lom broken */ 30101c42de6dSgd78059 bscv_set_fault(ssp); 30111c42de6dSgd78059 poll_period = BSC_EVENT_POLL_FAULTY; 30121c42de6dSgd78059 cmn_err(CE_WARN, 30131c42de6dSgd78059 "!bscv_event_daemon had faults probing " 30141c42de6dSgd78059 "lom - marking it as faulty."); 30151c42de6dSgd78059 /* 30161c42de6dSgd78059 * Increment fault_cnt to ensure that 30171c42de6dSgd78059 * next time we do not report a message 30181c42de6dSgd78059 * i.e. we drop out of the bottom 30191c42de6dSgd78059 */ 30201c42de6dSgd78059 fault_cnt = BSC_PROBE_FAULT_LIMIT + 1; 30211c42de6dSgd78059 ssp->event_sleep = B_TRUE; 30221c42de6dSgd78059 } else if (fault_cnt < BSC_PROBE_FAULT_LIMIT) { 30231c42de6dSgd78059 if (bscv_faulty(ssp)) { 30241c42de6dSgd78059 poll_period = BSC_EVENT_POLL_FAULTY; 30251c42de6dSgd78059 /* 30261c42de6dSgd78059 * No recovery messages in this case 30271c42de6dSgd78059 * because there was never a fault 30281c42de6dSgd78059 * message here. 30291c42de6dSgd78059 */ 30301c42de6dSgd78059 fault_cnt = 0; 30311c42de6dSgd78059 } else { 30321c42de6dSgd78059 /* Getting ready to explode */ 30331c42de6dSgd78059 fault_cnt++; 30341c42de6dSgd78059 cmn_err(CE_WARN, 30351c42de6dSgd78059 "!bscv_event_daemon had fault 0x%x", 30361c42de6dSgd78059 fault); 30371c42de6dSgd78059 } 30381c42de6dSgd78059 ssp->event_sleep = B_TRUE; 30391c42de6dSgd78059 } 30401c42de6dSgd78059 bscv_exit(ssp); 30411c42de6dSgd78059 mutex_enter(&ssp->task_mu); 30421c42de6dSgd78059 } 30431c42de6dSgd78059 30441c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 30451c42de6dSgd78059 /* 30461c42de6dSgd78059 * we have no platmod hook on Solaris x86 to report 30471c42de6dSgd78059 * a change to the nodename so we keep a copy so 30481c42de6dSgd78059 * we can detect a change and request that the bsc 30491c42de6dSgd78059 * be updated when appropriate. 30501c42de6dSgd78059 */ 30511c42de6dSgd78059 if (strcmp(ssp->last_nodename, utsname.nodename) != 0) { 30521c42de6dSgd78059 3053*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'X', "bscv_event_daemon", 30541c42de6dSgd78059 "utsname.nodename='%s' possible change detected", 30551c42de6dSgd78059 utsname.nodename); 30561c42de6dSgd78059 ssp->nodename_change = B_TRUE; 30571c42de6dSgd78059 (void) strncpy(ssp->last_nodename, utsname.nodename, 30581c42de6dSgd78059 sizeof (ssp->last_nodename)); 30591c42de6dSgd78059 /* enforce null termination */ 30601c42de6dSgd78059 ssp->last_nodename[sizeof (ssp->last_nodename) - 1] = 30611c42de6dSgd78059 '\0'; 30621c42de6dSgd78059 } 30631c42de6dSgd78059 #endif /* __i386 || __amd64 */ 30641c42de6dSgd78059 30651c42de6dSgd78059 if (((ssp->task_flags & TASK_PAUSE_FLG) == 0) && 30661c42de6dSgd78059 fault_cnt == 0 && ssp->cssp_prog == B_FALSE && 30671c42de6dSgd78059 (ssp->event_waiting || ssp->status_change || 30681c42de6dSgd78059 ssp->nodename_change || ssp->watchdog_change)) { 30691c42de6dSgd78059 30701c42de6dSgd78059 do_events = ssp->event_waiting; 30711c42de6dSgd78059 ssp->event_waiting = B_FALSE; 30721c42de6dSgd78059 ssp->task_flags |= do_events ? 30731c42de6dSgd78059 TASK_EVENT_PENDING_FLG : 0; 30741c42de6dSgd78059 do_status = ssp->status_change; 30751c42de6dSgd78059 ssp->status_change = B_FALSE; 30761c42de6dSgd78059 do_nodename = ssp->nodename_change; 30771c42de6dSgd78059 ssp->nodename_change = B_FALSE; 30781c42de6dSgd78059 do_watchdog = ssp->watchdog_change; 30791c42de6dSgd78059 if (ssp->watchdog_change) { 30801c42de6dSgd78059 ssp->watchdog_change = B_FALSE; 30811c42de6dSgd78059 } 30821c42de6dSgd78059 30831c42de6dSgd78059 mutex_exit(&ssp->task_mu); 30841c42de6dSgd78059 /* 30851c42de6dSgd78059 * We must not hold task_mu whilst processing 30861c42de6dSgd78059 * events because this can lead to priority 30871c42de6dSgd78059 * inversion and hence our interrupts getting 30881c42de6dSgd78059 * locked out. 30891c42de6dSgd78059 */ 30901c42de6dSgd78059 bscv_enter(ssp); 30911c42de6dSgd78059 if (do_events) { 30921c42de6dSgd78059 bscv_event_process(ssp, do_events); 30931c42de6dSgd78059 } 30941c42de6dSgd78059 if (do_nodename) { 3095*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_event_daemon", 30961c42de6dSgd78059 "do_nodename task"); 30971c42de6dSgd78059 bscv_setup_hostname(ssp); 30981c42de6dSgd78059 } 30991c42de6dSgd78059 if (do_watchdog) { 3100*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_event_daemon", 31011c42de6dSgd78059 "do_watchdog task"); 31021c42de6dSgd78059 bscv_setup_watchdog(ssp); 31031c42de6dSgd78059 } 31041c42de6dSgd78059 /* 31051c42de6dSgd78059 * Pending status changes are dealt with last because 31061c42de6dSgd78059 * if we see that the BSC is about to be programmed, 31071c42de6dSgd78059 * then it will expect us to to quiescent in the 31081c42de6dSgd78059 * first second so it can cleanly tear down its comms 31091c42de6dSgd78059 * protocols; this takes ~100 ms. 31101c42de6dSgd78059 */ 31111c42de6dSgd78059 if (do_status) { 31121c42de6dSgd78059 bscv_get_state_changes(ssp); 31131c42de6dSgd78059 } 31141c42de6dSgd78059 if (bscv_session_error(ssp)) { 31151c42de6dSgd78059 /* 31161c42de6dSgd78059 * Had fault during event session. We always 31171c42de6dSgd78059 * sleep after one of these because there 31181c42de6dSgd78059 * may be a problem with the lom which stops 31191c42de6dSgd78059 * us doing useful work in the event daemon. 31201c42de6dSgd78059 * If we don't sleep then we may livelock. 31211c42de6dSgd78059 */ 3122*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_event_daemon", 31231c42de6dSgd78059 "had session error - sleeping"); 31241c42de6dSgd78059 ssp->event_sleep = B_TRUE; 31251c42de6dSgd78059 } 31261c42de6dSgd78059 bscv_exit(ssp); 31271c42de6dSgd78059 31281c42de6dSgd78059 mutex_enter(&ssp->task_mu); 31291c42de6dSgd78059 31301c42de6dSgd78059 if (ssp->task_flags & TASK_EVENT_PENDING_FLG) { 31311c42de6dSgd78059 /* 31321c42de6dSgd78059 * We have read any events which were 31331c42de6dSgd78059 * pending. Let the consumer continue. 31341c42de6dSgd78059 * Ignore the race condition with new events 31351c42de6dSgd78059 * arriving - just let the consumer have 31361c42de6dSgd78059 * whatever was pending when they asked. 31371c42de6dSgd78059 */ 31381c42de6dSgd78059 ssp->event_active_count++; 31391c42de6dSgd78059 ssp->task_flags &= ~(TASK_EVENT_PENDING_FLG | 31401c42de6dSgd78059 TASK_EVENT_CONSUMER_FLG); 31411c42de6dSgd78059 cv_broadcast(&ssp->task_evnt_cv); 31421c42de6dSgd78059 } 31431c42de6dSgd78059 } else { 31441c42de6dSgd78059 /* There was nothing to do - sleep */ 31451c42de6dSgd78059 ssp->event_sleep = B_TRUE; 31461c42de6dSgd78059 } 31471c42de6dSgd78059 31481c42de6dSgd78059 if (ssp->event_sleep) { 31491c42de6dSgd78059 ssp->task_flags |= TASK_SLEEPING_FLG; 31501c42de6dSgd78059 /* Sleep until there is something to do */ 31511c42de6dSgd78059 (void) cv_timedwait(&ssp->task_cv, 31521c42de6dSgd78059 &ssp->task_mu, 31531c42de6dSgd78059 poll_period + ddi_get_lbolt()); 31541c42de6dSgd78059 ssp->task_flags &= ~TASK_SLEEPING_FLG; 31551c42de6dSgd78059 ssp->event_sleep = B_FALSE; 31561c42de6dSgd78059 } 31571c42de6dSgd78059 } 31581c42de6dSgd78059 31591c42de6dSgd78059 if (ssp->task_flags & TASK_EVENT_CONSUMER_FLG) { 31601c42de6dSgd78059 /* 31611c42de6dSgd78059 * We are going away so wake up any event consumer. 31621c42de6dSgd78059 * Pretend that any pending events have been processed. 31631c42de6dSgd78059 */ 31641c42de6dSgd78059 ssp->event_active_count += 2; 31651c42de6dSgd78059 cv_broadcast(&ssp->task_evnt_cv); 31661c42de6dSgd78059 } 31671c42de6dSgd78059 31681c42de6dSgd78059 ASSERT(!(ssp->task_flags & TASK_EVENT_PENDING_FLG)); 31691c42de6dSgd78059 ssp->task_flags &= 31701c42de6dSgd78059 ~(TASK_STOP_FLG | TASK_ALIVE_FLG | TASK_EVENT_CONSUMER_FLG); 31711c42de6dSgd78059 mutex_exit(&ssp->task_mu); 31721c42de6dSgd78059 3173*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_event_daemon", 31741c42de6dSgd78059 "exiting."); 31751c42de6dSgd78059 } 31761c42de6dSgd78059 31771c42de6dSgd78059 /* 31781c42de6dSgd78059 * function - bscv_start_event_daemon 31791c42de6dSgd78059 * description - Create the event daemon thread. 31801c42de6dSgd78059 * inputs - LOM soft state structure pointer 31811c42de6dSgd78059 * outputs - none 31821c42de6dSgd78059 */ 31831c42de6dSgd78059 static void 31841c42de6dSgd78059 bscv_start_event_daemon(bscv_soft_state_t *ssp) 31851c42de6dSgd78059 { 31861c42de6dSgd78059 if (ssp->progress & BSCV_THREAD) 31871c42de6dSgd78059 return; 31881c42de6dSgd78059 31891c42de6dSgd78059 /* Start the event thread after the queue has started */ 31901c42de6dSgd78059 (void) thread_create(NULL, 0, (void (*)())bscv_event_daemon, ssp, 31911c42de6dSgd78059 0, &p0, TS_RUN, minclsyspri); 31921c42de6dSgd78059 31931c42de6dSgd78059 ssp->progress |= BSCV_THREAD; 31941c42de6dSgd78059 } 31951c42de6dSgd78059 31961c42de6dSgd78059 /* 31971c42de6dSgd78059 * function - bscv_stop_event_daemon 31981c42de6dSgd78059 * description - Attempt to stop the event daemon thread. 31991c42de6dSgd78059 * inputs - LOM soft state structure pointer 32001c42de6dSgd78059 * outputs - DDI_SUCCESS OR DDI_FAILURE 32011c42de6dSgd78059 */ 32021c42de6dSgd78059 static int 32031c42de6dSgd78059 bscv_stop_event_daemon(bscv_soft_state_t *ssp) 32041c42de6dSgd78059 { 32051c42de6dSgd78059 int try; 32061c42de6dSgd78059 int res = DDI_SUCCESS; 32071c42de6dSgd78059 32081c42de6dSgd78059 mutex_enter(&ssp->task_mu); 32091c42de6dSgd78059 32101c42de6dSgd78059 /* Wait for task daemon to stop running. */ 32111c42de6dSgd78059 for (try = 0; 32121c42de6dSgd78059 ((ssp->task_flags & TASK_ALIVE_FLG) && try < 10); 32131c42de6dSgd78059 try++) { 32141c42de6dSgd78059 /* Signal that the task daemon should stop */ 32151c42de6dSgd78059 ssp->task_flags |= TASK_STOP_FLG; 32161c42de6dSgd78059 cv_signal(&ssp->task_cv); 32171c42de6dSgd78059 /* Release task daemon lock. */ 32181c42de6dSgd78059 mutex_exit(&ssp->task_mu); 32191c42de6dSgd78059 /* 32201c42de6dSgd78059 * TODO - when the driver is modified to support 32211c42de6dSgd78059 * system suspend or if this routine gets called 32221c42de6dSgd78059 * during panic we should use drv_usecwait() rather 32231c42de6dSgd78059 * than delay in those circumstances. 32241c42de6dSgd78059 */ 32251c42de6dSgd78059 delay(drv_usectohz(1000000)); 32261c42de6dSgd78059 mutex_enter(&ssp->task_mu); 32271c42de6dSgd78059 } 32281c42de6dSgd78059 32291c42de6dSgd78059 if (ssp->task_flags & TASK_ALIVE_FLG) { 32301c42de6dSgd78059 res = DDI_FAILURE; 32311c42de6dSgd78059 } 32321c42de6dSgd78059 mutex_exit(&ssp->task_mu); 32331c42de6dSgd78059 32341c42de6dSgd78059 return (res); 32351c42de6dSgd78059 } 32361c42de6dSgd78059 32371c42de6dSgd78059 /* 32381c42de6dSgd78059 * function - bscv_pause_event_daemon 32391c42de6dSgd78059 * description - Attempt to pause the event daemon thread. 32401c42de6dSgd78059 * inputs - LOM soft state structure pointer 32411c42de6dSgd78059 * outputs - DDI_SUCCESS OR DDI_FAILURE 32421c42de6dSgd78059 */ 32431c42de6dSgd78059 static int 32441c42de6dSgd78059 bscv_pause_event_daemon(bscv_soft_state_t *ssp) 32451c42de6dSgd78059 { 32461c42de6dSgd78059 int try; 32471c42de6dSgd78059 32481c42de6dSgd78059 if (!(ssp->progress & BSCV_THREAD)) { 32491c42de6dSgd78059 /* Nothing to do */ 32501c42de6dSgd78059 return (BSCV_SUCCESS); 32511c42de6dSgd78059 } 32521c42de6dSgd78059 3253*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon", 32541c42de6dSgd78059 "Attempting to pause event daemon"); 32551c42de6dSgd78059 32561c42de6dSgd78059 mutex_enter(&ssp->task_mu); 32571c42de6dSgd78059 /* Signal that the task daemon should pause */ 32581c42de6dSgd78059 ssp->task_flags |= TASK_PAUSE_FLG; 32591c42de6dSgd78059 32601c42de6dSgd78059 /* Wait for task daemon to pause. */ 32611c42de6dSgd78059 for (try = 0; 32621c42de6dSgd78059 (!(ssp->task_flags & TASK_SLEEPING_FLG) && 32631c42de6dSgd78059 (ssp->task_flags & TASK_ALIVE_FLG) && 32641c42de6dSgd78059 try < 10); 32651c42de6dSgd78059 try++) { 32661c42de6dSgd78059 /* Paranoia */ 32671c42de6dSgd78059 ssp->task_flags |= TASK_PAUSE_FLG; 32681c42de6dSgd78059 cv_signal(&ssp->task_cv); 32691c42de6dSgd78059 /* Release task daemon lock. */ 32701c42de6dSgd78059 mutex_exit(&ssp->task_mu); 32711c42de6dSgd78059 delay(drv_usectohz(1000000)); 32721c42de6dSgd78059 mutex_enter(&ssp->task_mu); 32731c42de6dSgd78059 } 32741c42de6dSgd78059 if ((ssp->task_flags & TASK_SLEEPING_FLG) || 32751c42de6dSgd78059 !(ssp->task_flags & TASK_ALIVE_FLG)) { 32761c42de6dSgd78059 mutex_exit(&ssp->task_mu); 3277*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon", 32781c42de6dSgd78059 "Pause event daemon - success"); 32791c42de6dSgd78059 return (BSCV_SUCCESS); 32801c42de6dSgd78059 } 32811c42de6dSgd78059 mutex_exit(&ssp->task_mu); 3282*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon", 32831c42de6dSgd78059 "Pause event daemon - failed"); 32841c42de6dSgd78059 return (BSCV_FAILURE); 32851c42de6dSgd78059 } 32861c42de6dSgd78059 32871c42de6dSgd78059 /* 32881c42de6dSgd78059 * function - bscv_resume_event_daemon 32891c42de6dSgd78059 * description - Resumethe event daemon thread. 32901c42de6dSgd78059 * inputs - LOM soft state structure pointer 32911c42de6dSgd78059 * outputs - None. 32921c42de6dSgd78059 */ 32931c42de6dSgd78059 static void 32941c42de6dSgd78059 bscv_resume_event_daemon(bscv_soft_state_t *ssp) 32951c42de6dSgd78059 { 32961c42de6dSgd78059 if (!(ssp->progress & BSCV_THREAD)) { 32971c42de6dSgd78059 /* Nothing to do */ 32981c42de6dSgd78059 return; 32991c42de6dSgd78059 } 33001c42de6dSgd78059 33011c42de6dSgd78059 mutex_enter(&ssp->task_mu); 33021c42de6dSgd78059 /* Allow the task daemon to resume event processing */ 33031c42de6dSgd78059 ssp->task_flags &= ~TASK_PAUSE_FLG; 33041c42de6dSgd78059 cv_signal(&ssp->task_cv); 33051c42de6dSgd78059 mutex_exit(&ssp->task_mu); 33061c42de6dSgd78059 3307*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_pause_event_daemon", 33081c42de6dSgd78059 "Event daemon resumed"); 33091c42de6dSgd78059 } 33101c42de6dSgd78059 33111c42de6dSgd78059 /* 33121c42de6dSgd78059 * function - bscv_event_process 33131c42de6dSgd78059 * description - process (report) events 33141c42de6dSgd78059 * inputs - Soft state ptr, process event request 33151c42de6dSgd78059 * outputs - none 33161c42de6dSgd78059 */ 33171c42de6dSgd78059 static void 33181c42de6dSgd78059 bscv_event_process(bscv_soft_state_t *ssp, boolean_t do_events) 33191c42de6dSgd78059 { 33201c42de6dSgd78059 uint32_t currptr; 33211c42de6dSgd78059 unsigned int count; 33221c42de6dSgd78059 33231c42de6dSgd78059 /* Raw values read from the lom */ 33241c42de6dSgd78059 uint8_t evcount; 33251c42de6dSgd78059 uint16_t logptr; 33261c42de6dSgd78059 33271c42de6dSgd78059 lom_event_t event; 33281c42de6dSgd78059 33291c42de6dSgd78059 if (do_events) { 33301c42de6dSgd78059 /* 33311c42de6dSgd78059 * Read count, next event ptr MSB,LSB. Note a read of count 33321c42de6dSgd78059 * latches values for the next event ptr 33331c42de6dSgd78059 */ 33341c42de6dSgd78059 evcount = bscv_get8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS); 33351c42de6dSgd78059 logptr = bscv_get16(ssp, chan_general, EBUS_IDX_LOG_PTR_HI); 33361c42de6dSgd78059 33371c42de6dSgd78059 /* Sanity check the values from the lom */ 33381c42de6dSgd78059 count = bscv_event_validate(ssp, logptr, evcount); 33391c42de6dSgd78059 33401c42de6dSgd78059 if (count == -1) { 33411c42de6dSgd78059 /* 33421c42de6dSgd78059 * Nothing to do - or badly configured event log. 33431c42de6dSgd78059 * We really do not want to touch the lom in this 33441c42de6dSgd78059 * case because any data that we access may be bad! 33451c42de6dSgd78059 * This differs from zero because if we have zero 33461c42de6dSgd78059 * to read the lom probably things that unread is 33471c42de6dSgd78059 * non-zero and we want that to be set to zero! 33481c42de6dSgd78059 * Signal event fault to make the thread wait 33491c42de6dSgd78059 * before attempting to re-read the log. 33501c42de6dSgd78059 */ 33511c42de6dSgd78059 ssp->event_sleep = B_TRUE; 33521c42de6dSgd78059 33531c42de6dSgd78059 goto logdone; 33541c42de6dSgd78059 } 33551c42de6dSgd78059 if (ssp->event_fault_reported) { 33561c42de6dSgd78059 /* Clear down any old status - things are fixed */ 33571c42de6dSgd78059 cmn_err(CE_NOTE, "Event pointer fault recovered."); 33581c42de6dSgd78059 ssp->event_fault_reported = B_FALSE; 33591c42de6dSgd78059 } 33601c42de6dSgd78059 33611c42de6dSgd78059 /* Compute the first entry that we need to read. */ 33621c42de6dSgd78059 currptr = logptr - ssp->eventlog_start; 33631c42de6dSgd78059 currptr += ssp->eventlog_size; 33641c42de6dSgd78059 currptr -= (count * sizeof (event)); 33651c42de6dSgd78059 currptr %= ssp->eventlog_size; 33661c42de6dSgd78059 currptr += ssp->eventlog_start; 33671c42de6dSgd78059 3368*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_event_process", 33691c42de6dSgd78059 "processing %d events from 0x%x in 0x%x:0x%x", 33701c42de6dSgd78059 count, currptr, 33711c42de6dSgd78059 ssp->eventlog_start, 33721c42de6dSgd78059 ssp->eventlog_start + ssp->eventlog_size); 33731c42de6dSgd78059 33741c42de6dSgd78059 for (; count > 0; count--) { 33751c42de6dSgd78059 /* Ensure window is positioned correctly */ 33761c42de6dSgd78059 if (bscv_eerw(ssp, currptr, (uint8_t *)&event, 33771c42de6dSgd78059 sizeof (event), B_FALSE /* read */) != 0) { 33781c42de6dSgd78059 /* Fault reading data - stop */ 33791c42de6dSgd78059 break; 33801c42de6dSgd78059 } 33811c42de6dSgd78059 33821c42de6dSgd78059 bscv_event_process_one(ssp, &event); 33831c42de6dSgd78059 bscv_sysevent(ssp, &event); 33841c42de6dSgd78059 33851c42de6dSgd78059 currptr += sizeof (event); 33861c42de6dSgd78059 if (currptr >= ssp->eventlog_start + 33871c42de6dSgd78059 ssp->eventlog_size) { 33881c42de6dSgd78059 currptr = ssp->eventlog_start; 33891c42de6dSgd78059 } 33901c42de6dSgd78059 } 33911c42de6dSgd78059 /* 33921c42de6dSgd78059 * Clear event count - write the evcount value to remove that 33931c42de6dSgd78059 * many from the unread total. 33941c42de6dSgd78059 * Adjust the value to reflect how many we have left to 33951c42de6dSgd78059 * read just in case we had a failure reading events. 33961c42de6dSgd78059 */ 33971c42de6dSgd78059 if (count == 0) { 33981c42de6dSgd78059 /*EMPTY*/ 33991c42de6dSgd78059 ASSERT(logptr == currptr); 34001c42de6dSgd78059 } else if (count > evcount) { 34011c42de6dSgd78059 evcount = 0; 34021c42de6dSgd78059 } else { 34031c42de6dSgd78059 evcount -= count; 34041c42de6dSgd78059 } 34051c42de6dSgd78059 bscv_put8(ssp, chan_general, EBUS_IDX_UNREAD_EVENTS, evcount); 34061c42de6dSgd78059 /* Remember where we were for next time */ 34071c42de6dSgd78059 ssp->oldeeptr = currptr; 34081c42de6dSgd78059 ssp->oldeeptr_valid = B_TRUE; 34091c42de6dSgd78059 logdone: 34101c42de6dSgd78059 ; 34111c42de6dSgd78059 } 34121c42de6dSgd78059 } 34131c42de6dSgd78059 34141c42de6dSgd78059 /* 34151c42de6dSgd78059 * function - bscv_event_validate 34161c42de6dSgd78059 * description - validate the event data supplied by the lom and determine 34171c42de6dSgd78059 * how many (if any) events to read. 34181c42de6dSgd78059 * This function performs complex checks to ensure that 34191c42de6dSgd78059 * events are not lost due to lom resets or host resets. 34201c42de6dSgd78059 * A combination of lom reset and host reset (i.e. power fail) 34211c42de6dSgd78059 * may cause some events to not be reported. 34221c42de6dSgd78059 * inputs - Soft state ptr, next event pointer, number of unread events. 34231c42de6dSgd78059 * outputs - the number of events to read. -1 on error. 34241c42de6dSgd78059 * zero is a valid value because it forces the loms unread 34251c42de6dSgd78059 * count to be cleared. 34261c42de6dSgd78059 */ 34271c42de6dSgd78059 static int 34281c42de6dSgd78059 bscv_event_validate(bscv_soft_state_t *ssp, uint32_t newptr, uint8_t unread) 34291c42de6dSgd78059 { 34301c42de6dSgd78059 uint32_t oldptr; 34311c42de6dSgd78059 unsigned int count; 34321c42de6dSgd78059 34331c42de6dSgd78059 if (!bscv_window_setup(ssp)) { 34341c42de6dSgd78059 /* Problem with lom eeprom setup we cannot do anything */ 34351c42de6dSgd78059 return (-1); 34361c42de6dSgd78059 } 34371c42de6dSgd78059 34381c42de6dSgd78059 /* Sanity check the event pointers */ 34391c42de6dSgd78059 if ((newptr < ssp->eventlog_start) || 34401c42de6dSgd78059 (newptr >= (ssp->eventlog_start + ssp->eventlog_size))) { 34411c42de6dSgd78059 if (!ssp->event_fault_reported) { 34421c42de6dSgd78059 cmn_err(CE_WARN, "Event pointer out of range. " 34431c42de6dSgd78059 "Cannot read events."); 34441c42de6dSgd78059 ssp->event_fault_reported = B_TRUE; 34451c42de6dSgd78059 } 34461c42de6dSgd78059 return (-1); 34471c42de6dSgd78059 } 34481c42de6dSgd78059 oldptr = ssp->oldeeptr; 34491c42de6dSgd78059 /* Now sanity check log pointer against count */ 34501c42de6dSgd78059 if (newptr < oldptr) { 34511c42de6dSgd78059 /* 34521c42de6dSgd78059 * Must have wrapped add eventlog_size to get the 34531c42de6dSgd78059 * correct relative values - this makes the checks 34541c42de6dSgd78059 * below work! 34551c42de6dSgd78059 */ 34561c42de6dSgd78059 newptr += ssp->eventlog_size; 34571c42de6dSgd78059 } 34581c42de6dSgd78059 if (!ssp->oldeeptr_valid) { 34591c42de6dSgd78059 /* We have just started up - we have to trust lom */ 34601c42de6dSgd78059 count = unread; 34611c42de6dSgd78059 } else if ((unread == 0) && (newptr == oldptr)) { 34621c42de6dSgd78059 /* Nothing to do - we were just polling */ 34631c42de6dSgd78059 return (-1); 34641c42de6dSgd78059 } else if (oldptr + (unread * sizeof (lom_event_t)) == newptr) { 34651c42de6dSgd78059 /* Ok - got as many events as we expected */ 34661c42de6dSgd78059 count = unread; 34671c42de6dSgd78059 } else if (oldptr + (unread * sizeof (lom_event_t)) > newptr) { 34681c42de6dSgd78059 /* 34691c42de6dSgd78059 * Errrm more messages than there should have been. 34701c42de6dSgd78059 * Possible causes: 34711c42de6dSgd78059 * 1. the event log has filled - we have been 34721c42de6dSgd78059 * away for a long time 34731c42de6dSgd78059 * 2. software bug in lom or driver. 34741c42de6dSgd78059 * 3. something that I haven't thought of! 34751c42de6dSgd78059 * Always warn about this we should really never 34761c42de6dSgd78059 * see it! 34771c42de6dSgd78059 */ 34781c42de6dSgd78059 count = (newptr - oldptr) / sizeof (lom_event_t); 3479*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_event_process", 34801c42de6dSgd78059 "bscv_event_process: lom reported " 34811c42de6dSgd78059 "more events (%d) than expected (%d).", 34821c42de6dSgd78059 unread, count); 34831c42de6dSgd78059 cmn_err(CE_CONT, "only processing %d events", count); 34841c42de6dSgd78059 } else { 34851c42de6dSgd78059 /* Less messages - perhaps the lom has been reset */ 34861c42de6dSgd78059 count = (newptr - oldptr) / sizeof (lom_event_t); 3487*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_event_process", 34881c42de6dSgd78059 "lom reported less events (%d) than expected (%d)" 34891c42de6dSgd78059 " - the lom may have been reset", 34901c42de6dSgd78059 unread, count); 34911c42de6dSgd78059 } 34921c42de6dSgd78059 /* Whatever happens only read a maximum of 255 entries */ 34931c42de6dSgd78059 if ((count >= 0xff)) { 34941c42de6dSgd78059 cmn_err(CE_WARN, 34951c42de6dSgd78059 "bscv_event_process: too many events (%d) to " 34961c42de6dSgd78059 "process - some may have been lost", count); 34971c42de6dSgd78059 count = 0xff; 34981c42de6dSgd78059 } 34991c42de6dSgd78059 return (count); 35001c42de6dSgd78059 } 35011c42de6dSgd78059 35021c42de6dSgd78059 /* 35031c42de6dSgd78059 * function - bscv_event_process_one 35041c42de6dSgd78059 * description - reports on state changes to the host. 35051c42de6dSgd78059 * 35061c42de6dSgd78059 * inputs - LOM soft state structure pointer. 35071c42de6dSgd78059 * 35081c42de6dSgd78059 * outputs - none. 35091c42de6dSgd78059 */ 35101c42de6dSgd78059 35111c42de6dSgd78059 static void 35121c42de6dSgd78059 bscv_event_process_one(bscv_soft_state_t *ssp, lom_event_t *event) 35131c42de6dSgd78059 { 35141c42de6dSgd78059 int level; 35151c42de6dSgd78059 char eventstr[100]; 35161c42de6dSgd78059 int msg_type = 0; 35171c42de6dSgd78059 35181c42de6dSgd78059 if (bscv_is_null_event(ssp, event)) { 35191c42de6dSgd78059 /* Cleared entry - do not report it */ 35201c42de6dSgd78059 return; 35211c42de6dSgd78059 } 35221c42de6dSgd78059 35231c42de6dSgd78059 level = bscv_level_of_event(event); 35241c42de6dSgd78059 35251c42de6dSgd78059 switch (level) { 35261c42de6dSgd78059 default: 35271c42de6dSgd78059 msg_type = CE_NOTE; 35281c42de6dSgd78059 break; 35291c42de6dSgd78059 35301c42de6dSgd78059 case EVENT_LEVEL_FATAL: 35311c42de6dSgd78059 case EVENT_LEVEL_FAULT: 35321c42de6dSgd78059 msg_type = CE_WARN; 35331c42de6dSgd78059 break; 35341c42de6dSgd78059 } 35351c42de6dSgd78059 35361c42de6dSgd78059 bscv_build_eventstring(ssp, event, eventstr, eventstr + 35371c42de6dSgd78059 sizeof (eventstr)); 35381c42de6dSgd78059 35391c42de6dSgd78059 if (level <= ssp->reporting_level) { 35401c42de6dSgd78059 /* 35411c42de6dSgd78059 * The message is important enough to be shown on the console 35421c42de6dSgd78059 * as well as the log. 35431c42de6dSgd78059 */ 35441c42de6dSgd78059 cmn_err(msg_type, "%s", eventstr); 35451c42de6dSgd78059 } else { 35461c42de6dSgd78059 /* 35471c42de6dSgd78059 * The message goes only to the log. 35481c42de6dSgd78059 */ 35491c42de6dSgd78059 cmn_err(msg_type, "!%s", eventstr); 35501c42de6dSgd78059 } 35511c42de6dSgd78059 } 35521c42de6dSgd78059 35531c42de6dSgd78059 /* 35541c42de6dSgd78059 * time formats 35551c42de6dSgd78059 * 35561c42de6dSgd78059 * The BSC represents times as seconds since epoch 1970. Currently it gives 35571c42de6dSgd78059 * us 32 bits, unsigned. In the future this might change to a 64-bit count, 35581c42de6dSgd78059 * to allow a greater range. 35591c42de6dSgd78059 * 35601c42de6dSgd78059 * Timestamp values below BSC_TIME_SANITY do not represent an absolute time, 35611c42de6dSgd78059 * but instead represent an offset from the last reset. This must be 35621c42de6dSgd78059 * borne in mind by output routines. 35631c42de6dSgd78059 */ 35641c42de6dSgd78059 35651c42de6dSgd78059 typedef uint32_t bsctime_t; 35661c42de6dSgd78059 35671c42de6dSgd78059 #define BSC_TIME_SANITY 1000000000 35681c42de6dSgd78059 35691c42de6dSgd78059 /* 35701c42de6dSgd78059 * render a formatted time for display 35711c42de6dSgd78059 */ 35721c42de6dSgd78059 35731c42de6dSgd78059 static size_t 35741c42de6dSgd78059 bscv_event_snprintgmttime(char *buf, size_t bufsz, todinfo_t t) 35751c42de6dSgd78059 { 35761c42de6dSgd78059 int year; 35771c42de6dSgd78059 35781c42de6dSgd78059 /* tod_year is base 1900 so this code needs to adjust */ 35791c42de6dSgd78059 year = 1900 + t.tod_year; 35801c42de6dSgd78059 35811c42de6dSgd78059 return (snprintf(buf, bufsz, "%04d-%02d-%02d %02d:%02d:%02dZ", 35821c42de6dSgd78059 year, t.tod_month, t.tod_day, t.tod_hour, 35831c42de6dSgd78059 t.tod_min, t.tod_sec)); 35841c42de6dSgd78059 } 35851c42de6dSgd78059 35861c42de6dSgd78059 /* 35871c42de6dSgd78059 * function - bscv_build_eventstring 35881c42de6dSgd78059 * description - reports on state changes to the host. 35891c42de6dSgd78059 * 35901c42de6dSgd78059 * inputs - LOM soft state structure pointer. 35911c42de6dSgd78059 * 35921c42de6dSgd78059 * outputs - none. 35931c42de6dSgd78059 */ 35941c42de6dSgd78059 35951c42de6dSgd78059 static void 35961c42de6dSgd78059 bscv_build_eventstring(bscv_soft_state_t *ssp, lom_event_t *event, 35971c42de6dSgd78059 char *buf, char *bufend) 35981c42de6dSgd78059 { 35991c42de6dSgd78059 uint8_t subsystem; 36001c42de6dSgd78059 uint8_t eventtype; 36011c42de6dSgd78059 bsctime_t bsctm; 36021c42de6dSgd78059 3603*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'S', "bscv_build_eventstring", "event %2x%2x%2x%2x", 36041c42de6dSgd78059 event->ev_subsys, event->ev_event, 36051c42de6dSgd78059 event->ev_resource, event->ev_detail); 3606*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'S', "bscv_build_eventstring", "time %2x%2x%2x%2x", 36071c42de6dSgd78059 event->ev_data[0], event->ev_data[1], 36081c42de6dSgd78059 event->ev_data[2], event->ev_data[3]); 36091c42de6dSgd78059 36101c42de6dSgd78059 /* 36111c42de6dSgd78059 * We accept bad subsystems and event type codes here. 36121c42de6dSgd78059 * The code decodes as much as possible and then produces 36131c42de6dSgd78059 * suitable output. 36141c42de6dSgd78059 */ 36151c42de6dSgd78059 subsystem = EVENT_DECODE_SUBSYS(event->ev_subsys); 36161c42de6dSgd78059 eventtype = event->ev_event; 36171c42de6dSgd78059 36181c42de6dSgd78059 /* time */ 36191c42de6dSgd78059 bsctm = (((uint32_t)event->ev_data[0]) << 24) | 36201c42de6dSgd78059 (((uint32_t)event->ev_data[1]) << 16) | 36211c42de6dSgd78059 (((uint32_t)event->ev_data[2]) << 8) | 36221c42de6dSgd78059 ((uint32_t)event->ev_data[3]); 36231c42de6dSgd78059 if (bsctm < BSC_TIME_SANITY) { 36241c42de6dSgd78059 /* offset */ 36251c42de6dSgd78059 buf += snprintf(buf, bufend-buf, "+P%dd%02dh%02dm%02ds", 36261c42de6dSgd78059 (int)(bsctm/86400), (int)(bsctm/3600%24), 36271c42de6dSgd78059 (int)(bsctm/60%60), (int)(bsctm%60)); 36281c42de6dSgd78059 } else { 36291c42de6dSgd78059 /* absolute time */ 36301c42de6dSgd78059 mutex_enter(&tod_lock); 36311c42de6dSgd78059 buf += bscv_event_snprintgmttime(buf, bufend-buf, 36321c42de6dSgd78059 utc_to_tod(bsctm)); 36331c42de6dSgd78059 mutex_exit(&tod_lock); 36341c42de6dSgd78059 } 36351c42de6dSgd78059 buf += snprintf(buf, bufend-buf, " "); 36361c42de6dSgd78059 36371c42de6dSgd78059 /* subsysp */ 36381c42de6dSgd78059 if (subsystem < 36391c42de6dSgd78059 (sizeof (eventSubsysStrings)/sizeof (*eventSubsysStrings))) { 36401c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "%s", 36411c42de6dSgd78059 eventSubsysStrings[subsystem]); 36421c42de6dSgd78059 } else { 36431c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 36441c42de6dSgd78059 "unknown subsystem %d ", subsystem); 36451c42de6dSgd78059 } 36461c42de6dSgd78059 36471c42de6dSgd78059 /* resource */ 36481c42de6dSgd78059 switch (subsystem) { 36491c42de6dSgd78059 case EVENT_SUBSYS_ALARM: 36501c42de6dSgd78059 case EVENT_SUBSYS_TEMP: 36511c42de6dSgd78059 case EVENT_SUBSYS_OVERTEMP: 36521c42de6dSgd78059 case EVENT_SUBSYS_FAN: 36531c42de6dSgd78059 case EVENT_SUBSYS_SUPPLY: 36541c42de6dSgd78059 case EVENT_SUBSYS_BREAKER: 36551c42de6dSgd78059 case EVENT_SUBSYS_PSU: 36561c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "%d ", event->ev_resource); 36571c42de6dSgd78059 break; 36581c42de6dSgd78059 case EVENT_SUBSYS_LED: 36591c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "%s ", bscv_get_label( 36601c42de6dSgd78059 ssp->led_names, MAX_LED_ID, event->ev_resource - 1)); 36611c42de6dSgd78059 break; 36621c42de6dSgd78059 default: 36631c42de6dSgd78059 break; 36641c42de6dSgd78059 } 36651c42de6dSgd78059 36661c42de6dSgd78059 /* fatal */ 36671c42de6dSgd78059 if (event->ev_subsys & EVENT_MASK_FAULT) { 36681c42de6dSgd78059 if (event->ev_subsys & EVENT_MASK_FATAL) { 36691c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "FATAL FAULT: "); 36701c42de6dSgd78059 } else { 36711c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "FAULT: "); 36721c42de6dSgd78059 } 36731c42de6dSgd78059 } 36741c42de6dSgd78059 36751c42de6dSgd78059 /* eventp */ 36761c42de6dSgd78059 if (eventtype < 36771c42de6dSgd78059 (sizeof (eventTypeStrings)/sizeof (*eventTypeStrings))) { 36781c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "%s", 36791c42de6dSgd78059 eventTypeStrings[eventtype]); 36801c42de6dSgd78059 } else { 36811c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 36821c42de6dSgd78059 "unknown event 0x%02x%02x%02x%02x", 36831c42de6dSgd78059 event->ev_subsys, event->ev_event, 36841c42de6dSgd78059 event->ev_resource, event->ev_detail); 36851c42de6dSgd78059 } 36861c42de6dSgd78059 36871c42de6dSgd78059 /* detail */ 36881c42de6dSgd78059 switch (subsystem) { 36891c42de6dSgd78059 case EVENT_SUBSYS_TEMP: 36901c42de6dSgd78059 if ((eventtype != EVENT_RECOVERED) && 36911c42de6dSgd78059 eventtype != EVENT_DEVICE_INACCESSIBLE) { 36921c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - %d degC", 36931c42de6dSgd78059 (int8_t)event->ev_detail); 36941c42de6dSgd78059 } 36951c42de6dSgd78059 break; 36961c42de6dSgd78059 case EVENT_SUBSYS_FAN: 36971c42de6dSgd78059 if (eventtype == EVENT_FAILED) { 36981c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 36991c42de6dSgd78059 " %d%%", event->ev_detail); 37001c42de6dSgd78059 } 37011c42de6dSgd78059 break; 37021c42de6dSgd78059 case EVENT_SUBSYS_LOM: 37031c42de6dSgd78059 switch (eventtype) { 37041c42de6dSgd78059 case EVENT_FLASH_DOWNLOAD: 37051c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 37061c42de6dSgd78059 ": v%d.%d to v%d.%d", 37071c42de6dSgd78059 (event->ev_resource >> 4), 37081c42de6dSgd78059 (event->ev_resource & 0x0f), 37091c42de6dSgd78059 (event->ev_detail >> 4), 37101c42de6dSgd78059 (event->ev_detail & 0x0f)); 37111c42de6dSgd78059 break; 37121c42de6dSgd78059 case EVENT_WATCHDOG_TRIGGER: 37131c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 37141c42de6dSgd78059 event->ev_detail ? "- soft" : " - hard"); 37151c42de6dSgd78059 break; 37161c42de6dSgd78059 case EVENT_UNEXPECTED_RESET: 37171c42de6dSgd78059 if (event->ev_detail & 37181c42de6dSgd78059 LOM_UNEXPECTEDRESET_MASK_BADTRAP) { 37191c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 37201c42de6dSgd78059 " - unclaimed exception 0x%x", 37211c42de6dSgd78059 event->ev_detail & 37221c42de6dSgd78059 ~LOM_UNEXPECTEDRESET_MASK_BADTRAP); 37231c42de6dSgd78059 } 37241c42de6dSgd78059 break; 37251c42de6dSgd78059 case EVENT_RESET: 37261c42de6dSgd78059 switch (event->ev_detail) { 37271c42de6dSgd78059 case LOM_RESET_DETAIL_BYUSER: 37281c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " by user"); 37291c42de6dSgd78059 break; 37301c42de6dSgd78059 case LOM_RESET_DETAIL_REPROGRAMMING: 37311c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 37321c42de6dSgd78059 " after flash download"); 37331c42de6dSgd78059 break; 37341c42de6dSgd78059 default: 37351c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 37361c42de6dSgd78059 " - unknown reason"); 37371c42de6dSgd78059 break; 37381c42de6dSgd78059 } 37391c42de6dSgd78059 break; 37401c42de6dSgd78059 default: 37411c42de6dSgd78059 break; 37421c42de6dSgd78059 } 37431c42de6dSgd78059 break; 37441c42de6dSgd78059 case EVENT_SUBSYS_LED: 37451c42de6dSgd78059 switch (event->ev_detail) { 37461c42de6dSgd78059 case LOM_LED_STATE_OFF: 37471c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": OFF"); 37481c42de6dSgd78059 break; 37491c42de6dSgd78059 case LOM_LED_STATE_ON_STEADY: 37501c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": ON"); 37511c42de6dSgd78059 break; 37521c42de6dSgd78059 case LOM_LED_STATE_ON_FLASHING: 37531c42de6dSgd78059 case LOM_LED_STATE_ON_SLOWFLASH: 37541c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": BLINKING"); 37551c42de6dSgd78059 break; 37561c42de6dSgd78059 case LOM_LED_STATE_INACCESSIBLE: 37571c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": inaccessible"); 37581c42de6dSgd78059 break; 37591c42de6dSgd78059 case LOM_LED_STATE_STANDBY: 37601c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": standby"); 37611c42de6dSgd78059 break; 37621c42de6dSgd78059 case LOM_LED_STATE_NOT_PRESENT: 37631c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": not present"); 37641c42de6dSgd78059 break; 37651c42de6dSgd78059 default: 37661c42de6dSgd78059 buf += snprintf(buf, bufend - buf, ": 0x%x", 37671c42de6dSgd78059 event->ev_resource); 37681c42de6dSgd78059 break; 37691c42de6dSgd78059 } 37701c42de6dSgd78059 break; 37711c42de6dSgd78059 case EVENT_SUBSYS_USER: 37721c42de6dSgd78059 switch (eventtype) { 37731c42de6dSgd78059 case EVENT_USER_ADDED: 37741c42de6dSgd78059 case EVENT_USER_REMOVED: 37751c42de6dSgd78059 case EVENT_USER_PERMSCHANGED: 37761c42de6dSgd78059 case EVENT_USER_LOGIN: 37771c42de6dSgd78059 case EVENT_USER_PASSWORD_CHANGE: 37781c42de6dSgd78059 case EVENT_USER_LOGINFAIL: 37791c42de6dSgd78059 case EVENT_USER_LOGOUT: 37801c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " %d", 37811c42de6dSgd78059 event->ev_resource); 37821c42de6dSgd78059 default: 37831c42de6dSgd78059 break; 37841c42de6dSgd78059 } 37851c42de6dSgd78059 break; 37861c42de6dSgd78059 case EVENT_SUBSYS_PSU: 37871c42de6dSgd78059 if (event->ev_detail & LOM_PSU_NOACCESS) { 37881c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - inaccessible"); 37891c42de6dSgd78059 } else if ((event->ev_detail & LOM_PSU_STATUS_MASK) 37901c42de6dSgd78059 == LOM_PSU_STATUS_MASK) { 37911c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - OK"); 37921c42de6dSgd78059 } else { 37931c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " -"); 37941c42de6dSgd78059 /* 37951c42de6dSgd78059 * If both inputs are seen to have failed then simply 37961c42de6dSgd78059 * indicate that the PSU input has failed 37971c42de6dSgd78059 */ 37981c42de6dSgd78059 if (!(event->ev_detail & 37991c42de6dSgd78059 (LOM_PSU_INPUT_A_OK | LOM_PSU_INPUT_B_OK))) { 38001c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " Input"); 38011c42de6dSgd78059 } else { 38021c42de6dSgd78059 /* At least one input is ok */ 38031c42de6dSgd78059 if (!(event->ev_detail & LOM_PSU_INPUT_A_OK)) { 38041c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 38051c42de6dSgd78059 " InA"); 38061c42de6dSgd78059 } 38071c42de6dSgd78059 if (!(event->ev_detail & LOM_PSU_INPUT_B_OK)) { 38081c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 38091c42de6dSgd78059 " InB"); 38101c42de6dSgd78059 } 38111c42de6dSgd78059 /* 38121c42de6dSgd78059 * Only flag an output error if an input is 38131c42de6dSgd78059 * still present 38141c42de6dSgd78059 */ 38151c42de6dSgd78059 if (!(event->ev_detail & LOM_PSU_OUTPUT_OK)) { 38161c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 38171c42de6dSgd78059 " Output"); 38181c42de6dSgd78059 } 38191c42de6dSgd78059 } 38201c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " failed"); 38211c42de6dSgd78059 } 38221c42de6dSgd78059 break; 38231c42de6dSgd78059 case EVENT_SUBSYS_NONE: 38241c42de6dSgd78059 if (eventtype == EVENT_FAULT_LED) { 38251c42de6dSgd78059 switch (event->ev_detail) { 38261c42de6dSgd78059 case 0: 38271c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - ON"); 38281c42de6dSgd78059 break; 38291c42de6dSgd78059 case 255: 38301c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - OFF"); 38311c42de6dSgd78059 break; 38321c42de6dSgd78059 default: 38331c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 38341c42de6dSgd78059 " - %dHz", event->ev_detail); 38351c42de6dSgd78059 break; 38361c42de6dSgd78059 } 38371c42de6dSgd78059 } 38381c42de6dSgd78059 break; 38391c42de6dSgd78059 case EVENT_SUBSYS_HOST: 38401c42de6dSgd78059 if (eventtype == EVENT_BOOTMODE_CHANGE) { 38411c42de6dSgd78059 switch (event->ev_detail & 38421c42de6dSgd78059 ~EBUS_BOOTMODE_FORCE_CONSOLE) { 38431c42de6dSgd78059 case EBUS_BOOTMODE_FORCE_NOBOOT: 38441c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 38451c42de6dSgd78059 " - no boot"); 38461c42de6dSgd78059 break; 38471c42de6dSgd78059 case EBUS_BOOTMODE_RESET_DEFAULT: 38481c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 38491c42de6dSgd78059 " - reset defaults"); 38501c42de6dSgd78059 break; 38511c42de6dSgd78059 case EBUS_BOOTMODE_FULLDIAG: 38521c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 38531c42de6dSgd78059 " - full diag"); 38541c42de6dSgd78059 break; 38551c42de6dSgd78059 case EBUS_BOOTMODE_SKIPDIAG: 38561c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 38571c42de6dSgd78059 " - skip diag"); 38581c42de6dSgd78059 break; 38591c42de6dSgd78059 default: 38601c42de6dSgd78059 break; 38611c42de6dSgd78059 } 38621c42de6dSgd78059 } 38631c42de6dSgd78059 if (eventtype == EVENT_SCC_STATUS) { 38641c42de6dSgd78059 switch (event->ev_detail) { 38651c42de6dSgd78059 case 0: 38661c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 38671c42de6dSgd78059 " - inserted"); 38681c42de6dSgd78059 break; 38691c42de6dSgd78059 case 1: 38701c42de6dSgd78059 buf += snprintf(buf, bufend - buf, 38711c42de6dSgd78059 " - removed"); 38721c42de6dSgd78059 break; 38731c42de6dSgd78059 default: 38741c42de6dSgd78059 break; 38751c42de6dSgd78059 } 38761c42de6dSgd78059 } 38771c42de6dSgd78059 break; 38781c42de6dSgd78059 38791c42de6dSgd78059 default: 38801c42de6dSgd78059 break; 38811c42de6dSgd78059 } 38821c42de6dSgd78059 38831c42de6dSgd78059 /* shutd */ 38841c42de6dSgd78059 if (event->ev_subsys & EVENT_MASK_SHUTDOWN_REQD) { 38851c42de6dSgd78059 buf += snprintf(buf, bufend - buf, " - shutdown req'd"); 38861c42de6dSgd78059 } 38871c42de6dSgd78059 38881c42de6dSgd78059 buf += snprintf(buf, bufend - buf, "\n"); 38891c42de6dSgd78059 38901c42de6dSgd78059 if (buf >= bufend) { 38911c42de6dSgd78059 /* Ensure newline at end of string */ 38921c42de6dSgd78059 bufend[-2] = '\n'; 38931c42de6dSgd78059 bufend[-1] = '\0'; 38941c42de6dSgd78059 #ifdef DEBUG 38951c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_build_eventstring: buffer too small!"); 38961c42de6dSgd78059 #endif /* DEBUG */ 38971c42de6dSgd78059 } 38981c42de6dSgd78059 } 38991c42de6dSgd78059 39001c42de6dSgd78059 /* 39011c42de6dSgd78059 * function - bscv_level_of_event 39021c42de6dSgd78059 * description - This routine determines which level an event should be 39031c42de6dSgd78059 * reported at. 39041c42de6dSgd78059 * inputs - lom event structure pointer 39051c42de6dSgd78059 * outputs - event level. 39061c42de6dSgd78059 */ 39071c42de6dSgd78059 static int 39081c42de6dSgd78059 bscv_level_of_event(lom_event_t *event) 39091c42de6dSgd78059 { 39101c42de6dSgd78059 int level; 39111c42de6dSgd78059 /* 39121c42de6dSgd78059 * This is the same criteria that the firmware uses except we 39131c42de6dSgd78059 * log the fault led on as being EVENT_LEVEL_FAULT 39141c42de6dSgd78059 */ 39151c42de6dSgd78059 if (EVENT_DECODE_SUBSYS(event->ev_subsys) == EVENT_SUBSYS_USER) { 39161c42de6dSgd78059 level = EVENT_LEVEL_USER; 39171c42de6dSgd78059 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) == 39181c42de6dSgd78059 EVENT_SUBSYS_ALARM) && (event->ev_event == EVENT_STATE_ON)) { 39191c42de6dSgd78059 level = EVENT_LEVEL_FAULT; 39201c42de6dSgd78059 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) == 39211c42de6dSgd78059 EVENT_SUBSYS_NONE) && 39221c42de6dSgd78059 (event->ev_event == EVENT_FAULT_LED) && 39231c42de6dSgd78059 (event->ev_detail != 0xff)) { 39241c42de6dSgd78059 level = EVENT_LEVEL_FAULT; 39251c42de6dSgd78059 } else if ((EVENT_DECODE_SUBSYS(event->ev_subsys) == 39261c42de6dSgd78059 EVENT_SUBSYS_LOM) && event->ev_event == EVENT_TIME_REFERENCE) { 39271c42de6dSgd78059 level = EVENT_LEVEL_NOTICE; 39281c42de6dSgd78059 } else if (event->ev_event == EVENT_RECOVERED) { 39291c42de6dSgd78059 /* 39301c42de6dSgd78059 * All recovery messages need to be reported to the console 39311c42de6dSgd78059 * because during boot, the faults which occurred whilst 39321c42de6dSgd78059 * Solaris was not running are relayed to the console. There 39331c42de6dSgd78059 * is a case whereby a fatal fault (eg. over temp) could 39341c42de6dSgd78059 * have occurred and then recovered. The recovery condition 39351c42de6dSgd78059 * needs to be reported so the user doesn't think that the 39361c42de6dSgd78059 * failure (over temp) is still present. 39371c42de6dSgd78059 */ 39381c42de6dSgd78059 level = EVENT_LEVEL_FAULT; 39391c42de6dSgd78059 } else if (EVENT_DECODE_FAULT(event->ev_subsys) == 0) { 39401c42de6dSgd78059 /* None of FAULT, FATAL or SHUTDOWN REQD are set */ 39411c42de6dSgd78059 level = EVENT_LEVEL_NOTICE; 39421c42de6dSgd78059 } else if (EVENT_DECODE_FAULT(event->ev_subsys) == EVENT_MASK_FAULT) { 39431c42de6dSgd78059 /* Only FAULT set i.e not FATAL or SHUTDOWN REQD */ 39441c42de6dSgd78059 level = EVENT_LEVEL_FAULT; 39451c42de6dSgd78059 } else { 39461c42de6dSgd78059 level = EVENT_LEVEL_FATAL; 39471c42de6dSgd78059 } 39481c42de6dSgd78059 39491c42de6dSgd78059 return (level); 39501c42de6dSgd78059 } 39511c42de6dSgd78059 39521c42de6dSgd78059 /* 39531c42de6dSgd78059 * function - bscv_status 39541c42de6dSgd78059 * description - This routine is called when any change in the LOMlite2 status 39551c42de6dSgd78059 * is indicated by the status registers. 39561c42de6dSgd78059 * 39571c42de6dSgd78059 * inputs - LOM soft state structure pointer 39581c42de6dSgd78059 * 39591c42de6dSgd78059 * outputs - none. 39601c42de6dSgd78059 */ 39611c42de6dSgd78059 static void 39621c42de6dSgd78059 bscv_status(bscv_soft_state_t *ssp, uint8_t state_chng, uint8_t dev_no) 39631c42de6dSgd78059 { 39641c42de6dSgd78059 int8_t temp; 39651c42de6dSgd78059 uint8_t fanspeed; 39661c42de6dSgd78059 39671c42de6dSgd78059 ASSERT(bscv_held(ssp)); 39681c42de6dSgd78059 3969*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_status", "state_chng 0x%x dev_no 0x%x", 39701c42de6dSgd78059 state_chng, dev_no); 39711c42de6dSgd78059 39721c42de6dSgd78059 /* 39731c42de6dSgd78059 * The device that has changed is given by the state change 39741c42de6dSgd78059 * register and the event detail register so react 39751c42de6dSgd78059 * accordingly. 39761c42de6dSgd78059 */ 39771c42de6dSgd78059 39781c42de6dSgd78059 if (state_chng == EBUS_STATE_NOTIFY) { 39791c42de6dSgd78059 /* 39801c42de6dSgd78059 * The BSC is indicating a self state change 39811c42de6dSgd78059 */ 39821c42de6dSgd78059 if (dev_no == EBUS_DETAIL_FLASH) { 39831c42de6dSgd78059 ssp->cssp_prog = B_TRUE; 3984*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_status", 39851c42de6dSgd78059 "ssp->cssp_prog changed to 0x%x", 39861c42de6dSgd78059 ssp->cssp_prog); 39871c42de6dSgd78059 /* 39881c42de6dSgd78059 * It takes the BSC at least 100 ms to 39891c42de6dSgd78059 * clear down the comms protocol. 39901c42de6dSgd78059 * We back-off from talking to the 39911c42de6dSgd78059 * BSC during this period. 39921c42de6dSgd78059 */ 39931c42de6dSgd78059 delay(BSC_EVENT_POLL_NORMAL); 3994*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_status", 39951c42de6dSgd78059 "completed delay"); 39961c42de6dSgd78059 } else if (dev_no == EBUS_DETAIL_RESET) { 39971c42de6dSgd78059 /* 39981c42de6dSgd78059 * The bsc has reset 39991c42de6dSgd78059 */ 4000*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_status", 40011c42de6dSgd78059 "BSC reset occured, re-synching"); 40021c42de6dSgd78059 (void) bscv_attach_common(ssp); 4003*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'D', "bscv_status", 40041c42de6dSgd78059 "completed attach_common"); 40051c42de6dSgd78059 } 40061c42de6dSgd78059 40071c42de6dSgd78059 } 40081c42de6dSgd78059 40091c42de6dSgd78059 if ((state_chng & EBUS_STATE_FAN) && ((dev_no - 1) < MAX_FANS)) { 40101c42de6dSgd78059 fanspeed = bscv_get8(ssp, chan_general, 40111c42de6dSgd78059 EBUS_IDX_FAN1_SPEED + dev_no - 1); 40121c42de6dSgd78059 /* 40131c42de6dSgd78059 * Only remember fanspeeds which are real values or 40141c42de6dSgd78059 * NOT PRESENT values. 40151c42de6dSgd78059 */ 40161c42de6dSgd78059 if ((fanspeed <= LOM_FAN_MAX_SPEED) || 40171c42de6dSgd78059 (fanspeed == LOM_FAN_NOT_PRESENT)) { 40181c42de6dSgd78059 ssp->fanspeed[dev_no - 1] = fanspeed; 40191c42de6dSgd78059 } 40201c42de6dSgd78059 } 40211c42de6dSgd78059 40221c42de6dSgd78059 if ((state_chng & EBUS_STATE_PSU) && ((dev_no - 1) < MAX_PSUS)) { 40231c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, 40241c42de6dSgd78059 EBUS_IDX_PSU1_STAT + dev_no - 1); 40251c42de6dSgd78059 } 40261c42de6dSgd78059 40271c42de6dSgd78059 if (state_chng & EBUS_STATE_GP) { 40281c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_GPIP); 40291c42de6dSgd78059 } 40301c42de6dSgd78059 40311c42de6dSgd78059 if (state_chng & EBUS_STATE_CB) { 40321c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_CBREAK_STATUS); 40331c42de6dSgd78059 } 40341c42de6dSgd78059 40351c42de6dSgd78059 if ((state_chng & EBUS_STATE_TEMPERATURE) && 40361c42de6dSgd78059 ((dev_no - 1) < MAX_TEMPS)) { 40371c42de6dSgd78059 temp = bscv_get8(ssp, chan_general, 40381c42de6dSgd78059 EBUS_IDX_TEMP1 + dev_no - 1); 40391c42de6dSgd78059 /* 40401c42de6dSgd78059 * Only remember temperatures which are real values or 40411c42de6dSgd78059 * a NOT PRESENT value. 40421c42de6dSgd78059 */ 40431c42de6dSgd78059 if ((temp <= LOM_TEMP_MAX_VALUE) || 40441c42de6dSgd78059 (temp == LOM_TEMP_STATE_NOT_PRESENT)) { 40451c42de6dSgd78059 ssp->temps.temp[dev_no - 1] = temp; 40461c42de6dSgd78059 } 40471c42de6dSgd78059 } 40481c42de6dSgd78059 40491c42de6dSgd78059 if (state_chng & EBUS_STATE_RAIL) { 40501c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_SUPPLY_LO); 40511c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_SUPPLY_HI); 40521c42de6dSgd78059 } 40531c42de6dSgd78059 } 40541c42de6dSgd78059 40551c42de6dSgd78059 char * 40561c42de6dSgd78059 bscv_get_label(char labels[][MAX_LOM2_NAME_STR], int limit, int index) 40571c42de6dSgd78059 { 40581c42de6dSgd78059 40591c42de6dSgd78059 if (labels == NULL) 40601c42de6dSgd78059 return (""); 40611c42de6dSgd78059 40621c42de6dSgd78059 if (limit < 0 || index < 0 || index > limit) 40631c42de6dSgd78059 return ("-"); 40641c42de6dSgd78059 40651c42de6dSgd78059 return (labels[index]); 40661c42de6dSgd78059 } 40671c42de6dSgd78059 40681c42de6dSgd78059 static void 40691c42de6dSgd78059 bscv_generic_sysevent(bscv_soft_state_t *ssp, char *class, char *subclass, 40701c42de6dSgd78059 char *fru_id, char *res_id, int32_t fru_state, char *msg) 40711c42de6dSgd78059 { 40721c42de6dSgd78059 int rv; 40731c42de6dSgd78059 nvlist_t *attr_list; 40741c42de6dSgd78059 4075*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", "%s/%s:(%s,%s,%d) %s", 40761c42de6dSgd78059 class, subclass, fru_id, res_id, fru_state, msg); 40771c42de6dSgd78059 40781c42de6dSgd78059 40791c42de6dSgd78059 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_SLEEP)) { 4080*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", 40811c42de6dSgd78059 "nvlist alloc failure"); 40821c42de6dSgd78059 return; 40831c42de6dSgd78059 } 40841c42de6dSgd78059 if (nvlist_add_uint32(attr_list, ENV_VERSION, 1)) { 4085*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", 40861c42de6dSgd78059 "nvlist ENV_VERSION failure"); 40871c42de6dSgd78059 nvlist_free(attr_list); 40881c42de6dSgd78059 return; 40891c42de6dSgd78059 } 40901c42de6dSgd78059 if (nvlist_add_string(attr_list, ENV_FRU_ID, fru_id)) { 4091*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", 40921c42de6dSgd78059 "nvlist ENV_FRU_ID failure"); 40931c42de6dSgd78059 nvlist_free(attr_list); 40941c42de6dSgd78059 return; 40951c42de6dSgd78059 } 40961c42de6dSgd78059 if (nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, res_id)) { 4097*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", 40981c42de6dSgd78059 "nvlist ENV_FRU_RESOURCE_ID failure"); 40991c42de6dSgd78059 nvlist_free(attr_list); 41001c42de6dSgd78059 return; 41011c42de6dSgd78059 } 41021c42de6dSgd78059 if (nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR)) { 4103*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", 41041c42de6dSgd78059 "nvlist ENV_FRU_DEVICE failure"); 41051c42de6dSgd78059 nvlist_free(attr_list); 41061c42de6dSgd78059 return; 41071c42de6dSgd78059 } 41081c42de6dSgd78059 if (nvlist_add_int32(attr_list, ENV_FRU_STATE, fru_state)) { 4109*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", 41101c42de6dSgd78059 "nvlist ENV_FRU_STATE failure"); 41111c42de6dSgd78059 nvlist_free(attr_list); 41121c42de6dSgd78059 return; 41131c42de6dSgd78059 } 41141c42de6dSgd78059 if (nvlist_add_string(attr_list, ENV_MSG, msg)) { 4115*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", 41161c42de6dSgd78059 "nvlist ENV_MSG failure"); 41171c42de6dSgd78059 nvlist_free(attr_list); 41181c42de6dSgd78059 return; 41191c42de6dSgd78059 } 41201c42de6dSgd78059 41211c42de6dSgd78059 rv = ddi_log_sysevent(ssp->dip, DDI_VENDOR_SUNW, class, 41221c42de6dSgd78059 subclass, attr_list, NULL, DDI_SLEEP); 41231c42de6dSgd78059 41241c42de6dSgd78059 if (rv == DDI_SUCCESS) { 4125*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_generic_sysevent", "sent sysevent"); 41261c42de6dSgd78059 } else { 41271c42de6dSgd78059 cmn_err(CE_WARN, "!cannot deliver sysevent"); 41281c42de6dSgd78059 } 41291c42de6dSgd78059 41301c42de6dSgd78059 nvlist_free(attr_list); 41311c42de6dSgd78059 } 41321c42de6dSgd78059 41331c42de6dSgd78059 /* 41341c42de6dSgd78059 * function - bscv_sysevent 41351c42de6dSgd78059 * description - send out a sysevent on the given change if needed 41361c42de6dSgd78059 * inputs - soft state pointer, event to report 41371c42de6dSgd78059 * outputs - none 41381c42de6dSgd78059 */ 41391c42de6dSgd78059 41401c42de6dSgd78059 static void 41411c42de6dSgd78059 bscv_sysevent(bscv_soft_state_t *ssp, lom_event_t *event) 41421c42de6dSgd78059 { 41431c42de6dSgd78059 char *class = NULL; 41441c42de6dSgd78059 char *subclass = NULL; 41451c42de6dSgd78059 char *fru_id = "Blade"; /* The blade is only one FRU */ 41461c42de6dSgd78059 char *res_id; 41471c42de6dSgd78059 int32_t fru_state = 0; 41481c42de6dSgd78059 4149*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_sysevent", "processing event"); 41501c42de6dSgd78059 41511c42de6dSgd78059 ASSERT(event != NULL); 41521c42de6dSgd78059 41531c42de6dSgd78059 /* Map ev_subsys to sysevent class/sub-class */ 41541c42de6dSgd78059 41551c42de6dSgd78059 switch (EVENT_DECODE_SUBSYS(event->ev_subsys)) { 41561c42de6dSgd78059 case EVENT_SUBSYS_NONE: 41571c42de6dSgd78059 break; 41581c42de6dSgd78059 case EVENT_SUBSYS_ALARM: 41591c42de6dSgd78059 break; 41601c42de6dSgd78059 case EVENT_SUBSYS_TEMP: 41611c42de6dSgd78059 class = EC_ENV, subclass = ESC_ENV_TEMP; 41621c42de6dSgd78059 res_id = bscv_get_label(ssp->temps.name, ssp->temps.num, 41631c42de6dSgd78059 event->ev_resource - 1); 41641c42de6dSgd78059 switch (event->ev_event) { 41651c42de6dSgd78059 case EVENT_SEVERE_OVERHEAT: 41661c42de6dSgd78059 fru_state = ENV_FAILED; 41671c42de6dSgd78059 break; 41681c42de6dSgd78059 case EVENT_OVERHEAT: 41691c42de6dSgd78059 fru_state = ENV_WARNING; 41701c42de6dSgd78059 break; 41711c42de6dSgd78059 case EVENT_NO_OVERHEAT: 41721c42de6dSgd78059 fru_state = ENV_OK; 41731c42de6dSgd78059 break; 41741c42de6dSgd78059 default: 41751c42de6dSgd78059 return; 41761c42de6dSgd78059 } 41771c42de6dSgd78059 break; 41781c42de6dSgd78059 case EVENT_SUBSYS_OVERTEMP: 41791c42de6dSgd78059 break; 41801c42de6dSgd78059 case EVENT_SUBSYS_FAN: 41811c42de6dSgd78059 class = EC_ENV, subclass = ESC_ENV_FAN; 41821c42de6dSgd78059 res_id = bscv_get_label(ssp->fan_names, ssp->num_fans, 41831c42de6dSgd78059 event->ev_resource - 1); 41841c42de6dSgd78059 switch (event->ev_event) { 41851c42de6dSgd78059 case EVENT_FAILED: 41861c42de6dSgd78059 fru_state = ENV_FAILED; 41871c42de6dSgd78059 break; 41881c42de6dSgd78059 case EVENT_RECOVERED: 41891c42de6dSgd78059 fru_state = ENV_OK; 41901c42de6dSgd78059 break; 41911c42de6dSgd78059 default: 41921c42de6dSgd78059 return; 41931c42de6dSgd78059 } 41941c42de6dSgd78059 break; 41951c42de6dSgd78059 case EVENT_SUBSYS_SUPPLY: 41961c42de6dSgd78059 class = EC_ENV, subclass = ESC_ENV_POWER; 41971c42de6dSgd78059 res_id = bscv_get_label(ssp->sflags.name, ssp->sflags.num, 41981c42de6dSgd78059 event->ev_resource - 1); 41991c42de6dSgd78059 switch (event->ev_event) { 42001c42de6dSgd78059 case EVENT_FAILED: 42011c42de6dSgd78059 fru_state = ENV_FAILED; 42021c42de6dSgd78059 break; 42031c42de6dSgd78059 case EVENT_RECOVERED: 42041c42de6dSgd78059 fru_state = ENV_OK; 42051c42de6dSgd78059 break; 42061c42de6dSgd78059 default: 42071c42de6dSgd78059 return; 42081c42de6dSgd78059 } 42091c42de6dSgd78059 break; 42101c42de6dSgd78059 case EVENT_SUBSYS_BREAKER: 42111c42de6dSgd78059 break; 42121c42de6dSgd78059 case EVENT_SUBSYS_PSU: 42131c42de6dSgd78059 break; 42141c42de6dSgd78059 case EVENT_SUBSYS_USER: 42151c42de6dSgd78059 break; 42161c42de6dSgd78059 case EVENT_SUBSYS_PHONEHOME: 42171c42de6dSgd78059 break; 42181c42de6dSgd78059 case EVENT_SUBSYS_LOM: 42191c42de6dSgd78059 break; 42201c42de6dSgd78059 case EVENT_SUBSYS_HOST: 42211c42de6dSgd78059 break; 42221c42de6dSgd78059 case EVENT_SUBSYS_EVENTLOG: 42231c42de6dSgd78059 break; 42241c42de6dSgd78059 case EVENT_SUBSYS_EXTRA: 42251c42de6dSgd78059 break; 42261c42de6dSgd78059 case EVENT_SUBSYS_LED: 42271c42de6dSgd78059 if (event->ev_event != EVENT_FAULT_LED && 42281c42de6dSgd78059 event->ev_event != EVENT_STATE_CHANGE) 42291c42de6dSgd78059 return; 42301c42de6dSgd78059 /* 42311c42de6dSgd78059 * There are 3 LEDs : Power, Service, Ready-to-Remove on a 42321c42de6dSgd78059 * JBOS blade. We'll never report the Power since Solaris 42331c42de6dSgd78059 * won't be running when it is _switched_ ON. Ready-to-Remove 42341c42de6dSgd78059 * will only be lit when we're powered down which also means 42351c42de6dSgd78059 * Solaris won't be running. We don't want to report it 42361c42de6dSgd78059 * during system testing / Sun VTS exercising the LEDs. 42371c42de6dSgd78059 * 42381c42de6dSgd78059 * Therefore, we only report the Service Required LED. 42391c42de6dSgd78059 */ 42401c42de6dSgd78059 class = EC_ENV, subclass = ESC_ENV_LED; 42411c42de6dSgd78059 res_id = bscv_get_label(ssp->led_names, MAX_LED_ID, 42421c42de6dSgd78059 event->ev_resource - 1); 42431c42de6dSgd78059 42441c42de6dSgd78059 switch (event->ev_detail) { 42451c42de6dSgd78059 case LOM_LED_STATE_ON_STEADY: 42461c42de6dSgd78059 fru_state = ENV_LED_ON; 42471c42de6dSgd78059 break; 42481c42de6dSgd78059 case LOM_LED_STATE_ON_FLASHING: 42491c42de6dSgd78059 case LOM_LED_STATE_ON_SLOWFLASH: 42501c42de6dSgd78059 fru_state = ENV_LED_BLINKING; 42511c42de6dSgd78059 break; 42521c42de6dSgd78059 case LOM_LED_STATE_OFF: 42531c42de6dSgd78059 fru_state = ENV_LED_OFF; 42541c42de6dSgd78059 break; 42551c42de6dSgd78059 case LOM_LED_STATE_INACCESSIBLE: 42561c42de6dSgd78059 fru_state = ENV_LED_INACCESSIBLE; 42571c42de6dSgd78059 break; 42581c42de6dSgd78059 case LOM_LED_STATE_STANDBY: 42591c42de6dSgd78059 fru_state = ENV_LED_STANDBY; 42601c42de6dSgd78059 break; 42611c42de6dSgd78059 case LOM_LED_STATE_NOT_PRESENT: 42621c42de6dSgd78059 fru_state = ENV_LED_NOT_PRESENT; 42631c42de6dSgd78059 break; 42641c42de6dSgd78059 default: 42651c42de6dSgd78059 fru_state = ENV_LED_INACCESSIBLE; 42661c42de6dSgd78059 break; 42671c42de6dSgd78059 } 42681c42de6dSgd78059 break; 42691c42de6dSgd78059 default : 42701c42de6dSgd78059 break; 42711c42de6dSgd78059 } 42721c42de6dSgd78059 42731c42de6dSgd78059 if (class == NULL || subclass == NULL) { 4274*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'E', "bscv_sysevent", "class/subclass NULL"); 42751c42de6dSgd78059 return; 42761c42de6dSgd78059 } 42771c42de6dSgd78059 42781c42de6dSgd78059 bscv_generic_sysevent(ssp, class, subclass, fru_id, res_id, fru_state, 42791c42de6dSgd78059 ENV_RESERVED_ATTR); 42801c42de6dSgd78059 } 42811c42de6dSgd78059 42821c42de6dSgd78059 /* 42831c42de6dSgd78059 * ********************************************************************* 42841c42de6dSgd78059 * Firmware download (programming) 42851c42de6dSgd78059 * ********************************************************************* 42861c42de6dSgd78059 */ 42871c42de6dSgd78059 42881c42de6dSgd78059 /* 42891c42de6dSgd78059 * function - bscv_prog 42901c42de6dSgd78059 * description - LOMlite2 flash programming code. 42911c42de6dSgd78059 * 42921c42de6dSgd78059 * bscv_prog_image - download a complete image to the lom. 42931c42de6dSgd78059 * bscv_prog_receive_image - receive data to build up a 42941c42de6dSgd78059 * complete image. 42951c42de6dSgd78059 * bscv_prog_stop_lom - pause the event daemon and prepare 42961c42de6dSgd78059 * lom for firmware upgrade. 42971c42de6dSgd78059 * bscv_prog_start_lom - reinit the driver/lom after upgrade 42981c42de6dSgd78059 * and restart the event daemon 42991c42de6dSgd78059 * 43001c42de6dSgd78059 * inputs - soft state pointer, arg ptr, ioctl mode 43011c42de6dSgd78059 * outputs - status 43021c42de6dSgd78059 */ 43031c42de6dSgd78059 43041c42de6dSgd78059 static int 43051c42de6dSgd78059 bscv_prog(bscv_soft_state_t *ssp, intptr_t arg, int mode) 43061c42de6dSgd78059 { 43071c42de6dSgd78059 lom_prog_t *prog; 43081c42de6dSgd78059 int res = 0; 43091c42de6dSgd78059 43101c42de6dSgd78059 /* 43111c42de6dSgd78059 * We will get repeatedly called with bits of data first for 43121c42de6dSgd78059 * loader, then for main image. 43131c42de6dSgd78059 */ 43141c42de6dSgd78059 prog = (lom_prog_t *)kmem_alloc(sizeof (lom_prog_t), KM_SLEEP); 43151c42de6dSgd78059 43161c42de6dSgd78059 if (ddi_copyin((caddr_t)arg, (caddr_t)prog, sizeof (*prog), 43171c42de6dSgd78059 mode) < 0) { 43181c42de6dSgd78059 kmem_free((void *)prog, sizeof (*prog)); 43191c42de6dSgd78059 return (EFAULT); 43201c42de6dSgd78059 } 43211c42de6dSgd78059 4322*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_prog", 43231c42de6dSgd78059 "index 0x%x size 0x%x", prog->index, prog->size); 43241c42de6dSgd78059 43251c42de6dSgd78059 mutex_enter(&ssp->prog_mu); 43261c42de6dSgd78059 if (prog->size == 0) { 43271c42de6dSgd78059 if (prog->index == 2) { 43281c42de6dSgd78059 /* 43291c42de6dSgd78059 * This is the initial request for the chip type so we 43301c42de6dSgd78059 * know what we are programming. 43311c42de6dSgd78059 * The type will have been read in at init so just 43321c42de6dSgd78059 * return it in data[0]. 43331c42de6dSgd78059 */ 43341c42de6dSgd78059 prog->data[0] = bscv_get8_cached(ssp, 43351c42de6dSgd78059 EBUS_IDX_CPU_IDENT); 43361c42de6dSgd78059 43371c42de6dSgd78059 if (ddi_copyout((caddr_t)prog, (caddr_t)arg, 43381c42de6dSgd78059 sizeof (lom_prog_t), mode) < 0) { 43391c42de6dSgd78059 res = EFAULT; 43401c42de6dSgd78059 } 43411c42de6dSgd78059 } else if (prog->index == 0) { 43421c42de6dSgd78059 res = bscv_prog_stop_lom(ssp); 43431c42de6dSgd78059 } else if (prog->index == 1) { 43441c42de6dSgd78059 res = bscv_prog_start_lom(ssp); 43451c42de6dSgd78059 } else { 43461c42de6dSgd78059 res = EINVAL; 43471c42de6dSgd78059 } 43481c42de6dSgd78059 } else { 43491c42de6dSgd78059 if (ssp->image == NULL) { 43501c42de6dSgd78059 ssp->image = (uint8_t *)kmem_zalloc( 43511c42de6dSgd78059 BSC_IMAGE_MAX_SIZE, KM_SLEEP); 43521c42de6dSgd78059 } 43531c42de6dSgd78059 res = bscv_prog_receive_image(ssp, prog, 43541c42de6dSgd78059 ssp->image, BSC_IMAGE_MAX_SIZE); 43551c42de6dSgd78059 } 43561c42de6dSgd78059 mutex_exit(&ssp->prog_mu); 43571c42de6dSgd78059 kmem_free((void *)prog, sizeof (lom_prog_t)); 43581c42de6dSgd78059 43591c42de6dSgd78059 return (res); 43601c42de6dSgd78059 } 43611c42de6dSgd78059 43621c42de6dSgd78059 static int 43631c42de6dSgd78059 bscv_check_loader_config(bscv_soft_state_t *ssp, boolean_t is_image2) 43641c42de6dSgd78059 { 4365*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_check_loader_config", 43661c42de6dSgd78059 "loader_running %d, is_image2 %d", 43671c42de6dSgd78059 ssp->loader_running, is_image2); 43681c42de6dSgd78059 43691c42de6dSgd78059 /* 43701c42de6dSgd78059 * loader_running TRUE means that we have told the microcontroller to 43711c42de6dSgd78059 * JUMP into the loader code which has been downloaded into its RAM. 43721c42de6dSgd78059 * At this point its an error to try and download another loader. We 43731c42de6dSgd78059 * should be downloading the actual image at this point. 43741c42de6dSgd78059 * Conversely, it is an error to download an image when the loader is 43751c42de6dSgd78059 * not already downloaded and the microcontroller hasn't JUMPed into it. 43761c42de6dSgd78059 * is_image2 TRUE means the image is being downloaded. 43771c42de6dSgd78059 * is_image2 FALSE means the loader is being downloaded. 43781c42de6dSgd78059 */ 43791c42de6dSgd78059 if (ssp->loader_running && !is_image2) { 43801c42de6dSgd78059 cmn_err(CE_WARN, "Attempt to download loader image " 43811c42de6dSgd78059 "with loader image already active"); 43821c42de6dSgd78059 cmn_err(CE_CONT, "This maybe an attempt to restart a " 43831c42de6dSgd78059 "failed firmware download - ignoring download attempt"); 43841c42de6dSgd78059 return (B_FALSE); 43851c42de6dSgd78059 } else if (!ssp->loader_running && is_image2) { 43861c42de6dSgd78059 cmn_err(CE_WARN, "Attempt to download firmware image " 43871c42de6dSgd78059 "without loader image active"); 43881c42de6dSgd78059 return (B_FALSE); 43891c42de6dSgd78059 43901c42de6dSgd78059 } 43911c42de6dSgd78059 43921c42de6dSgd78059 return (B_TRUE); 43931c42de6dSgd78059 } 43941c42de6dSgd78059 43951c42de6dSgd78059 static uint32_t 43961c42de6dSgd78059 bscv_get_pagesize(bscv_soft_state_t *ssp) 43971c42de6dSgd78059 { 43981c42de6dSgd78059 uint32_t pagesize; 43991c42de6dSgd78059 44001c42de6dSgd78059 ASSERT(bscv_held(ssp)); 44011c42de6dSgd78059 44021c42de6dSgd78059 pagesize = bscv_get32(ssp, chan_prog, 44031c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PAGE0)); 44041c42de6dSgd78059 4405*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_get_pagesize", "pagesize 0x%x", pagesize); 44061c42de6dSgd78059 44071c42de6dSgd78059 return (pagesize); 44081c42de6dSgd78059 } 44091c42de6dSgd78059 44101c42de6dSgd78059 /* 44111c42de6dSgd78059 * Sets the pagesize, returning the old value. 44121c42de6dSgd78059 */ 44131c42de6dSgd78059 static uint32_t 44141c42de6dSgd78059 bscv_set_pagesize(bscv_soft_state_t *ssp, uint32_t pagesize) 44151c42de6dSgd78059 { 44161c42de6dSgd78059 uint32_t old_pagesize; 44171c42de6dSgd78059 44181c42de6dSgd78059 ASSERT(bscv_held(ssp)); 44191c42de6dSgd78059 44201c42de6dSgd78059 old_pagesize = bscv_get_pagesize(ssp); 44211c42de6dSgd78059 44221c42de6dSgd78059 /* 44231c42de6dSgd78059 * The microcontroller remembers this value until until someone 44241c42de6dSgd78059 * changes it. 44251c42de6dSgd78059 */ 44261c42de6dSgd78059 bscv_put32(ssp, chan_prog, 44271c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PSIZ0), pagesize); 44281c42de6dSgd78059 44291c42de6dSgd78059 return (old_pagesize); 44301c42de6dSgd78059 } 44311c42de6dSgd78059 44321c42de6dSgd78059 static uint8_t 44331c42de6dSgd78059 bscv_enter_programming_mode(bscv_soft_state_t *ssp) 44341c42de6dSgd78059 { 44351c42de6dSgd78059 uint8_t retval; 44361c42de6dSgd78059 44371c42de6dSgd78059 ASSERT(bscv_held(ssp)); 44381c42de6dSgd78059 44391c42de6dSgd78059 bscv_put8(ssp, chan_prog, 44401c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), 44411c42de6dSgd78059 EBUS_PROGRAM_PCR_PRGMODE_ON); 44421c42de6dSgd78059 44431c42de6dSgd78059 retval = bscv_get8(ssp, chan_prog, BSCVA(EBUS_CMD_SPACE_PROGRAM, 44441c42de6dSgd78059 EBUS_PROGRAM_PCSR)); 44451c42de6dSgd78059 44461c42de6dSgd78059 return (retval); 44471c42de6dSgd78059 } 44481c42de6dSgd78059 44491c42de6dSgd78059 static void 44501c42de6dSgd78059 bscv_leave_programming_mode(bscv_soft_state_t *ssp, boolean_t with_jmp) 44511c42de6dSgd78059 { 44521c42de6dSgd78059 uint8_t reg; 44531c42de6dSgd78059 ASSERT(bscv_held(ssp)); 44541c42de6dSgd78059 44551c42de6dSgd78059 if (with_jmp) { 44561c42de6dSgd78059 reg = EBUS_PROGRAM_PCR_PROGOFF_JUMPTOADDR; 4457*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_leave_programming_mode", 44581c42de6dSgd78059 "jumptoaddr"); 44591c42de6dSgd78059 } else { 44601c42de6dSgd78059 reg = EBUS_PROGRAM_PCR_PRGMODE_OFF; 4461*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_leave_programming_mode", 44621c42de6dSgd78059 "prgmode_off"); 44631c42de6dSgd78059 } 44641c42de6dSgd78059 44651c42de6dSgd78059 bscv_put8(ssp, chan_prog, 44661c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), reg); 44671c42de6dSgd78059 } 44681c42de6dSgd78059 44691c42de6dSgd78059 44701c42de6dSgd78059 static void 44711c42de6dSgd78059 bscv_set_jump_to_addr(bscv_soft_state_t *ssp, uint32_t loadaddr) 44721c42de6dSgd78059 { 44731c42de6dSgd78059 ASSERT(bscv_held(ssp)); 44741c42de6dSgd78059 44751c42de6dSgd78059 bscv_put32(ssp, chan_prog, 44761c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0), loadaddr); 44771c42de6dSgd78059 4478*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_set_jump_to_addr", 44791c42de6dSgd78059 "set jump to loadaddr 0x%x", loadaddr); 44801c42de6dSgd78059 } 44811c42de6dSgd78059 44821c42de6dSgd78059 static uint8_t 44831c42de6dSgd78059 bscv_erase_once(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size) 44841c42de6dSgd78059 { 44851c42de6dSgd78059 uint8_t retval; 44861c42de6dSgd78059 44871c42de6dSgd78059 ASSERT(bscv_held(ssp)); 44881c42de6dSgd78059 44891c42de6dSgd78059 /* 44901c42de6dSgd78059 * write PADR, PSIZ to define area to be erased 44911c42de6dSgd78059 * We do not send erase for zero size because the current 44921c42de6dSgd78059 * downloader gets this wrong 44931c42de6dSgd78059 */ 44941c42de6dSgd78059 44951c42de6dSgd78059 /* 44961c42de6dSgd78059 * start at 0 44971c42de6dSgd78059 */ 4498*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_erase_once", "sending erase command"); 44991c42de6dSgd78059 45001c42de6dSgd78059 bscv_put32(ssp, chan_prog, 45011c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0), 45021c42de6dSgd78059 loadaddr); 45031c42de6dSgd78059 45041c42de6dSgd78059 /* set PSIZ to full size of image to be programmed */ 45051c42de6dSgd78059 bscv_put32(ssp, chan_prog, 45061c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PSIZ0), 45071c42de6dSgd78059 image_size); 45081c42de6dSgd78059 45091c42de6dSgd78059 /* write ERASE to PCSR */ 45101c42de6dSgd78059 bscv_put8(ssp, chan_prog, 45111c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), 45121c42de6dSgd78059 EBUS_PROGRAM_PCR_ERASE); 45131c42de6dSgd78059 45141c42de6dSgd78059 /* read PCSR to check status */ 45151c42de6dSgd78059 retval = bscv_get8(ssp, chan_prog, 45161c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR)); 45171c42de6dSgd78059 return (retval); 45181c42de6dSgd78059 } 45191c42de6dSgd78059 45201c42de6dSgd78059 static uint8_t 45211c42de6dSgd78059 bscv_do_erase(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size, 45221c42de6dSgd78059 boolean_t is_image2) 45231c42de6dSgd78059 { 45241c42de6dSgd78059 int retryable = BSC_ERASE_RETRY_LIMIT; 45251c42de6dSgd78059 uint8_t retval; 45261c42de6dSgd78059 45271c42de6dSgd78059 while (retryable--) { 45281c42de6dSgd78059 retval = bscv_erase_once(ssp, loadaddr, image_size); 45291c42de6dSgd78059 if (PSR_SUCCESS(retval)) 45301c42de6dSgd78059 break; 45311c42de6dSgd78059 else 45321c42de6dSgd78059 cmn_err(CE_WARN, "erase error 0x%x, attempt %d" 45331c42de6dSgd78059 ", base 0x%x, size 0x%x, %s image", 45341c42de6dSgd78059 retval, BSC_ERASE_RETRY_LIMIT - retryable, 45351c42de6dSgd78059 loadaddr, image_size, 45361c42de6dSgd78059 is_image2 ? "main" : "loader"); 45371c42de6dSgd78059 } 45381c42de6dSgd78059 45391c42de6dSgd78059 return (retval); 45401c42de6dSgd78059 } 45411c42de6dSgd78059 45421c42de6dSgd78059 static uint8_t 45431c42de6dSgd78059 bscv_set_page(bscv_soft_state_t *ssp, uint32_t addr) 45441c42de6dSgd78059 { 45451c42de6dSgd78059 uint32_t retval; 45461c42de6dSgd78059 int retryable = BSC_PAGE_RETRY_LIMIT; 45471c42de6dSgd78059 45481c42de6dSgd78059 ASSERT(bscv_held(ssp)); 45491c42de6dSgd78059 45501c42de6dSgd78059 while (retryable--) { 45511c42de6dSgd78059 45521c42de6dSgd78059 /* 45531c42de6dSgd78059 * Write the page address and read it back for confirmation. 45541c42de6dSgd78059 */ 45551c42de6dSgd78059 bscv_put32(ssp, chan_prog, 45561c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0), 45571c42de6dSgd78059 addr); 45581c42de6dSgd78059 retval = bscv_get32(ssp, chan_prog, 45591c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PADR0)); 45601c42de6dSgd78059 45611c42de6dSgd78059 if (retval == addr) 45621c42de6dSgd78059 break; 45631c42de6dSgd78059 else { 45641c42de6dSgd78059 cmn_err(CE_WARN, "programmming error, attempt %d, " 45651c42de6dSgd78059 "set page 0x%x, read back 0x%x", 45661c42de6dSgd78059 BSC_PAGE_RETRY_LIMIT - retryable, 45671c42de6dSgd78059 addr, retval); 45681c42de6dSgd78059 } 45691c42de6dSgd78059 } 45701c42de6dSgd78059 return ((addr == retval) ? EBUS_PROGRAM_PSR_SUCCESS : 45711c42de6dSgd78059 EBUS_PROGRAM_PSR_INVALID_OPERATION); 45721c42de6dSgd78059 } 45731c42de6dSgd78059 45741c42de6dSgd78059 static uint8_t 45751c42de6dSgd78059 bscv_do_page_data_once(bscv_soft_state_t *ssp, uint32_t index, 45761c42de6dSgd78059 uint32_t image_size, uint32_t pagesize, uint8_t *imagep, 45771c42de6dSgd78059 uint16_t *calcd_chksum) 45781c42de6dSgd78059 { 45791c42de6dSgd78059 uint32_t size; 45801c42de6dSgd78059 uint16_t chksum; 45811c42de6dSgd78059 int i; 45821c42de6dSgd78059 uint8_t retval; 45831c42de6dSgd78059 45841c42de6dSgd78059 ASSERT(bscv_held(ssp)); 45851c42de6dSgd78059 4586*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'P', "bscv_do_page_data_once", "index 0x%x", index); 45871c42de6dSgd78059 45881c42de6dSgd78059 /* write PSIZ bytes to PDAT */ 45891c42de6dSgd78059 if (index + pagesize < image_size) { 45901c42de6dSgd78059 bscv_rep_rw8(ssp, chan_prog, imagep + index, 45911c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_DATA), 45921c42de6dSgd78059 pagesize, DDI_DEV_NO_AUTOINCR, B_TRUE /* write */); 45931c42de6dSgd78059 size = pagesize; 45941c42de6dSgd78059 } else { 4595*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'P', "bscv_do_page_once", 45961c42de6dSgd78059 "Sending last block, last 0x%x bytes", 45971c42de6dSgd78059 (image_size % pagesize)); 45981c42de6dSgd78059 size = (image_size - index); 45991c42de6dSgd78059 bscv_rep_rw8(ssp, chan_prog, imagep + index, 46001c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_DATA), 46011c42de6dSgd78059 size, DDI_DEV_NO_AUTOINCR, B_TRUE /* write */); 46021c42de6dSgd78059 /* Now pad the rest of the page with zeros */ 46031c42de6dSgd78059 for (i = size; i < pagesize; i++) { 46041c42de6dSgd78059 bscv_put8(ssp, chan_prog, 46051c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, 46061c42de6dSgd78059 EBUS_PROGRAM_DATA), 46071c42de6dSgd78059 0); 46081c42de6dSgd78059 } 46091c42de6dSgd78059 } 46101c42de6dSgd78059 46111c42de6dSgd78059 /* write the checksum to PCSM */ 46121c42de6dSgd78059 chksum = 0; 46131c42de6dSgd78059 for (i = 0; i < size; i++) { 46141c42de6dSgd78059 chksum = ((chksum << 3) | (chksum >> 13)) ^ 46151c42de6dSgd78059 *(imagep + index + i); 46161c42de6dSgd78059 } 46171c42de6dSgd78059 /* Cope with non-pagesize sized bufers */ 46181c42de6dSgd78059 for (; i < pagesize; i++) { 46191c42de6dSgd78059 chksum = ((chksum << 3) | (chksum >> 13)) ^ 0; 46201c42de6dSgd78059 } 46211c42de6dSgd78059 bscv_put16(ssp, chan_prog, 46221c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSM0), chksum); 46231c42de6dSgd78059 46241c42de6dSgd78059 bscv_put8(ssp, chan_prog, 46251c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), 46261c42de6dSgd78059 EBUS_PROGRAM_PCR_PROGRAM); 46271c42de6dSgd78059 46281c42de6dSgd78059 retval = bscv_get8(ssp, chan_prog, 46291c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR)); 46301c42de6dSgd78059 46311c42de6dSgd78059 *calcd_chksum = chksum; 46321c42de6dSgd78059 return (retval); 46331c42de6dSgd78059 } 46341c42de6dSgd78059 46351c42de6dSgd78059 static uint8_t bscv_do_page(bscv_soft_state_t *ssp, uint32_t loadaddr, 46361c42de6dSgd78059 uint32_t index, uint32_t image_size, uint32_t pagesize, uint8_t *imagep, 46371c42de6dSgd78059 boolean_t is_image2) 46381c42de6dSgd78059 { 46391c42de6dSgd78059 int retryable = BSC_PAGE_RETRY_LIMIT; 46401c42de6dSgd78059 uint8_t retval; 46411c42de6dSgd78059 uint16_t checksum; 46421c42de6dSgd78059 4643*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'P', "bscv_do_page", "index 0x%x", index); 46441c42de6dSgd78059 46451c42de6dSgd78059 while (retryable--) { 46461c42de6dSgd78059 /* 46471c42de6dSgd78059 * Set the page address (with retries). If this is not 46481c42de6dSgd78059 * successful, then there is no point carrying on and sending 46491c42de6dSgd78059 * the page's data since that could cause random memory 46501c42de6dSgd78059 * corruption in the microcontroller. 46511c42de6dSgd78059 */ 46521c42de6dSgd78059 retval = bscv_set_page(ssp, loadaddr + index); 46531c42de6dSgd78059 if (!PSR_SUCCESS(retval)) { 46541c42de6dSgd78059 cmn_err(CE_WARN, "programming error 0x%x, " 46551c42de6dSgd78059 "could not setup page address 0x%x, %s image", 46561c42de6dSgd78059 retval, loadaddr + index, 46571c42de6dSgd78059 is_image2 ? "main" : "loader"); 46581c42de6dSgd78059 break; 46591c42de6dSgd78059 } 46601c42de6dSgd78059 46611c42de6dSgd78059 /* 46621c42de6dSgd78059 * Send down the data for the page 46631c42de6dSgd78059 */ 46641c42de6dSgd78059 4665*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'P', "bscv_do_page", "sending data for page"); 46661c42de6dSgd78059 46671c42de6dSgd78059 retval = bscv_do_page_data_once(ssp, index, image_size, 46681c42de6dSgd78059 pagesize, imagep, &checksum); 46691c42de6dSgd78059 if (PSR_SUCCESS(retval)) 46701c42de6dSgd78059 break; 46711c42de6dSgd78059 else 46721c42de6dSgd78059 cmn_err(CE_WARN, "programming error 0x%x," 46731c42de6dSgd78059 " attempt %d, index 0x%x, checksum 0x%x, %s image", 46741c42de6dSgd78059 retval, BSC_PAGE_RETRY_LIMIT - retryable, 46751c42de6dSgd78059 index, checksum, is_image2 ? "main" : "loader"); 46761c42de6dSgd78059 } 46771c42de6dSgd78059 4678*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_do_page", "Returning 0x%x for index 0x%x," 46791c42de6dSgd78059 " checksum 0x%x, %s image", retval, index, checksum, 46801c42de6dSgd78059 is_image2 ? "main" : "loader"); 46811c42de6dSgd78059 46821c42de6dSgd78059 return (retval); 46831c42de6dSgd78059 } 46841c42de6dSgd78059 46851c42de6dSgd78059 static uint8_t 46861c42de6dSgd78059 bscv_do_pages(bscv_soft_state_t *ssp, uint32_t loadaddr, uint32_t image_size, 46871c42de6dSgd78059 uint32_t pagesize, uint8_t *imagep, boolean_t is_image2) 46881c42de6dSgd78059 { 46891c42de6dSgd78059 uint8_t retval; 46901c42de6dSgd78059 uint32_t index; 46911c42de6dSgd78059 4692*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'P', "bscv_do_pages", "entered"); 46931c42de6dSgd78059 46941c42de6dSgd78059 for (index = 0; index < image_size; index += pagesize) { 46951c42de6dSgd78059 retval = bscv_do_page(ssp, loadaddr, index, image_size, 46961c42de6dSgd78059 pagesize, imagep, is_image2); 46971c42de6dSgd78059 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) { 4698*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_do_pages", 46991c42de6dSgd78059 "Failed to program lom (status 0x%x)", retval); 47001c42de6dSgd78059 break; 47011c42de6dSgd78059 } 47021c42de6dSgd78059 } 47031c42de6dSgd78059 47041c42de6dSgd78059 return (retval); 47051c42de6dSgd78059 } 47061c42de6dSgd78059 47071c42de6dSgd78059 static int 47081c42de6dSgd78059 bscv_prog_image(bscv_soft_state_t *ssp, boolean_t is_image2, 47091c42de6dSgd78059 uint8_t *imagep, int image_size, uint32_t loadaddr) 47101c42de6dSgd78059 { 47111c42de6dSgd78059 uint32_t pagesize; 47121c42de6dSgd78059 int res = 0; 47131c42de6dSgd78059 uint8_t retval; 47141c42de6dSgd78059 4715*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_prog_image", 47161c42de6dSgd78059 "image 0x%x, imagep %p, size 0x%x", 47171c42de6dSgd78059 is_image2 ? 2 : 1, imagep, image_size); 47181c42de6dSgd78059 47191c42de6dSgd78059 if (!bscv_check_loader_config(ssp, is_image2)) 47201c42de6dSgd78059 /* 47211c42de6dSgd78059 * Return no error to allow userland to continue on with 47221c42de6dSgd78059 * downloading the image. 47231c42de6dSgd78059 */ 47241c42de6dSgd78059 return (0); 47251c42de6dSgd78059 47261c42de6dSgd78059 bscv_enter(ssp); 47271c42de6dSgd78059 47281c42de6dSgd78059 pagesize = bscv_get_pagesize(ssp); 47291c42de6dSgd78059 47301c42de6dSgd78059 retval = bscv_enter_programming_mode(ssp); 47311c42de6dSgd78059 if (bscv_faulty(ssp) || !PSR_PROG(retval)) { 47321c42de6dSgd78059 cmn_err(CE_WARN, "lom: Failed to enter program mode, error 0x%x" 47331c42de6dSgd78059 ", %s image", retval, is_image2 ? "main" : "loader"); 47341c42de6dSgd78059 res = EIO; 47351c42de6dSgd78059 goto BSCV_PROG_IMAGE_END; 47361c42de6dSgd78059 } 4737*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_prog_image", "entered programming mode"); 47381c42de6dSgd78059 47391c42de6dSgd78059 /* 47401c42de6dSgd78059 * Only issue an erase if we are downloading the image. The loader 47411c42de6dSgd78059 * does not need this step. 47421c42de6dSgd78059 */ 47431c42de6dSgd78059 if (is_image2 && (image_size != 0)) { 47441c42de6dSgd78059 retval = bscv_do_erase(ssp, loadaddr, image_size, is_image2); 47451c42de6dSgd78059 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) { 47461c42de6dSgd78059 cmn_err(CE_WARN, 47471c42de6dSgd78059 "lom: Erase failed during programming, status 0x%x", 47481c42de6dSgd78059 retval); 47491c42de6dSgd78059 res = EIO; 47501c42de6dSgd78059 goto BSCV_PROG_IMAGE_END; 47511c42de6dSgd78059 } else { 4752*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_prog_image", 47531c42de6dSgd78059 "erase complete - programming..."); 47541c42de6dSgd78059 47551c42de6dSgd78059 } 47561c42de6dSgd78059 } 47571c42de6dSgd78059 47581c42de6dSgd78059 (void) bscv_set_pagesize(ssp, pagesize); 47591c42de6dSgd78059 47601c42de6dSgd78059 retval = bscv_do_pages(ssp, loadaddr, image_size, pagesize, imagep, 47611c42de6dSgd78059 is_image2); 47621c42de6dSgd78059 if (bscv_faulty(ssp) || !PSR_SUCCESS(retval)) { 4763*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_prog_image", 47641c42de6dSgd78059 "Failed to program lom (status 0x%x)", retval); 47651c42de6dSgd78059 res = EIO; 47661c42de6dSgd78059 goto BSCV_PROG_IMAGE_END; 47671c42de6dSgd78059 } 47681c42de6dSgd78059 47691c42de6dSgd78059 BSCV_PROG_IMAGE_END: 47701c42de6dSgd78059 if (res == 0 && !is_image2) { 47711c42de6dSgd78059 /* 47721c42de6dSgd78059 * We've downloaded the loader successfully. Now make the 47731c42de6dSgd78059 * microcontroller jump to it. 47741c42de6dSgd78059 */ 47751c42de6dSgd78059 bscv_set_jump_to_addr(ssp, loadaddr); 47761c42de6dSgd78059 ssp->loader_running = B_TRUE; 47771c42de6dSgd78059 bscv_leave_programming_mode(ssp, B_TRUE); 47781c42de6dSgd78059 } else { 47791c42de6dSgd78059 /* 47801c42de6dSgd78059 * We've just downloaded either the loader which failed, or 47811c42de6dSgd78059 * the image (which may or may not have been successful). 47821c42de6dSgd78059 */ 47831c42de6dSgd78059 bscv_set_jump_to_addr(ssp, 0); 47841c42de6dSgd78059 47851c42de6dSgd78059 if (res != 0) { 4786*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_prog_image", 47871c42de6dSgd78059 "got error 0x%x - leaving programming mode", 47881c42de6dSgd78059 res); 47891c42de6dSgd78059 cmn_err(CE_WARN, "programming error 0x%x, %s image", 47901c42de6dSgd78059 res, is_image2 ? "main" : "loader"); 47911c42de6dSgd78059 } else { 4792*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_prog_image", 47931c42de6dSgd78059 "programming complete - leaving programming mode"); 47941c42de6dSgd78059 } 47951c42de6dSgd78059 47961c42de6dSgd78059 bscv_leave_programming_mode(ssp, B_FALSE); 47971c42de6dSgd78059 ssp->loader_running = B_FALSE; 47981c42de6dSgd78059 } 47991c42de6dSgd78059 48001c42de6dSgd78059 bscv_exit(ssp); 48011c42de6dSgd78059 48021c42de6dSgd78059 return (res); 48031c42de6dSgd78059 } 48041c42de6dSgd78059 48051c42de6dSgd78059 48061c42de6dSgd78059 static int 48071c42de6dSgd78059 bscv_prog_receive_image(bscv_soft_state_t *ssp, lom_prog_t *prog, 48081c42de6dSgd78059 uint8_t *imagep, int max_size) 48091c42de6dSgd78059 { 48101c42de6dSgd78059 int res = 0; 48111c42de6dSgd78059 uint_t size; 48121c42de6dSgd78059 int32_t loadaddr; 48131c42de6dSgd78059 lom_prog_data_t *prog_data; 48141c42de6dSgd78059 48151c42de6dSgd78059 if ((prog->index & 0x7FFF) != ssp->prog_index) { 4816*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'U', "bscv_prog_receive_image", 48171c42de6dSgd78059 "Got wrong buffer 0x%x, expected 0x%x", 48181c42de6dSgd78059 prog->index & 0x7fff, ssp->prog_index); 48191c42de6dSgd78059 return (EINVAL); 48201c42de6dSgd78059 } 48211c42de6dSgd78059 48221c42de6dSgd78059 /* 48231c42de6dSgd78059 * We want to get the whole image and then do the download. 48241c42de6dSgd78059 * It is assumed the device is now in programming mode. 48251c42de6dSgd78059 */ 48261c42de6dSgd78059 48271c42de6dSgd78059 if ((prog->index & 0x7fff) == 0) { 48281c42de6dSgd78059 /* Starting a new image */ 48291c42de6dSgd78059 ssp->image_ptr = 0; 48301c42de6dSgd78059 } 48311c42de6dSgd78059 48321c42de6dSgd78059 if ((ssp->image_ptr + prog->size) > max_size) { 48331c42de6dSgd78059 cmn_err(CE_WARN, 48341c42de6dSgd78059 "lom image exceeded maximum size: got 0x%x, maximum 0x%x", 48351c42de6dSgd78059 (ssp->image_ptr + prog->size), max_size); 48361c42de6dSgd78059 return (EFAULT); 48371c42de6dSgd78059 } 48381c42de6dSgd78059 bcopy(prog->data, &imagep[ssp->image_ptr], prog->size); 48391c42de6dSgd78059 ssp->image_ptr += prog->size; 48401c42de6dSgd78059 48411c42de6dSgd78059 ssp->prog_index++; 48421c42de6dSgd78059 48431c42de6dSgd78059 if (prog->index & 0x8000) { 48441c42de6dSgd78059 /* 48451c42de6dSgd78059 * OK we have the whole image so synch up and start download. 48461c42de6dSgd78059 */ 48471c42de6dSgd78059 prog_data = (lom_prog_data_t *)imagep; 48481c42de6dSgd78059 if (prog_data->header.magic != PROG_MAGIC) { 48491c42de6dSgd78059 /* Old style programming data */ 48501c42de6dSgd78059 /* Take care image may not fill all of structure */ 48511c42de6dSgd78059 48521c42de6dSgd78059 /* sign extend loadaddr from 16 to 32 bits */ 48531c42de6dSgd78059 loadaddr = (int16_t)((uint16_t)((imagep[2] << 8) + 48541c42de6dSgd78059 imagep[3])); 48551c42de6dSgd78059 48561c42de6dSgd78059 size = (imagep[0] << 8) + imagep[1]; 48571c42de6dSgd78059 if (size != (ssp->image_ptr - 4)) { 48581c42de6dSgd78059 cmn_err(CE_WARN, "Image size mismatch:" 48591c42de6dSgd78059 " expected 0x%x, got 0x%x", 48601c42de6dSgd78059 size, (ssp->image_ptr - 1)); 48611c42de6dSgd78059 } 48621c42de6dSgd78059 48631c42de6dSgd78059 res = bscv_prog_image(ssp, 48641c42de6dSgd78059 ssp->image2_processing, 48651c42de6dSgd78059 imagep + 4, ssp->image_ptr - 4, loadaddr); 48661c42de6dSgd78059 48671c42de6dSgd78059 /* 48681c42de6dSgd78059 * Done the loading so set the flag to say we are doing 48691c42de6dSgd78059 * the other image. 48701c42de6dSgd78059 */ 48711c42de6dSgd78059 ssp->image2_processing = !ssp->image2_processing; 48721c42de6dSgd78059 } else if ((ssp->image_ptr < sizeof (*prog_data)) || 48731c42de6dSgd78059 (prog_data->platform.bscv.size != 48741c42de6dSgd78059 (ssp->image_ptr - sizeof (*prog_data)))) { 48751c42de6dSgd78059 /* Image too small for new style image */ 48761c42de6dSgd78059 cmn_err(CE_WARN, "image too small"); 48771c42de6dSgd78059 res = EINVAL; 48781c42de6dSgd78059 } else { 48791c42de6dSgd78059 /* New style programming image */ 48801c42de6dSgd78059 switch (prog_data->platmagic) { 48811c42de6dSgd78059 case PROG_PLAT_BSCV_IMAGE: 48821c42de6dSgd78059 res = bscv_prog_image(ssp, B_TRUE, 48831c42de6dSgd78059 imagep + sizeof (*prog_data), 48841c42de6dSgd78059 prog_data->platform.bscv.size, 48851c42de6dSgd78059 prog_data->platform.bscv.loadaddr); 48861c42de6dSgd78059 ssp->image2_processing = B_FALSE; 48871c42de6dSgd78059 break; 48881c42de6dSgd78059 case PROG_PLAT_BSCV_LOADER: 48891c42de6dSgd78059 res = bscv_prog_image(ssp, B_FALSE, 48901c42de6dSgd78059 imagep + sizeof (*prog_data), 48911c42de6dSgd78059 prog_data->platform.bscv.size, 48921c42de6dSgd78059 prog_data->platform.bscv.loadaddr); 48931c42de6dSgd78059 ssp->image2_processing = B_TRUE; 48941c42de6dSgd78059 break; 48951c42de6dSgd78059 default: 48961c42de6dSgd78059 cmn_err(CE_WARN, "unknown platmagic 0x%x", 48971c42de6dSgd78059 prog_data->platmagic); 48981c42de6dSgd78059 res = EINVAL; 48991c42de6dSgd78059 break; 49001c42de6dSgd78059 } 49011c42de6dSgd78059 } 49021c42de6dSgd78059 ssp->prog_index = 0; 49031c42de6dSgd78059 ssp->image_ptr = 0; 49041c42de6dSgd78059 } 49051c42de6dSgd78059 return (res); 49061c42de6dSgd78059 } 49071c42de6dSgd78059 49081c42de6dSgd78059 static int 49091c42de6dSgd78059 bscv_prog_stop_lom(bscv_soft_state_t *ssp) 49101c42de6dSgd78059 { 49111c42de6dSgd78059 if (ssp->programming) { 49121c42de6dSgd78059 /* 49131c42de6dSgd78059 * Already programming - this may be a retry of a failed 49141c42de6dSgd78059 * programming attempt or just a software error! 49151c42de6dSgd78059 */ 49161c42de6dSgd78059 goto queue_stopped; 49171c42de6dSgd78059 } 49181c42de6dSgd78059 49191c42de6dSgd78059 if (bscv_pause_event_daemon(ssp) == BSCV_FAILURE) { 4920*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'Q', "bscv_prog_stop_lom", 49211c42de6dSgd78059 "failed to pause event daemon thread"); 49221c42de6dSgd78059 return (EAGAIN); 49231c42de6dSgd78059 } 49241c42de6dSgd78059 49251c42de6dSgd78059 bscv_enter(ssp); 49261c42de6dSgd78059 49271c42de6dSgd78059 ssp->programming = B_TRUE; 49281c42de6dSgd78059 49291c42de6dSgd78059 bscv_exit(ssp); 49301c42de6dSgd78059 49311c42de6dSgd78059 queue_stopped: 49321c42de6dSgd78059 49331c42de6dSgd78059 ssp->prog_index = 0; 49341c42de6dSgd78059 ssp->image2_processing = B_FALSE; 49351c42de6dSgd78059 49361c42de6dSgd78059 return (0); 49371c42de6dSgd78059 } 49381c42de6dSgd78059 49391c42de6dSgd78059 static int 49401c42de6dSgd78059 bscv_prog_start_lom(bscv_soft_state_t *ssp) 49411c42de6dSgd78059 { 49421c42de6dSgd78059 int res = 0; 49431c42de6dSgd78059 49441c42de6dSgd78059 if (!ssp->programming) { 49451c42de6dSgd78059 /* Not programming so this is not a valid command */ 49461c42de6dSgd78059 return (EINVAL); 49471c42de6dSgd78059 } 49481c42de6dSgd78059 49491c42de6dSgd78059 if (ssp->image != NULL) { 49501c42de6dSgd78059 kmem_free((void *)ssp->image, BSC_IMAGE_MAX_SIZE); 49511c42de6dSgd78059 ssp->image = NULL; 49521c42de6dSgd78059 } 49531c42de6dSgd78059 49541c42de6dSgd78059 /* 49551c42de6dSgd78059 * OK we are out of reset now so: 49561c42de6dSgd78059 * Probe the firmware and set everything up. 49571c42de6dSgd78059 */ 49581c42de6dSgd78059 49591c42de6dSgd78059 bscv_enter(ssp); 49601c42de6dSgd78059 49611c42de6dSgd78059 /* Explicit clear fault because things may have been mended now */ 49621c42de6dSgd78059 bscv_clear_fault(ssp); 49631c42de6dSgd78059 49641c42de6dSgd78059 if (ssp->loader_running) { 49651c42de6dSgd78059 cmn_err(CE_WARN, "Firmware upgrade failed to exit loader - " 49661c42de6dSgd78059 "performing forced exit"); 49671c42de6dSgd78059 /* Must try to restart the lom here. */ 49681c42de6dSgd78059 /* Ensure prog mode entry to enable PRGMODE_OFF */ 49691c42de6dSgd78059 bscv_put8(ssp, chan_prog, 49701c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), 49711c42de6dSgd78059 EBUS_PROGRAM_PCR_PRGMODE_ON); 49721c42de6dSgd78059 bscv_put8(ssp, chan_prog, 49731c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_PROGRAM, EBUS_PROGRAM_PCSR), 49741c42de6dSgd78059 EBUS_PROGRAM_PCR_PRGMODE_OFF); 49751c42de6dSgd78059 ssp->loader_running = B_FALSE; 49761c42de6dSgd78059 /* give the lom chance to recover */ 49771c42de6dSgd78059 delay(drv_usectohz(5000000)); /* 5 seconds */ 49781c42de6dSgd78059 } 49791c42de6dSgd78059 49801c42de6dSgd78059 ssp->prog_mode_only = B_FALSE; 49811c42de6dSgd78059 ssp->programming = B_FALSE; 49821c42de6dSgd78059 49831c42de6dSgd78059 if (bscv_attach_common(ssp) == DDI_FAILURE) { 49841c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 49851c42de6dSgd78059 res = EIO; 49861c42de6dSgd78059 } 49871c42de6dSgd78059 49881c42de6dSgd78059 bscv_exit(ssp); 49891c42de6dSgd78059 49901c42de6dSgd78059 if (!ssp->prog_mode_only) { 49911c42de6dSgd78059 /* 49921c42de6dSgd78059 * Start the event thread after the queue has started 49931c42de6dSgd78059 * 49941c42de6dSgd78059 * Not sure if this is entirely correct because 49951c42de6dSgd78059 * the other code at the end of bscv_attach() 49961c42de6dSgd78059 * does not get run here. 49971c42de6dSgd78059 */ 49981c42de6dSgd78059 bscv_start_event_daemon(ssp); 49991c42de6dSgd78059 bscv_resume_event_daemon(ssp); 50001c42de6dSgd78059 } 50011c42de6dSgd78059 50021c42de6dSgd78059 return (res); 50031c42de6dSgd78059 } 50041c42de6dSgd78059 50051c42de6dSgd78059 50061c42de6dSgd78059 /* 50071c42de6dSgd78059 * ********************************************************************* 50081c42de6dSgd78059 * Attach processing 50091c42de6dSgd78059 * ********************************************************************* 50101c42de6dSgd78059 */ 50111c42de6dSgd78059 50121c42de6dSgd78059 /* 50131c42de6dSgd78059 * function - bscv_attach_common 50141c42de6dSgd78059 * description - this routine co-ordinates the initialisation of the 50151c42de6dSgd78059 * driver both at attach time and after firmware programming. 50161c42de6dSgd78059 * sequence - bscv_setup_capability - read LOMlite2 capabilities 50171c42de6dSgd78059 * bscv_probe_check - test comms and setup register cache 50181c42de6dSgd78059 * bscv_setup_hostname - sync stored name in lom with nodename. 50191c42de6dSgd78059 * bscv_setup_static_info - read device names etc. 50201c42de6dSgd78059 * bscv_setup_events - start event daemon etc. 50211c42de6dSgd78059 * 50221c42de6dSgd78059 * inputs - device information structure, DDI_ATTACH command 50231c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 50241c42de6dSgd78059 */ 50251c42de6dSgd78059 50261c42de6dSgd78059 static int 50271c42de6dSgd78059 bscv_attach_common(bscv_soft_state_t *ssp) 50281c42de6dSgd78059 { 50291c42de6dSgd78059 ASSERT(bscv_held(ssp)); 50301c42de6dSgd78059 5031*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_attach_common:", ""); 50321c42de6dSgd78059 50331c42de6dSgd78059 /* 50341c42de6dSgd78059 * Set the threshold for reporting messages to the console to 50351c42de6dSgd78059 * Warnings or higher. 50361c42de6dSgd78059 */ 50371c42de6dSgd78059 ssp->reporting_level = 2; 50381c42de6dSgd78059 50391c42de6dSgd78059 /* 50401c42de6dSgd78059 * When the system is not running the Operating System, make 50411c42de6dSgd78059 * the microcontroller print event messages straight onto the 50421c42de6dSgd78059 * console. 50431c42de6dSgd78059 */ 50441c42de6dSgd78059 ssp->serial_reporting = LOM_SER_EVENTS_DEF; 50451c42de6dSgd78059 50461c42de6dSgd78059 /* Setup capabilities */ 50471c42de6dSgd78059 bscv_setup_capability(ssp); 50481c42de6dSgd78059 50491c42de6dSgd78059 if (bscv_probe_check(ssp) == DDI_FAILURE) { 50501c42de6dSgd78059 cmn_err(CE_WARN, "BSC chip not responding"); 50511c42de6dSgd78059 /* 50521c42de6dSgd78059 * We want lom -G to talk to this driver upon broken firmware 50531c42de6dSgd78059 * so we prematurely return success here. 50541c42de6dSgd78059 */ 50551c42de6dSgd78059 return (DDI_SUCCESS); 50561c42de6dSgd78059 } 50571c42de6dSgd78059 50581c42de6dSgd78059 bscv_setup_hostname(ssp); 50591c42de6dSgd78059 bscv_setup_static_info(ssp); 50601c42de6dSgd78059 bscv_setup_events(ssp); 50611c42de6dSgd78059 50621c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 50631c42de6dSgd78059 bscv_inform_bsc(ssp, BSC_INFORM_ONLINE); 50641c42de6dSgd78059 #endif /* __i386 || __amd64 */ 50651c42de6dSgd78059 /* 50661c42de6dSgd78059 * Watchdog configuration and CPU signatures are sent asynchronously 50671c42de6dSgd78059 * with respect to attach so only inform the BSC if we've already 50681c42de6dSgd78059 * sent the data in the past. 50691c42de6dSgd78059 */ 50701c42de6dSgd78059 50711c42de6dSgd78059 if (ssp->progress & BSCV_WDOG_CFG) 50721c42de6dSgd78059 bscv_setup_watchdog(ssp); 50731c42de6dSgd78059 50741c42de6dSgd78059 #ifdef __sparc 50751c42de6dSgd78059 if (ssp->progress & BSCV_SIG_SENT) 50761c42de6dSgd78059 bscv_write_sig(ssp, ssp->last_sig); 50771c42de6dSgd78059 #endif /* __sparc */ 50781c42de6dSgd78059 50791c42de6dSgd78059 return (DDI_SUCCESS); 50801c42de6dSgd78059 } 50811c42de6dSgd78059 50821c42de6dSgd78059 /* 50831c42de6dSgd78059 * function - bscv_cleanup 50841c42de6dSgd78059 * description - routine that does the necessary tidying up if the attach 50851c42de6dSgd78059 * request fails or the driver is to be detached. 50861c42de6dSgd78059 * If the event thread has been started we may fail to 50871c42de6dSgd78059 * stop it (because it is busy) so we fail the cleanup 50881c42de6dSgd78059 * and hence the detach. All other calls to bscv_cleanup 50891c42de6dSgd78059 * are done before the event daemon is started. 50901c42de6dSgd78059 * inputs - soft state structure address. 50911c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE. 50921c42de6dSgd78059 */ 50931c42de6dSgd78059 50941c42de6dSgd78059 static int 50951c42de6dSgd78059 bscv_cleanup(bscv_soft_state_t *ssp) 50961c42de6dSgd78059 { 50971c42de6dSgd78059 int instance; 50981c42de6dSgd78059 uint8_t bits2set; 50991c42de6dSgd78059 uint8_t bits2clear; 51001c42de6dSgd78059 51011c42de6dSgd78059 instance = ssp->instance; 51021c42de6dSgd78059 51031c42de6dSgd78059 if (ssp->progress & BSCV_LOCKS) { 51041c42de6dSgd78059 bscv_enter(ssp); 51051c42de6dSgd78059 } 51061c42de6dSgd78059 51071c42de6dSgd78059 if (ssp->progress & BSCV_THREAD) { 51081c42de6dSgd78059 if (bscv_stop_event_daemon(ssp) == DDI_FAILURE) { 51091c42de6dSgd78059 /* Fail the cleanup - may be able to cleanup later */ 51101c42de6dSgd78059 if (ssp->progress & BSCV_LOCKS) { 51111c42de6dSgd78059 bscv_exit(ssp); 51121c42de6dSgd78059 } 51131c42de6dSgd78059 return (DDI_FAILURE); 51141c42de6dSgd78059 } 51151c42de6dSgd78059 } 51161c42de6dSgd78059 51171c42de6dSgd78059 if (ssp->progress & BSCV_NODES) { 51181c42de6dSgd78059 ddi_remove_minor_node(ssp->dip, NULL); 51191c42de6dSgd78059 } 51201c42de6dSgd78059 51211c42de6dSgd78059 if (ssp->progress & BSCV_MAPPED_REGS) { 51221c42de6dSgd78059 /* 51231c42de6dSgd78059 * switch back on serial event reporting - cover all configs. 51241c42de6dSgd78059 */ 51251c42de6dSgd78059 bits2set = 0; 51261c42de6dSgd78059 bits2clear = 0; 51271c42de6dSgd78059 if (ssp->serial_reporting == LOM_SER_EVENTS_ON) { 51281c42de6dSgd78059 bits2clear |= EBUS_ALARM_NOEVENTS; 51291c42de6dSgd78059 } else if (ssp->serial_reporting == LOM_SER_EVENTS_OFF) { 51301c42de6dSgd78059 bits2set |= EBUS_ALARM_NOEVENTS; 51311c42de6dSgd78059 } else if (ssp->serial_reporting == LOM_SER_EVENTS_DEF) { 51321c42de6dSgd78059 bits2clear |= EBUS_ALARM_NOEVENTS; 51331c42de6dSgd78059 } 51341c42de6dSgd78059 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_ALARM, 51351c42de6dSgd78059 bits2set, bits2clear); 51361c42de6dSgd78059 51371c42de6dSgd78059 /* 51381c42de6dSgd78059 * disable the reset function if we have enabled 51391c42de6dSgd78059 * it. We don't want any nasty surprises like system 51401c42de6dSgd78059 * rebooting unexpectedly. If we timeout on the busy 51411c42de6dSgd78059 * flag we just have to carry on. 51421c42de6dSgd78059 */ 51431c42de6dSgd78059 5144*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'W', "bscv_cleanup", 51451c42de6dSgd78059 "bscv_cleanup - disable wdog"); 51461c42de6dSgd78059 if (bscv_get8_cached(ssp, EBUS_IDX_WDOG_CTRL) & 51471c42de6dSgd78059 EBUS_WDOG_ENABLE) { 51481c42de6dSgd78059 bscv_setclear8(ssp, chan_general, EBUS_IDX_WDOG_CTRL, 51491c42de6dSgd78059 0, EBUS_WDOG_RST | EBUS_WDOG_ENABLE); 51501c42de6dSgd78059 } 51511c42de6dSgd78059 } 51521c42de6dSgd78059 51531c42de6dSgd78059 /* 51541c42de6dSgd78059 * unmap registers 51551c42de6dSgd78059 */ 51561c42de6dSgd78059 51571c42de6dSgd78059 if (ssp->progress & BSCV_MAPPED_REGS) { 51581c42de6dSgd78059 bscv_unmap_regs(ssp); 51591c42de6dSgd78059 } 51601c42de6dSgd78059 51611c42de6dSgd78059 /* 51621c42de6dSgd78059 * release any memory allocated for mutexes and condition 51631c42de6dSgd78059 * variables before deallocating the structures containing them 51641c42de6dSgd78059 */ 51651c42de6dSgd78059 51661c42de6dSgd78059 if (ssp->progress & BSCV_LOCKS) { 51671c42de6dSgd78059 bscv_exit(ssp); 51681c42de6dSgd78059 cv_destroy(&ssp->task_cv); 51691c42de6dSgd78059 cv_destroy(&ssp->task_evnt_cv); 51701c42de6dSgd78059 mutex_destroy(&ssp->task_mu); 51711c42de6dSgd78059 mutex_destroy(&ssp->prog_mu); 51721c42de6dSgd78059 mutex_destroy(&ssp->cmd_mutex); 51731c42de6dSgd78059 } 51741c42de6dSgd78059 51751c42de6dSgd78059 if (ssp->image != NULL) { 51761c42de6dSgd78059 kmem_free((void *)ssp->image, BSC_IMAGE_MAX_SIZE); 51771c42de6dSgd78059 } 51781c42de6dSgd78059 51791c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 51801c42de6dSgd78059 bscv_watchdog_cyclic_remove(ssp); 51811c42de6dSgd78059 #endif /* __i386 || __amd64 */ 51821c42de6dSgd78059 ddi_soft_state_free(bscv_statep, instance); 51831c42de6dSgd78059 51841c42de6dSgd78059 return (DDI_SUCCESS); 51851c42de6dSgd78059 } 51861c42de6dSgd78059 51871c42de6dSgd78059 /* 51881c42de6dSgd78059 * function - bscv_setup_capability 51891c42de6dSgd78059 * description - probe the lom find what capabilities are present for 51901c42de6dSgd78059 * us to use. 51911c42de6dSgd78059 * inputs - soft state ptr 51921c42de6dSgd78059 * outputs - returns DDI_SUCCESS or DDI_FAILURE 51931c42de6dSgd78059 */ 51941c42de6dSgd78059 static void bscv_setup_capability(bscv_soft_state_t *ssp) 51951c42de6dSgd78059 { 51961c42de6dSgd78059 ASSERT(bscv_held(ssp)); 51971c42de6dSgd78059 51981c42de6dSgd78059 if (ssp->prog_mode_only) { 51991c42de6dSgd78059 /* Turn off all capabilities */ 52001c42de6dSgd78059 ssp->cap0 = 0; 52011c42de6dSgd78059 ssp->cap1 = 0; 52021c42de6dSgd78059 ssp->cap2 = 0; 52031c42de6dSgd78059 return; 52041c42de6dSgd78059 } 52051c42de6dSgd78059 52061c42de6dSgd78059 ssp->cap0 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP0); 52071c42de6dSgd78059 ssp->cap1 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP1); 52081c42de6dSgd78059 ssp->cap2 = bscv_get8(ssp, chan_general, EBUS_IDX_CAP2); 52091c42de6dSgd78059 if (!bscv_faulty(ssp)) { 5210*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_setup_capability", 52111c42de6dSgd78059 "Capability flags cap0=0x%x cap1=0x%x, cap2=0x%x", 52121c42de6dSgd78059 ssp->cap0, ssp->cap1, ssp->cap2); 52131c42de6dSgd78059 } else { 52141c42de6dSgd78059 cmn_err(CE_WARN, "!Could not read capability flags"); 52151c42de6dSgd78059 ssp->cap0 = 0; ssp->cap1 = 0; ssp->cap2 = 0; 52161c42de6dSgd78059 } 52171c42de6dSgd78059 } 52181c42de6dSgd78059 52191c42de6dSgd78059 /* 52201c42de6dSgd78059 * function - bscv_probe_check 52211c42de6dSgd78059 * description - probe the lom to check for correct operation 52221c42de6dSgd78059 * has a side effect of setting up the cached registers and 52231c42de6dSgd78059 * updates ssp->prog_mode_only. 52241c42de6dSgd78059 * inputs - soft state ptr 52251c42de6dSgd78059 * outputs - returns DDI_SUCCESS or DDI_FAILURE 52261c42de6dSgd78059 */ 52271c42de6dSgd78059 52281c42de6dSgd78059 static int bscv_probe_check(bscv_soft_state_t *ssp) 52291c42de6dSgd78059 { 52301c42de6dSgd78059 int i; 52311c42de6dSgd78059 uint8_t probeval; 52321c42de6dSgd78059 52331c42de6dSgd78059 ASSERT(bscv_held(ssp)); 52341c42de6dSgd78059 5235*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_probe_check", ""); 52361c42de6dSgd78059 52371c42de6dSgd78059 if (!ssp->prog_mode_only) { 52381c42de6dSgd78059 /* 52391c42de6dSgd78059 * Make sure probe location is OK so that we are 52401c42de6dSgd78059 * in sync. 52411c42de6dSgd78059 * We want to make sure that this is not faulty so we 52421c42de6dSgd78059 * do a bscv_clear_fault to clear any existing 52431c42de6dSgd78059 * fault records down. 52441c42de6dSgd78059 */ 52451c42de6dSgd78059 bscv_clear_fault(ssp); 52461c42de6dSgd78059 probeval = bscv_get8(ssp, chan_general, EBUS_IDX_PROBEAA); 52471c42de6dSgd78059 if (bscv_faulty(ssp)) { 52481c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 52491c42de6dSgd78059 } else if (probeval != 0xAA) { 5250*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_probe_check", 52511c42de6dSgd78059 "LOMlite out of sync"); 52521c42de6dSgd78059 52531c42de6dSgd78059 /* 52541c42de6dSgd78059 * It may be that the LOMlite was out of 52551c42de6dSgd78059 * sync so lets try the read again. 52561c42de6dSgd78059 */ 52571c42de6dSgd78059 probeval = bscv_get8(ssp, chan_general, 52581c42de6dSgd78059 EBUS_IDX_PROBEAA); 52591c42de6dSgd78059 if (bscv_faulty(ssp)) { 5260*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_probe_check", 52611c42de6dSgd78059 "Init readAA1 failed"); 52621c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 52631c42de6dSgd78059 } else if (probeval != 0xAA) { 52641c42de6dSgd78059 /* 52651c42de6dSgd78059 * OK that is twice we are out so I 52661c42de6dSgd78059 * guess the LOMlite is in trouble 52671c42de6dSgd78059 */ 5268*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_probe_check", 52691c42de6dSgd78059 "Init readAA probe failed - got 0x%x", 52701c42de6dSgd78059 probeval); 52711c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 52721c42de6dSgd78059 } 52731c42de6dSgd78059 } 52741c42de6dSgd78059 } 52751c42de6dSgd78059 52761c42de6dSgd78059 /* 52771c42de6dSgd78059 * Read in all page zero lom registers. 52781c42de6dSgd78059 * Read state change 1st so we dont miss anything and clear it. 52791c42de6dSgd78059 * Note: we discard the values because we rely on bscv_get8 to 52801c42de6dSgd78059 * setup the cache of register values. 52811c42de6dSgd78059 */ 52821c42de6dSgd78059 52831c42de6dSgd78059 if (!ssp->prog_mode_only) { 52841c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, EBUS_IDX_STATE_CHNG); 52851c42de6dSgd78059 if (bscv_faulty(ssp)) { 5286*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_probe_check", 52871c42de6dSgd78059 "Read of state change register failed"); 52881c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 52891c42de6dSgd78059 } 52901c42de6dSgd78059 } 52911c42de6dSgd78059 52921c42de6dSgd78059 if (!ssp->prog_mode_only) { 52931c42de6dSgd78059 for (i = 1; i < 0x80; i++) { 52941c42de6dSgd78059 switch (i) { 52951c42de6dSgd78059 case EBUS_IDX_STATE_CHNG: 52961c42de6dSgd78059 case EBUS_IDX_CMD_RES: 52971c42de6dSgd78059 case EBUS_IDX_HNAME_CHAR: 52981c42de6dSgd78059 /* 52991c42de6dSgd78059 * Should not read these - they have side 53001c42de6dSgd78059 * effects. 53011c42de6dSgd78059 */ 53021c42de6dSgd78059 break; 53031c42de6dSgd78059 default: 53041c42de6dSgd78059 (void) bscv_get8(ssp, chan_general, i); 53051c42de6dSgd78059 break; 53061c42de6dSgd78059 } 53071c42de6dSgd78059 if (bscv_faulty(ssp)) { 5308*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_probe_check", 53091c42de6dSgd78059 "Initial read or register %2x failed", i); 53101c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 53111c42de6dSgd78059 /* Might as well give up now! */ 53121c42de6dSgd78059 break; 53131c42de6dSgd78059 } 53141c42de6dSgd78059 } 53151c42de6dSgd78059 } 53161c42de6dSgd78059 53171c42de6dSgd78059 /* 53181c42de6dSgd78059 * Check the probe keys so we know the lom is OK 53191c42de6dSgd78059 */ 53201c42de6dSgd78059 53211c42de6dSgd78059 if (!ssp->prog_mode_only) { 53221c42de6dSgd78059 if ((bscv_get8_cached(ssp, EBUS_IDX_PROBE55) != 0x55) || 53231c42de6dSgd78059 (bscv_get8_cached(ssp, EBUS_IDX_PROBEAA) != 0xAA)) { 53241c42de6dSgd78059 5325*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_probe_check", 53261c42de6dSgd78059 "LOMlite Probe failed"); 53271c42de6dSgd78059 for (i = 0; i < 0x8; i++) { 5328*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_probe_check", 53291c42de6dSgd78059 "%2x %2x %2x %2x %2x %2x %2x %2x %2x " 53301c42de6dSgd78059 "%2x %2x %2x %2x %2x %2x %2x %2x %2x", 53311c42de6dSgd78059 bscv_get8_cached(ssp, i), 53321c42de6dSgd78059 bscv_get8_cached(ssp, i + 1), 53331c42de6dSgd78059 bscv_get8_cached(ssp, i + 2), 53341c42de6dSgd78059 bscv_get8_cached(ssp, i + 3), 53351c42de6dSgd78059 bscv_get8_cached(ssp, i + 4), 53361c42de6dSgd78059 bscv_get8_cached(ssp, i + 5), 53371c42de6dSgd78059 bscv_get8_cached(ssp, i + 6), 53381c42de6dSgd78059 bscv_get8_cached(ssp, i + 7), 53391c42de6dSgd78059 bscv_get8_cached(ssp, i + 8), 53401c42de6dSgd78059 bscv_get8_cached(ssp, i + 9), 53411c42de6dSgd78059 bscv_get8_cached(ssp, i + 10), 53421c42de6dSgd78059 bscv_get8_cached(ssp, i + 11), 53431c42de6dSgd78059 bscv_get8_cached(ssp, i + 12), 53441c42de6dSgd78059 bscv_get8_cached(ssp, i + 13), 53451c42de6dSgd78059 bscv_get8_cached(ssp, i + 14), 53461c42de6dSgd78059 bscv_get8_cached(ssp, i + 15)); 53471c42de6dSgd78059 } 53481c42de6dSgd78059 ssp->prog_mode_only = B_TRUE; 53491c42de6dSgd78059 } 53501c42de6dSgd78059 } 53511c42de6dSgd78059 53521c42de6dSgd78059 return ((ssp->prog_mode_only == B_FALSE) ? DDI_SUCCESS : DDI_FAILURE); 53531c42de6dSgd78059 } 53541c42de6dSgd78059 53551c42de6dSgd78059 #ifdef __sparc 53561c42de6dSgd78059 /* 53571c42de6dSgd78059 * function - bscv_idi_set 53581c42de6dSgd78059 * description - bscv inter driver interface set function 53591c42de6dSgd78059 * inputs - structure which defines type of service required and data 53601c42de6dSgd78059 * ouputs - none 53611c42de6dSgd78059 * 53621c42de6dSgd78059 * This is the Entry Point function for the platmod driver. It works out which 53631c42de6dSgd78059 * X Bus channel ought to deliver the service requested. 53641c42de6dSgd78059 */ 53651c42de6dSgd78059 void 53661c42de6dSgd78059 bscv_idi_set(struct bscv_idi_info info) 53671c42de6dSgd78059 { 53681c42de6dSgd78059 struct bscv_idi_callout *tbl; 53691c42de6dSgd78059 boolean_t retval; 53701c42de6dSgd78059 53711c42de6dSgd78059 ASSERT(bscv_idi_mgr.magic == BSCV_IDI_CALLOUT_MAGIC); 53721c42de6dSgd78059 53731c42de6dSgd78059 if (bscv_idi_mgr.tbl == NULL) { 53741c42de6dSgd78059 if (bscv_idi_err()) 53751c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_idi_set : cannot find " 53761c42de6dSgd78059 "bscv_callout_table"); 53771c42de6dSgd78059 return; 53781c42de6dSgd78059 } else if (bscv_idi_mgr.valid_inst == (uint32_t)~0) { 53791c42de6dSgd78059 if (bscv_idi_err()) 53801c42de6dSgd78059 /* 53811c42de6dSgd78059 * This error message can appear in the context of 53821c42de6dSgd78059 * another driver, say platmod or todblade. We want 53831c42de6dSgd78059 * to clearly indicate the culprit driver so put in 53841c42de6dSgd78059 * the driver name. 53851c42de6dSgd78059 */ 53861c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_idi_set : no valid " 53871c42de6dSgd78059 "driver instance of " 53881c42de6dSgd78059 MYNAME); 53891c42de6dSgd78059 return; 53901c42de6dSgd78059 } 53911c42de6dSgd78059 53921c42de6dSgd78059 tbl = bscv_idi_mgr.tbl; 53931c42de6dSgd78059 53941c42de6dSgd78059 while (tbl->type != BSCV_IDI_NULL) { 53951c42de6dSgd78059 if (tbl->type == info.type) { 53961c42de6dSgd78059 /* 53971c42de6dSgd78059 * We service the request with a valid instance number 53981c42de6dSgd78059 * for the driver. 53991c42de6dSgd78059 */ 54001c42de6dSgd78059 retval = ((tbl->fn) (info)); 54011c42de6dSgd78059 54021c42de6dSgd78059 /* 54031c42de6dSgd78059 * If the request was serviced, clear any accumulated 54041c42de6dSgd78059 * error counters so future warnings will be reported if 54051c42de6dSgd78059 * seen. 54061c42de6dSgd78059 */ 54071c42de6dSgd78059 if (retval == B_TRUE) 54081c42de6dSgd78059 bscv_idi_clear_err(); 54091c42de6dSgd78059 return; 54101c42de6dSgd78059 } else { 54111c42de6dSgd78059 tbl++; 54121c42de6dSgd78059 } 54131c42de6dSgd78059 } 54141c42de6dSgd78059 54151c42de6dSgd78059 if (bscv_idi_err()) 54161c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_idi_set : cannot match info.type %d", 54171c42de6dSgd78059 info.type); 54181c42de6dSgd78059 } 54191c42de6dSgd78059 54201c42de6dSgd78059 /* 54211c42de6dSgd78059 * function - bscv_nodename_set 54221c42de6dSgd78059 * description - notify the event thread that a nodename change has occurred. 54231c42de6dSgd78059 * inputs - data from client driver 54241c42de6dSgd78059 * outputs - none. 54251c42de6dSgd78059 * side-effects - the event thread will schedule an update to the lom firmware. 54261c42de6dSgd78059 */ 54271c42de6dSgd78059 /*ARGSUSED*/ 54281c42de6dSgd78059 static boolean_t 54291c42de6dSgd78059 bscv_nodename_set(struct bscv_idi_info info) 54301c42de6dSgd78059 { 54311c42de6dSgd78059 bscv_soft_state_t *ssp; 54321c42de6dSgd78059 54331c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst); 54341c42de6dSgd78059 54351c42de6dSgd78059 if (ssp == NULL) { 54361c42de6dSgd78059 if (bscv_idi_err()) 54371c42de6dSgd78059 cmn_err(CE_WARN, "!blade_nodename_set: cannot get ssp"); 54381c42de6dSgd78059 return (B_FALSE); 54391c42de6dSgd78059 } 54401c42de6dSgd78059 54411c42de6dSgd78059 /* Get a lock on the SSP, notify our change, then exit */ 54421c42de6dSgd78059 mutex_enter(&ssp->task_mu); 54431c42de6dSgd78059 ssp->nodename_change = B_TRUE; 54441c42de6dSgd78059 cv_signal(&ssp->task_cv); 54451c42de6dSgd78059 mutex_exit(&ssp->task_mu); 54461c42de6dSgd78059 54471c42de6dSgd78059 return (B_TRUE); 54481c42de6dSgd78059 } 54491c42de6dSgd78059 54501c42de6dSgd78059 /* 54511c42de6dSgd78059 * function - bscv_sig_set 54521c42de6dSgd78059 * description - write a signature 54531c42de6dSgd78059 * inputs - data from client driver 54541c42de6dSgd78059 * outputs - none. 54551c42de6dSgd78059 */ 54561c42de6dSgd78059 static boolean_t 54571c42de6dSgd78059 bscv_sig_set(struct bscv_idi_info info) 54581c42de6dSgd78059 { 54591c42de6dSgd78059 bscv_soft_state_t *ssp; 54601c42de6dSgd78059 bscv_sig_t sig; 54611c42de6dSgd78059 54621c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst); 54631c42de6dSgd78059 54641c42de6dSgd78059 if (ssp == NULL) { 54651c42de6dSgd78059 if (bscv_idi_err()) 54661c42de6dSgd78059 cmn_err(CE_WARN, "!blade_nodename_set: cannot get ssp"); 54671c42de6dSgd78059 return (B_FALSE); 54681c42de6dSgd78059 } 54691c42de6dSgd78059 54701c42de6dSgd78059 /* Service the request */ 54711c42de6dSgd78059 bcopy(info.data, &sig, sizeof (sig)); 54721c42de6dSgd78059 bscv_enter(ssp); 54731c42de6dSgd78059 bscv_write_sig(ssp, sig); 54741c42de6dSgd78059 bscv_exit(ssp); 54751c42de6dSgd78059 54761c42de6dSgd78059 return (B_TRUE); 54771c42de6dSgd78059 } 54781c42de6dSgd78059 #endif /* __sparc */ 54791c42de6dSgd78059 54801c42de6dSgd78059 static void 54811c42de6dSgd78059 bscv_wdog_do_pat(bscv_soft_state_t *ssp) 54821c42de6dSgd78059 { 54831c42de6dSgd78059 uint8_t pat; 54841c42de6dSgd78059 54851c42de6dSgd78059 /* 54861c42de6dSgd78059 * The value of the dog pat is a sequence number which wraps around, 54871c42de6dSgd78059 * bounded by BSCV_WDOG_PAT_SEQ_MASK. 54881c42de6dSgd78059 */ 54891c42de6dSgd78059 pat = ssp->pat_seq++; 54901c42de6dSgd78059 pat &= EBUS_WDOG_NB_PAT_SEQ_MASK; 54911c42de6dSgd78059 54921c42de6dSgd78059 /* Set top nibble to indicate a pat */ 54931c42de6dSgd78059 pat |= EBUS_WDOG_NB_PAT; 54941c42de6dSgd78059 54951c42de6dSgd78059 /* 54961c42de6dSgd78059 * Now pat the dog. This exercises a special protocol in the 54971c42de6dSgd78059 * bus nexus that offers : non-blocking IO, and timely delivery, 54981c42de6dSgd78059 * callable from high-level interrupt context. The requirement 54991c42de6dSgd78059 * on us is that the channel is not shared for any other use. 55001c42de6dSgd78059 * This means for chan_wdogpat, nothing may use channel[chan].regs 55011c42de6dSgd78059 * or channel.[chan].handle. 55021c42de6dSgd78059 */ 55031c42de6dSgd78059 55041c42de6dSgd78059 ddi_put8(ssp->channel[chan_wdogpat].handle, 55051c42de6dSgd78059 ssp->channel[chan_wdogpat].regs, pat); 55061c42de6dSgd78059 5507*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'W', "bscv_wdog_pat", "patted the dog with seq %d", 55081c42de6dSgd78059 pat); 55091c42de6dSgd78059 } 55101c42de6dSgd78059 55111c42de6dSgd78059 #ifdef __sparc 55121c42de6dSgd78059 /* 55131c42de6dSgd78059 * function - bscv_wdog_pat 55141c42de6dSgd78059 * description - pat the watchdog 55151c42de6dSgd78059 * inputs - data from client driver 55161c42de6dSgd78059 * outputs - none. 55171c42de6dSgd78059 */ 55181c42de6dSgd78059 /*ARGSUSED*/ 55191c42de6dSgd78059 static boolean_t 55201c42de6dSgd78059 bscv_wdog_pat(struct bscv_idi_info info) 55211c42de6dSgd78059 { 55221c42de6dSgd78059 /* 55231c42de6dSgd78059 * This function remembers if it has ever been called with the 55241c42de6dSgd78059 * configure option set. 55251c42de6dSgd78059 */ 55261c42de6dSgd78059 bscv_soft_state_t *ssp; 55271c42de6dSgd78059 55281c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst); 55291c42de6dSgd78059 55301c42de6dSgd78059 if (ssp == NULL) { 55311c42de6dSgd78059 if (bscv_idi_err()) 55321c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_wdog_pat: cannot get ssp"); 55331c42de6dSgd78059 return (B_FALSE); 55341c42de6dSgd78059 } else if (ssp->nchannels == 0) { 55351c42de6dSgd78059 /* Didn't manage to map handles so ddi_{get,put}* broken */ 55361c42de6dSgd78059 if (bscv_idi_err()) 55371c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_wdog_pat: handle not mapped"); 55381c42de6dSgd78059 return (B_FALSE); 55391c42de6dSgd78059 } 55401c42de6dSgd78059 55411c42de6dSgd78059 bscv_wdog_do_pat(ssp); 55421c42de6dSgd78059 return (B_TRUE); 55431c42de6dSgd78059 } 55441c42de6dSgd78059 55451c42de6dSgd78059 /* 55461c42de6dSgd78059 * function - bscv_wdog_cfg 55471c42de6dSgd78059 * description - configure the watchdog 55481c42de6dSgd78059 * inputs - data from client driver 55491c42de6dSgd78059 * outputs - none. 55501c42de6dSgd78059 */ 55511c42de6dSgd78059 static boolean_t 55521c42de6dSgd78059 bscv_wdog_cfg(struct bscv_idi_info info) 55531c42de6dSgd78059 { 55541c42de6dSgd78059 bscv_soft_state_t *ssp; 55551c42de6dSgd78059 55561c42de6dSgd78059 ssp = ddi_get_soft_state(bscv_statep, bscv_idi_mgr.valid_inst); 55571c42de6dSgd78059 55581c42de6dSgd78059 if (ssp == NULL) { 55591c42de6dSgd78059 if (bscv_idi_err()) 55601c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_wdog_cfg: cannot get ssp"); 55611c42de6dSgd78059 return (B_FALSE); 55621c42de6dSgd78059 } else if (ssp->nchannels == 0) { 55631c42de6dSgd78059 /* Didn't manage to map handles so ddi_{get,put}* broken */ 55641c42de6dSgd78059 if (bscv_idi_err()) 55651c42de6dSgd78059 cmn_err(CE_WARN, "!bscv_wdog_cfg: handle not mapped"); 55661c42de6dSgd78059 return (B_FALSE); 55671c42de6dSgd78059 } 55681c42de6dSgd78059 55691c42de6dSgd78059 if (sizeof (bscv_wdog_t) != info.size) { 5570*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'W', "bscv_wdog_set", "data passed in is size" 55711c42de6dSgd78059 " %d instead of %d", info.size, 55721c42de6dSgd78059 sizeof (bscv_wdog_t)); 55731c42de6dSgd78059 return (B_FALSE); 55741c42de6dSgd78059 } 55751c42de6dSgd78059 5576*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'W', "bscv_wdog_cfg", "enable_wdog %s, " 55771c42de6dSgd78059 "wdog_timeout_s %d, reset_system_on_timeout %s", 55781c42de6dSgd78059 ((bscv_wdog_t *)info.data)->enable_wdog ? "enabled" : "disabled", 55791c42de6dSgd78059 ((bscv_wdog_t *)info.data)->wdog_timeout_s, 55801c42de6dSgd78059 ((bscv_wdog_t *)info.data)->reset_system_on_timeout ? "yes" : "no"); 55811c42de6dSgd78059 bscv_write_wdog_cfg(ssp, 55821c42de6dSgd78059 ((bscv_wdog_t *)info.data)->wdog_timeout_s, 55831c42de6dSgd78059 ((bscv_wdog_t *)info.data)->enable_wdog, 55841c42de6dSgd78059 ((bscv_wdog_t *)info.data)->reset_system_on_timeout); 55851c42de6dSgd78059 return (B_TRUE); 55861c42de6dSgd78059 } 55871c42de6dSgd78059 #endif /* __sparc */ 55881c42de6dSgd78059 55891c42de6dSgd78059 static void 55901c42de6dSgd78059 bscv_write_wdog_cfg(bscv_soft_state_t *ssp, 55911c42de6dSgd78059 uint_t wdog_timeout_s, 55921c42de6dSgd78059 boolean_t enable_wdog, 55931c42de6dSgd78059 uint8_t reset_system_on_timeout) 55941c42de6dSgd78059 { 55951c42de6dSgd78059 uint8_t cfg = EBUS_WDOG_NB_CFG; 55961c42de6dSgd78059 55971c42de6dSgd78059 /* 55981c42de6dSgd78059 * Configure the timeout value (1 to 127 seconds). 55991c42de6dSgd78059 * Note that a policy is implemented at the bsc/ssp which bounds 56001c42de6dSgd78059 * the value further. The bounding here is to fit the timeout value 56011c42de6dSgd78059 * into the 7 bits the bsc uses. 56021c42de6dSgd78059 */ 56031c42de6dSgd78059 if (wdog_timeout_s < 1) 56041c42de6dSgd78059 ssp->watchdog_timeout = 1; 56051c42de6dSgd78059 else if (wdog_timeout_s > 127) 56061c42de6dSgd78059 ssp->watchdog_timeout = 127; 56071c42de6dSgd78059 else 56081c42de6dSgd78059 ssp->watchdog_timeout = wdog_timeout_s; 56091c42de6dSgd78059 56101c42de6dSgd78059 /* 56111c42de6dSgd78059 * Configure the watchdog on or off. 56121c42de6dSgd78059 */ 56131c42de6dSgd78059 if (enable_wdog) 56141c42de6dSgd78059 cfg |= EBUS_WDOG_NB_CFG_ENB; 56151c42de6dSgd78059 else 56161c42de6dSgd78059 cfg &= ~EBUS_WDOG_NB_CFG_ENB; 56171c42de6dSgd78059 56181c42de6dSgd78059 /* 56191c42de6dSgd78059 * Configure whether the microcontroller should reset the system when 56201c42de6dSgd78059 * the watchdog expires. 56211c42de6dSgd78059 */ 56221c42de6dSgd78059 ssp->watchdog_reset_on_timeout = reset_system_on_timeout; 56231c42de6dSgd78059 56241c42de6dSgd78059 ddi_put8(ssp->channel[chan_wdogpat].handle, 56251c42de6dSgd78059 ssp->channel[chan_wdogpat].regs, cfg); 56261c42de6dSgd78059 56271c42de6dSgd78059 /* have the event daemon set the timeout value and whether to reset */ 56281c42de6dSgd78059 ssp->watchdog_change = B_TRUE; 56291c42de6dSgd78059 5630*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'W', "bscv_wdog_cfg", 56311c42de6dSgd78059 "configured the dog with cfg 0x%x", cfg); 56321c42de6dSgd78059 } 56331c42de6dSgd78059 56341c42de6dSgd78059 /* 56351c42de6dSgd78059 * function - bscv_setup_watchdog 56361c42de6dSgd78059 * description - setup the bsc watchdog 56371c42de6dSgd78059 * inputs - soft state ptr 56381c42de6dSgd78059 * outputs - 56391c42de6dSgd78059 */ 56401c42de6dSgd78059 static void bscv_setup_watchdog(bscv_soft_state_t *ssp) 56411c42de6dSgd78059 { 56421c42de6dSgd78059 uint8_t set = 0; 56431c42de6dSgd78059 uint8_t clear = 0; 56441c42de6dSgd78059 #ifdef __sparc 56451c42de6dSgd78059 extern int watchdog_activated; 56461c42de6dSgd78059 #endif /* __sparc */ 56471c42de6dSgd78059 56481c42de6dSgd78059 ASSERT(bscv_held(ssp)); 56491c42de6dSgd78059 56501c42de6dSgd78059 /* Set the timeout */ 56511c42de6dSgd78059 bscv_put8(ssp, chan_general, 56521c42de6dSgd78059 EBUS_IDX_WDOG_TIME, ssp->watchdog_timeout); 56531c42de6dSgd78059 56541c42de6dSgd78059 /* Set whether to reset the system on timeout */ 56551c42de6dSgd78059 if (ssp->watchdog_reset_on_timeout) { 56561c42de6dSgd78059 set |= EBUS_WDOG_RST; 56571c42de6dSgd78059 } else { 56581c42de6dSgd78059 clear |= EBUS_WDOG_RST; 56591c42de6dSgd78059 } 56601c42de6dSgd78059 56611c42de6dSgd78059 if (watchdog_activated) { 56621c42de6dSgd78059 set |= EBUS_WDOG_ENABLE; 56631c42de6dSgd78059 } else { 56641c42de6dSgd78059 clear |= EBUS_WDOG_ENABLE; 56651c42de6dSgd78059 } 56661c42de6dSgd78059 56671c42de6dSgd78059 /* Set other host defaults */ 56681c42de6dSgd78059 clear |= (EBUS_WDOG_BREAK_DISABLE | EBUS_WDOG_AL3_FANPSU 56691c42de6dSgd78059 | EBUS_WDOG_AL3_WDOG); 56701c42de6dSgd78059 56711c42de6dSgd78059 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_WDOG_CTRL, 56721c42de6dSgd78059 set, clear); 56731c42de6dSgd78059 56741c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 56751c42de6dSgd78059 /* start the cyclic based watchdog patter */ 56761c42de6dSgd78059 bscv_watchdog_cyclic_add(ssp); 56771c42de6dSgd78059 #endif /* __i386 || __amd64 */ 56781c42de6dSgd78059 ssp->progress |= BSCV_WDOG_CFG; 56791c42de6dSgd78059 } 56801c42de6dSgd78059 56811c42de6dSgd78059 56821c42de6dSgd78059 /* 56831c42de6dSgd78059 * function - bscv_setup_hostname 56841c42de6dSgd78059 * description - setup the lom hostname if different from the nodename 56851c42de6dSgd78059 * inputs - soft state ptr 56861c42de6dSgd78059 * outputs - none 56871c42de6dSgd78059 */ 56881c42de6dSgd78059 56891c42de6dSgd78059 static void bscv_setup_hostname(bscv_soft_state_t *ssp) 56901c42de6dSgd78059 { 56911c42de6dSgd78059 char host_nodename[128]; 56921c42de6dSgd78059 char lom_nodename[128]; 56931c42de6dSgd78059 size_t hostlen; 56941c42de6dSgd78059 size_t nodelen; 56951c42de6dSgd78059 56961c42de6dSgd78059 ASSERT(bscv_held(ssp)); 56971c42de6dSgd78059 56981c42de6dSgd78059 /* 56991c42de6dSgd78059 * Check machine label is the same as the 57001c42de6dSgd78059 * system nodename. 57011c42de6dSgd78059 */ 57021c42de6dSgd78059 (void) strncpy(host_nodename, utsname.nodename, 57031c42de6dSgd78059 sizeof (host_nodename)); 57041c42de6dSgd78059 57051c42de6dSgd78059 /* read in lom hostname */ 57061c42de6dSgd78059 bscv_read_hostname(ssp, lom_nodename); 57071c42de6dSgd78059 57081c42de6dSgd78059 /* Enforce null termination */ 57091c42de6dSgd78059 host_nodename[sizeof (host_nodename) - 1] = '\0'; 57101c42de6dSgd78059 lom_nodename[sizeof (lom_nodename) - 1] = '\0'; 57111c42de6dSgd78059 57121c42de6dSgd78059 hostlen = (size_t)bscv_get8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH); 57131c42de6dSgd78059 nodelen = (size_t)strlen(host_nodename); 57141c42de6dSgd78059 if ((nodelen > 0) && 57151c42de6dSgd78059 ((hostlen != nodelen) || (strcmp((const char *)&lom_nodename, 57161c42de6dSgd78059 (const char *)&host_nodename)) || 57171c42de6dSgd78059 (hostlen == 0))) { 5718*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_setup_hostname", 57191c42de6dSgd78059 "nodename(%s,%d) != bsc label(%s,%d)", 57201c42de6dSgd78059 host_nodename, nodelen, lom_nodename, hostlen); 57211c42de6dSgd78059 57221c42de6dSgd78059 /* Write new label into LOM EEPROM */ 57231c42de6dSgd78059 bscv_write_hostname(ssp, 57241c42de6dSgd78059 host_nodename, 57251c42de6dSgd78059 (uint8_t)strlen(host_nodename)); 57261c42de6dSgd78059 } 57271c42de6dSgd78059 57281c42de6dSgd78059 ssp->progress |= BSCV_HOSTNAME_DONE; 57291c42de6dSgd78059 } 57301c42de6dSgd78059 57311c42de6dSgd78059 /* 57321c42de6dSgd78059 * function - bscv_read_hostname 57331c42de6dSgd78059 * description - read the current hostname from the lom 57341c42de6dSgd78059 * inputs - soft state pointer and buffer to store the hostname in. 57351c42de6dSgd78059 * outputs - none 57361c42de6dSgd78059 */ 57371c42de6dSgd78059 57381c42de6dSgd78059 static void 57391c42de6dSgd78059 bscv_read_hostname(bscv_soft_state_t *ssp, char *lom_nodename) 57401c42de6dSgd78059 { 57411c42de6dSgd78059 int num_failures; 57421c42de6dSgd78059 boolean_t needretry; 57431c42de6dSgd78059 int length; 57441c42de6dSgd78059 int i; 57451c42de6dSgd78059 57461c42de6dSgd78059 ASSERT(bscv_held(ssp)); 57471c42de6dSgd78059 57481c42de6dSgd78059 /* 57491c42de6dSgd78059 * We have a special failure case here because a retry of a read 57501c42de6dSgd78059 * causes data to be lost. Thus we handle the retries ourselves 57511c42de6dSgd78059 * and are also responsible for detemining if the lom is faulty 57521c42de6dSgd78059 */ 57531c42de6dSgd78059 for (num_failures = 0; 57541c42de6dSgd78059 num_failures < BSC_FAILURE_RETRY_LIMIT; 57551c42de6dSgd78059 num_failures++) { 57561c42de6dSgd78059 bscv_clear_fault(ssp); 57571c42de6dSgd78059 length = bscv_get8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH); 57581c42de6dSgd78059 if (bscv_faulty(ssp)) { 57591c42de6dSgd78059 needretry = 1; 57601c42de6dSgd78059 } else { 57611c42de6dSgd78059 needretry = 0; 57621c42de6dSgd78059 for (i = 0; i < length; i++) { 57631c42de6dSgd78059 lom_nodename[i] = bscv_get8_once(ssp, 57641c42de6dSgd78059 chan_general, EBUS_IDX_HNAME_CHAR); 57651c42de6dSgd78059 /* Retry on any error */ 57661c42de6dSgd78059 if (bscv_retcode(ssp) != 0) { 57671c42de6dSgd78059 needretry = 1; 57681c42de6dSgd78059 break; 57691c42de6dSgd78059 } 57701c42de6dSgd78059 } 57711c42de6dSgd78059 /* null terminate for strcmp later */ 57721c42de6dSgd78059 lom_nodename[length] = '\0'; 57731c42de6dSgd78059 } 57741c42de6dSgd78059 if (!needretry) { 57751c42de6dSgd78059 break; 57761c42de6dSgd78059 } 57771c42de6dSgd78059 /* Force the nodename to be empty */ 57781c42de6dSgd78059 lom_nodename[0] = '\0'; 57791c42de6dSgd78059 } 57801c42de6dSgd78059 57811c42de6dSgd78059 if (needretry) { 57821c42de6dSgd78059 /* Failure - we ran out of retries */ 57831c42de6dSgd78059 cmn_err(CE_WARN, 57841c42de6dSgd78059 "bscv_read_hostname: retried %d times, giving up", 57851c42de6dSgd78059 num_failures); 57861c42de6dSgd78059 ssp->had_fault = B_TRUE; 57871c42de6dSgd78059 } else if (num_failures > 0) { 5788*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'R', "bscv_read_hostname", 57891c42de6dSgd78059 "retried %d times, succeeded", num_failures); 57901c42de6dSgd78059 } 57911c42de6dSgd78059 } 57921c42de6dSgd78059 57931c42de6dSgd78059 /* 57941c42de6dSgd78059 * function - bscv_write_hostname 57951c42de6dSgd78059 * description - write a new hostname to the lom 57961c42de6dSgd78059 * inputs - soft state pointer, pointer to new name, name length 57971c42de6dSgd78059 * outputs - none 57981c42de6dSgd78059 */ 57991c42de6dSgd78059 static void 58001c42de6dSgd78059 bscv_write_hostname(bscv_soft_state_t *ssp, 58011c42de6dSgd78059 char *host_nodename, uint8_t length) 58021c42de6dSgd78059 { 58031c42de6dSgd78059 int num_failures; 58041c42de6dSgd78059 boolean_t needretry; 58051c42de6dSgd78059 int i; 58061c42de6dSgd78059 58071c42de6dSgd78059 ASSERT(bscv_held(ssp)); 58081c42de6dSgd78059 58091c42de6dSgd78059 /* 58101c42de6dSgd78059 * We have a special failure case here because a retry of a read 58111c42de6dSgd78059 * causes data to be lost. Thus we handle the retries ourselves 58121c42de6dSgd78059 * and are also responsible for detemining if the lom is faulty 58131c42de6dSgd78059 */ 58141c42de6dSgd78059 for (num_failures = 0; 58151c42de6dSgd78059 num_failures < BSC_FAILURE_RETRY_LIMIT; 58161c42de6dSgd78059 num_failures++) { 58171c42de6dSgd78059 bscv_clear_fault(ssp); 58181c42de6dSgd78059 bscv_put8(ssp, chan_general, EBUS_IDX_HNAME_LENGTH, length); 58191c42de6dSgd78059 if (bscv_faulty(ssp)) { 58201c42de6dSgd78059 needretry = 1; 58211c42de6dSgd78059 } else { 58221c42de6dSgd78059 needretry = 0; 58231c42de6dSgd78059 for (i = 0; i < length; i++) { 58241c42de6dSgd78059 bscv_put8_once(ssp, chan_general, 58251c42de6dSgd78059 EBUS_IDX_HNAME_CHAR, host_nodename[i]); 58261c42de6dSgd78059 /* Retry on any error */ 58271c42de6dSgd78059 if (bscv_retcode(ssp) != 0) { 58281c42de6dSgd78059 needretry = 1; 58291c42de6dSgd78059 break; 58301c42de6dSgd78059 } 58311c42de6dSgd78059 } 58321c42de6dSgd78059 } 58331c42de6dSgd78059 if (!needretry) { 58341c42de6dSgd78059 break; 58351c42de6dSgd78059 } 58361c42de6dSgd78059 } 58371c42de6dSgd78059 58381c42de6dSgd78059 if (needretry) { 58391c42de6dSgd78059 /* Failure - we ran out of retries */ 58401c42de6dSgd78059 cmn_err(CE_WARN, 58411c42de6dSgd78059 "bscv_write_hostname: retried %d times, giving up", 58421c42de6dSgd78059 num_failures); 58431c42de6dSgd78059 ssp->had_fault = B_TRUE; 58441c42de6dSgd78059 } else if (num_failures > 0) { 5845*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'R', "bscv_write_hostname", 58461c42de6dSgd78059 "retried %d times, succeeded", num_failures); 58471c42de6dSgd78059 } 58481c42de6dSgd78059 } 58491c42de6dSgd78059 58501c42de6dSgd78059 /* 58511c42de6dSgd78059 * function - bscv_setup_static_info 58521c42de6dSgd78059 * description - read in static information from the lom at attach time. 58531c42de6dSgd78059 * inputs - soft state ptr 58541c42de6dSgd78059 * outputs - none 58551c42de6dSgd78059 */ 58561c42de6dSgd78059 58571c42de6dSgd78059 static void 58581c42de6dSgd78059 bscv_setup_static_info(bscv_soft_state_t *ssp) 58591c42de6dSgd78059 { 58601c42de6dSgd78059 uint8_t addr_space_ptr; 58611c42de6dSgd78059 uint16_t mask; 58621c42de6dSgd78059 uint8_t fanspeed; 58631c42de6dSgd78059 int oldtemps[MAX_TEMPS]; 58641c42de6dSgd78059 int8_t temp; 58651c42de6dSgd78059 int i; 58661c42de6dSgd78059 58671c42de6dSgd78059 ASSERT(bscv_held(ssp)); 58681c42de6dSgd78059 58691c42de6dSgd78059 /* 58701c42de6dSgd78059 * Finally read in some static info like device names, 58711c42de6dSgd78059 * shutdown enabled, etc before the queue starts. 58721c42de6dSgd78059 */ 58731c42de6dSgd78059 58741c42de6dSgd78059 /* 58751c42de6dSgd78059 * To get the volts static info we need address space 2 58761c42de6dSgd78059 */ 58771c42de6dSgd78059 bzero(&ssp->volts, sizeof (lom_volts_t)); 58781c42de6dSgd78059 ssp->volts.num = EBUS_CONFIG2_NSUPPLY_DEC( 58791c42de6dSgd78059 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG2)); 58801c42de6dSgd78059 if (ssp->volts.num > MAX_VOLTS) { 58811c42de6dSgd78059 cmn_err(CE_WARN, 58821c42de6dSgd78059 "lom: firmware reported too many voltage lines. "); 58831c42de6dSgd78059 cmn_err(CE_CONT, "Reported %d, maximum is %d", 58841c42de6dSgd78059 ssp->volts.num, MAX_VOLTS); 58851c42de6dSgd78059 ssp->volts.num = MAX_VOLTS; 58861c42de6dSgd78059 } 58871c42de6dSgd78059 5888*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_setup_static_info", 58891c42de6dSgd78059 "num volts %d", ssp->volts.num); 58901c42de6dSgd78059 (void) bscv_read_env_name(ssp, 58911c42de6dSgd78059 EBUS_CMD_SPACE2, 58921c42de6dSgd78059 EBUS_IDX2_SUPPLY_NAME_START, 58931c42de6dSgd78059 EBUS_IDX2_SUPPLY_NAME_END, 58941c42de6dSgd78059 ssp->volts.name, 58951c42de6dSgd78059 ssp->volts.num); 58961c42de6dSgd78059 58971c42de6dSgd78059 mask = bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE2, 58981c42de6dSgd78059 EBUS_IDX2_SUPPLY_FATAL_MASK1)) << 8; 58991c42de6dSgd78059 mask |= bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE2, 59001c42de6dSgd78059 EBUS_IDX2_SUPPLY_FATAL_MASK2)); 59011c42de6dSgd78059 59021c42de6dSgd78059 for (i = 0; i < ssp->volts.num; i++) { 59031c42de6dSgd78059 ssp->volts.shutdown_enabled[i] = 59041c42de6dSgd78059 (((mask >> i) & 1) == 0) ? 0 : 1; 59051c42de6dSgd78059 } 59061c42de6dSgd78059 59071c42de6dSgd78059 /* 59081c42de6dSgd78059 * Get the temperature static info and populate initial temperatures. 59091c42de6dSgd78059 * Do not destroy old temperature values if the new value is not 59101c42de6dSgd78059 * known i.e. if the device is inaccessible. 59111c42de6dSgd78059 */ 59121c42de6dSgd78059 bcopy(ssp->temps.temp, oldtemps, sizeof (oldtemps)); 59131c42de6dSgd78059 59141c42de6dSgd78059 bzero(&ssp->temps, sizeof (lom_temp_t)); 59151c42de6dSgd78059 ssp->temps.num = EBUS_CONFIG2_NTEMP_DEC( 59161c42de6dSgd78059 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG2)); 59171c42de6dSgd78059 if (ssp->temps.num > MAX_TEMPS) { 59181c42de6dSgd78059 cmn_err(CE_WARN, 59191c42de6dSgd78059 "lom: firmware reported too many temperatures being " 59201c42de6dSgd78059 "monitored."); 59211c42de6dSgd78059 cmn_err(CE_CONT, "Reported %d, maximum is %d", 59221c42de6dSgd78059 ssp->temps.num, MAX_TEMPS); 59231c42de6dSgd78059 ssp->temps.num = MAX_TEMPS; 59241c42de6dSgd78059 } 59251c42de6dSgd78059 ssp->temps.num_ov = EBUS_CONFIG3_NOTEMP_DEC( 59261c42de6dSgd78059 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG3)); 59271c42de6dSgd78059 if (ssp->temps.num_ov > MAX_TEMPS) { 59281c42de6dSgd78059 cmn_err(CE_WARN, 59291c42de6dSgd78059 "lom: firmware reported too many over temperatures being " 59301c42de6dSgd78059 "monitored."); 59311c42de6dSgd78059 cmn_err(CE_CONT, "Reported %d, maximum is %d", 59321c42de6dSgd78059 ssp->temps.num_ov, MAX_TEMPS); 59331c42de6dSgd78059 ssp->temps.num_ov = MAX_TEMPS; 59341c42de6dSgd78059 } 5935*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_setup_static_info", 59361c42de6dSgd78059 "num temps %d, over temps %d", 59371c42de6dSgd78059 ssp->temps.num, ssp->temps.num_ov); 59381c42de6dSgd78059 59391c42de6dSgd78059 addr_space_ptr = bscv_read_env_name(ssp, 59401c42de6dSgd78059 EBUS_CMD_SPACE4, 59411c42de6dSgd78059 EBUS_IDX4_TEMP_NAME_START, 59421c42de6dSgd78059 EBUS_IDX4_TEMP_NAME_END, 59431c42de6dSgd78059 ssp->temps.name, 59441c42de6dSgd78059 ssp->temps.num); 59451c42de6dSgd78059 59461c42de6dSgd78059 for (i = 0; i < ssp->temps.num; i++) { 59471c42de6dSgd78059 ssp->temps.warning[i] = (int8_t)bscv_get8(ssp, chan_general, 59481c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE4, EBUS_IDX4_TEMP_WARN1 + i)); 59491c42de6dSgd78059 59501c42de6dSgd78059 /* 59511c42de6dSgd78059 * If shutdown is not enabled then set it as zero so 59521c42de6dSgd78059 * it is not displayed by the utility. 59531c42de6dSgd78059 */ 59541c42de6dSgd78059 if ((bscv_get8(ssp, chan_general, BSCVA(EBUS_CMD_SPACE4, 59551c42de6dSgd78059 EBUS_IDX4_TEMP_FATAL_MASK)) >> i) & 0x01) { 59561c42de6dSgd78059 ssp->temps.shutdown[i] = (int8_t)bscv_get8(ssp, 59571c42de6dSgd78059 chan_general, 59581c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE4, EBUS_IDX4_TEMP_SDOWN1 + i)); 59591c42de6dSgd78059 } else { 59601c42de6dSgd78059 ssp->temps.shutdown[i] = 0; 59611c42de6dSgd78059 } 59621c42de6dSgd78059 } 59631c42de6dSgd78059 59641c42de6dSgd78059 for (i = 0; i < ssp->temps.num; i++) { 59651c42de6dSgd78059 temp = bscv_get8(ssp, chan_general, EBUS_IDX_TEMP1 + i); 59661c42de6dSgd78059 if ((temp <= LOM_TEMP_MAX_VALUE) || 59671c42de6dSgd78059 (temp == LOM_TEMP_STATE_NOT_PRESENT)) { 59681c42de6dSgd78059 ssp->temps.temp[i] = temp; 59691c42de6dSgd78059 } else { 59701c42de6dSgd78059 /* New value is not known - use old value */ 59711c42de6dSgd78059 ssp->temps.temp[i] = oldtemps[i]; 59721c42de6dSgd78059 } 59731c42de6dSgd78059 } 59741c42de6dSgd78059 59751c42de6dSgd78059 /* 59761c42de6dSgd78059 * Check for and skip a single 0xff character between the 59771c42de6dSgd78059 * temperature and over temperature names 59781c42de6dSgd78059 */ 59791c42de6dSgd78059 if (bscv_get8(ssp, chan_general, 59801c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE4, addr_space_ptr)) == 0xff) { 59811c42de6dSgd78059 addr_space_ptr++; 59821c42de6dSgd78059 } 59831c42de6dSgd78059 59841c42de6dSgd78059 (void) bscv_read_env_name(ssp, 59851c42de6dSgd78059 EBUS_CMD_SPACE4, 59861c42de6dSgd78059 addr_space_ptr, 59871c42de6dSgd78059 EBUS_IDX4_TEMP_NAME_END, 59881c42de6dSgd78059 ssp->temps.name_ov, 59891c42de6dSgd78059 ssp->temps.num_ov); 59901c42de6dSgd78059 59911c42de6dSgd78059 /* 59921c42de6dSgd78059 * To get the CB static info we need address space 3 59931c42de6dSgd78059 */ 59941c42de6dSgd78059 bzero(&ssp->sflags, sizeof (lom_sflags_t)); 59951c42de6dSgd78059 ssp->sflags.num = EBUS_CONFIG3_NBREAKERS_DEC(bscv_get8(ssp, 59961c42de6dSgd78059 chan_general, EBUS_IDX_CONFIG3)); 59971c42de6dSgd78059 if (ssp->sflags.num > MAX_STATS) { 59981c42de6dSgd78059 cmn_err(CE_WARN, 59991c42de6dSgd78059 "lom: firmware reported too many status flags."); 60001c42de6dSgd78059 cmn_err(CE_CONT, 60011c42de6dSgd78059 "Reported %d, maximum is %d", 60021c42de6dSgd78059 ssp->sflags.num, MAX_STATS); 60031c42de6dSgd78059 ssp->sflags.num = MAX_STATS; 60041c42de6dSgd78059 } 6005*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_setup_static_info", 60061c42de6dSgd78059 "num sflags %d", ssp->sflags.num); 60071c42de6dSgd78059 60081c42de6dSgd78059 (void) bscv_read_env_name(ssp, 60091c42de6dSgd78059 EBUS_CMD_SPACE3, 60101c42de6dSgd78059 EBUS_IDX3_BREAKER_NAME_START, 60111c42de6dSgd78059 EBUS_IDX3_BREAKER_NAME_END, 60121c42de6dSgd78059 ssp->sflags.name, 60131c42de6dSgd78059 ssp->sflags.num); 60141c42de6dSgd78059 60151c42de6dSgd78059 60161c42de6dSgd78059 /* 60171c42de6dSgd78059 * To get the fan static info we need address space 5 60181c42de6dSgd78059 */ 60191c42de6dSgd78059 ssp->num_fans = EBUS_CONFIG_NFAN_DEC( 60201c42de6dSgd78059 bscv_get8(ssp, chan_general, EBUS_IDX_CONFIG)); 60211c42de6dSgd78059 if (ssp->num_fans > MAX_FANS) { 60221c42de6dSgd78059 cmn_err(CE_WARN, 60231c42de6dSgd78059 "lom: firmware reported too many fans. "); 60241c42de6dSgd78059 cmn_err(CE_CONT, 60251c42de6dSgd78059 "Reported %d, maximum is %d", 60261c42de6dSgd78059 ssp->num_fans, MAX_FANS); 60271c42de6dSgd78059 ssp->num_fans = MAX_FANS; 60281c42de6dSgd78059 } 60291c42de6dSgd78059 60301c42de6dSgd78059 for (i = 0; i < ssp->num_fans; i++) { 60311c42de6dSgd78059 fanspeed = bscv_get8(ssp, chan_general, 60321c42de6dSgd78059 EBUS_IDX_FAN1_SPEED + i); 60331c42de6dSgd78059 if ((fanspeed <= LOM_FAN_MAX_SPEED) || 60341c42de6dSgd78059 (fanspeed == LOM_FAN_NOT_PRESENT)) { 60351c42de6dSgd78059 /* 60361c42de6dSgd78059 * Do not destroy previous values unless the 60371c42de6dSgd78059 * value is definitive. 60381c42de6dSgd78059 */ 60391c42de6dSgd78059 ssp->fanspeed[i] = fanspeed; 60401c42de6dSgd78059 } 60411c42de6dSgd78059 } 60421c42de6dSgd78059 6043*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_setup_static_info", 60441c42de6dSgd78059 "num fans %d", ssp->num_fans); 60451c42de6dSgd78059 60461c42de6dSgd78059 (void) bscv_read_env_name(ssp, 60471c42de6dSgd78059 EBUS_CMD_SPACE5, 60481c42de6dSgd78059 EBUS_IDX5_FAN_NAME_START, 60491c42de6dSgd78059 EBUS_IDX5_FAN_NAME_END, 60501c42de6dSgd78059 ssp->fan_names, 60511c42de6dSgd78059 ssp->num_fans); 60521c42de6dSgd78059 60531c42de6dSgd78059 /* Get led static information from address space 10 */ 60541c42de6dSgd78059 60551c42de6dSgd78059 (void) bscv_read_env_name(ssp, 60561c42de6dSgd78059 EBUS_CMD_SPACE_LEDS, 60571c42de6dSgd78059 EBUS_IDX10_LED_NAME_START, 60581c42de6dSgd78059 EBUS_IDX10_LED_NAME_END, 60591c42de6dSgd78059 ssp->led_names, 60601c42de6dSgd78059 MAX_LED_ID); 60611c42de6dSgd78059 } 60621c42de6dSgd78059 60631c42de6dSgd78059 /* 60641c42de6dSgd78059 * function - bscv_read_env_name 60651c42de6dSgd78059 * description - read in static environment names 60661c42de6dSgd78059 * warning changes address space and the caller relies 60671c42de6dSgd78059 * on this behaviour. 60681c42de6dSgd78059 * inputs - soft state ptr, chosen address space, 60691c42de6dSgd78059 * start of name data, end of name data, 60701c42de6dSgd78059 * name storage, number of names. 60711c42de6dSgd78059 * outputs - next address for reading name data. 60721c42de6dSgd78059 */ 60731c42de6dSgd78059 60741c42de6dSgd78059 static uint8_t 60751c42de6dSgd78059 bscv_read_env_name(bscv_soft_state_t *ssp, 60761c42de6dSgd78059 uint8_t addr_space, 60771c42de6dSgd78059 uint8_t addr_start, 60781c42de6dSgd78059 uint8_t addr_end, 60791c42de6dSgd78059 char namebuf[][MAX_LOM2_NAME_STR], 60801c42de6dSgd78059 int numnames) 60811c42de6dSgd78059 { 60821c42de6dSgd78059 int i; 60831c42de6dSgd78059 int nameidx; 60841c42de6dSgd78059 int namemax; 60851c42de6dSgd78059 unsigned int addr_space_ptr; 60861c42de6dSgd78059 uint8_t this_char; 60871c42de6dSgd78059 60881c42de6dSgd78059 ASSERT(bscv_held(ssp)); 60891c42de6dSgd78059 6090*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'A', "bscv_read_env_name", 60911c42de6dSgd78059 "bscv_read_env_name, space %d, start 0x%x, end 0x%x, numnames %d", 60921c42de6dSgd78059 addr_space, addr_start, addr_end, numnames); 60931c42de6dSgd78059 60941c42de6dSgd78059 addr_space_ptr = addr_start; 60951c42de6dSgd78059 60961c42de6dSgd78059 for (i = 0; i < numnames; i++) { 60971c42de6dSgd78059 nameidx = 0; 60981c42de6dSgd78059 namemax = sizeof (namebuf[i]); 60991c42de6dSgd78059 bzero(namebuf[i], namemax); 61001c42de6dSgd78059 61011c42de6dSgd78059 while (addr_space_ptr <= addr_end) { 61021c42de6dSgd78059 /* 61031c42de6dSgd78059 * Read the current character. 61041c42de6dSgd78059 */ 61051c42de6dSgd78059 this_char = bscv_get8(ssp, chan_general, 61061c42de6dSgd78059 BSCVA(addr_space, addr_space_ptr)); 61071c42de6dSgd78059 61081c42de6dSgd78059 if (this_char == 0xff) { 61091c42de6dSgd78059 /* 61101c42de6dSgd78059 * Ran out of names - this must 61111c42de6dSgd78059 * be the end of the name. 61121c42de6dSgd78059 * This is really an error because 61131c42de6dSgd78059 * we have just seen either a non-NUL 61141c42de6dSgd78059 * terminated string or the number of 61151c42de6dSgd78059 * strings did not match what was 61161c42de6dSgd78059 * reported. 61171c42de6dSgd78059 */ 61181c42de6dSgd78059 break; 61191c42de6dSgd78059 } 61201c42de6dSgd78059 /* 61211c42de6dSgd78059 * We increment the buffer pointer now so that 61221c42de6dSgd78059 * it is ready for the next read 61231c42de6dSgd78059 */ 61241c42de6dSgd78059 addr_space_ptr++; 61251c42de6dSgd78059 61261c42de6dSgd78059 if (this_char == '\0') { 61271c42de6dSgd78059 /* Found end of string - done */ 61281c42de6dSgd78059 break; 61291c42de6dSgd78059 } 61301c42de6dSgd78059 if (nameidx < (namemax - 1)) { 61311c42de6dSgd78059 /* 61321c42de6dSgd78059 * Buffer not full - record character 61331c42de6dSgd78059 * NOTE we always leave room for the NUL 61341c42de6dSgd78059 * terminator. 61351c42de6dSgd78059 */ 61361c42de6dSgd78059 namebuf[i][nameidx++] = this_char; 61371c42de6dSgd78059 } 61381c42de6dSgd78059 } 61391c42de6dSgd78059 /* Ensure null termination */ 61401c42de6dSgd78059 namebuf[i][nameidx] = '\0'; 61411c42de6dSgd78059 } 61421c42de6dSgd78059 /* Clamp addr_space_ptr to 0xff because we return uint8_t */ 61431c42de6dSgd78059 if (addr_space_ptr > 0xff) { 61441c42de6dSgd78059 addr_space_ptr = 0xff; 61451c42de6dSgd78059 } 61461c42de6dSgd78059 return (addr_space_ptr); 61471c42de6dSgd78059 } 61481c42de6dSgd78059 61491c42de6dSgd78059 /* 61501c42de6dSgd78059 * function - bscv_setup_events 61511c42de6dSgd78059 * description - initialise the event reporting code 61521c42de6dSgd78059 * inputs - soft state ptr 61531c42de6dSgd78059 * outputs - DDI_SUCCESS or DDI_FAILURE 61541c42de6dSgd78059 */ 61551c42de6dSgd78059 61561c42de6dSgd78059 static void 61571c42de6dSgd78059 bscv_setup_events(bscv_soft_state_t *ssp) 61581c42de6dSgd78059 { 61591c42de6dSgd78059 uint8_t bits2set; 61601c42de6dSgd78059 uint8_t bits2clear; 61611c42de6dSgd78059 61621c42de6dSgd78059 ASSERT(bscv_held(ssp)); 61631c42de6dSgd78059 61641c42de6dSgd78059 /* 61651c42de6dSgd78059 * deal with event reporting - cover all cases 61661c42de6dSgd78059 */ 61671c42de6dSgd78059 61681c42de6dSgd78059 bits2set = 0; 61691c42de6dSgd78059 bits2clear = 0; 61701c42de6dSgd78059 if (ssp->serial_reporting == LOM_SER_EVENTS_ON) { 61711c42de6dSgd78059 bits2clear |= EBUS_ALARM_NOEVENTS; 61721c42de6dSgd78059 } else if (ssp->serial_reporting == LOM_SER_EVENTS_OFF) { 61731c42de6dSgd78059 bits2set |= EBUS_ALARM_NOEVENTS; 61741c42de6dSgd78059 } else if (ssp->serial_reporting == LOM_SER_EVENTS_DEF) { 61751c42de6dSgd78059 bits2set |= EBUS_ALARM_NOEVENTS; 61761c42de6dSgd78059 } 61771c42de6dSgd78059 bscv_setclear8_volatile(ssp, chan_general, EBUS_IDX_ALARM, 61781c42de6dSgd78059 bits2set, bits2clear); 61791c42de6dSgd78059 } 61801c42de6dSgd78059 61811c42de6dSgd78059 #ifdef __sparc 61821c42de6dSgd78059 /* 61831c42de6dSgd78059 * function - bscv_write_sig 61841c42de6dSgd78059 * description - write out a signature, taking care to deal with any strange 61851c42de6dSgd78059 * values for CPU ID 61861c42de6dSgd78059 * inputs - soft state ptr, signature 61871c42de6dSgd78059 * outputs - none 61881c42de6dSgd78059 */ 61891c42de6dSgd78059 static void 61901c42de6dSgd78059 bscv_write_sig(bscv_soft_state_t *ssp, bscv_sig_t s) 61911c42de6dSgd78059 { 61921c42de6dSgd78059 ASSERT(bscv_held(ssp)); 61931c42de6dSgd78059 61941c42de6dSgd78059 /* Upload the signature */ 61951c42de6dSgd78059 bscv_put32(ssp, chan_cpusig, 61961c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_SIG_MSB), 61971c42de6dSgd78059 s.sig_info.signature); 61981c42de6dSgd78059 61991c42de6dSgd78059 /* 62001c42de6dSgd78059 * We always write the CPU ID last because this tells the firmware 62011c42de6dSgd78059 * that the signature is fully uploaded and therefore to consume the 62021c42de6dSgd78059 * data. This is required since the signature is > 1 byte in size 62031c42de6dSgd78059 * and we transmit data in single bytes. 62041c42de6dSgd78059 */ 62051c42de6dSgd78059 if (s.cpu == ~0) { 62061c42de6dSgd78059 /* ~0 means the signature applies to any CPU. */ 62071c42de6dSgd78059 bscv_put8(ssp, chan_cpusig, 62081c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_ID), 62091c42de6dSgd78059 EBUS_ANY_CPU_ID); 62101c42de6dSgd78059 } else { 62111c42de6dSgd78059 if (s.cpu > 255) { 62121c42de6dSgd78059 /* 62131c42de6dSgd78059 * The CPU ID supplied is unexpectedly large. Lets 62141c42de6dSgd78059 * just use the bottom bits, in case other high order 62151c42de6dSgd78059 * bits are being used for special meaning. 62161c42de6dSgd78059 */ 62171c42de6dSgd78059 cmn_err(CE_WARN, "CPU Signature ID 0x%x > 255", s.cpu); 62181c42de6dSgd78059 s.cpu %= 256; 62191c42de6dSgd78059 cmn_err(CE_CONT, "using ID 0x%x instead ", s.cpu); 62201c42de6dSgd78059 } 62211c42de6dSgd78059 bscv_put8(ssp, chan_cpusig, 62221c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_ID), 62231c42de6dSgd78059 (uint8_t)s.cpu); 62241c42de6dSgd78059 } 62251c42de6dSgd78059 62261c42de6dSgd78059 ssp->last_sig = s; 62271c42de6dSgd78059 ssp->progress |= BSCV_SIG_SENT; 62281c42de6dSgd78059 } 62291c42de6dSgd78059 #endif /* __sparc */ 62301c42de6dSgd78059 62311c42de6dSgd78059 #if defined(__i386) || defined(__amd64) 62321c42de6dSgd78059 62331c42de6dSgd78059 /* 62341c42de6dSgd78059 * function - bscv_inform_bsc 62351c42de6dSgd78059 * description - inform bsc of driver state for logging purposes 62361c42de6dSgd78059 * inputs - driver soft state, state 62371c42de6dSgd78059 * outputs - none 62381c42de6dSgd78059 * 62391c42de6dSgd78059 */ 62401c42de6dSgd78059 static void 62411c42de6dSgd78059 bscv_inform_bsc(bscv_soft_state_t *ssp, uint32_t state) 62421c42de6dSgd78059 { 62431c42de6dSgd78059 ASSERT(bscv_held(ssp)); 62441c42de6dSgd78059 6245*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'X', "bscv_inform_bsc", 62461c42de6dSgd78059 "bscv_inform_bsc: state=%d", state); 62471c42de6dSgd78059 62481c42de6dSgd78059 bscv_put32(ssp, chan_general, 62491c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_SIG_MSB), state); 62501c42de6dSgd78059 bscv_put8(ssp, chan_cpusig, 62511c42de6dSgd78059 BSCVA(EBUS_CMD_SPACE_CPUSIG, EBUS_IDX11_CPU_ID), EBUS_ANY_CPU_ID); 62521c42de6dSgd78059 } 62531c42de6dSgd78059 62541c42de6dSgd78059 /* 62551c42de6dSgd78059 * function - bscv_watchdog_pat_request 62561c42de6dSgd78059 * description - request a heartbeat pat 62571c42de6dSgd78059 * inputs - timeout value in seconds 62581c42de6dSgd78059 * outputs - none 62591c42de6dSgd78059 */ 62601c42de6dSgd78059 static void 62611c42de6dSgd78059 bscv_watchdog_pat_request(void *arg) 62621c42de6dSgd78059 { 62631c42de6dSgd78059 bscv_soft_state_t *ssp = (bscv_soft_state_t *)arg; 62641c42de6dSgd78059 62651c42de6dSgd78059 bscv_wdog_do_pat(ssp); 62661c42de6dSgd78059 } 62671c42de6dSgd78059 62681c42de6dSgd78059 /* 62691c42de6dSgd78059 * function - bscv_watchdog_cfg_request 62701c42de6dSgd78059 * description - request configuration of the bsc hardware watchdog 62711c42de6dSgd78059 * inputs - new state (0=disabled, 1=enabled) 62721c42de6dSgd78059 * outputs - one if successful, zero if unsuccesful 62731c42de6dSgd78059 */ 62741c42de6dSgd78059 static void 62751c42de6dSgd78059 bscv_watchdog_cfg_request(bscv_soft_state_t *ssp, uint8_t new_state) 62761c42de6dSgd78059 { 62771c42de6dSgd78059 ASSERT(new_state == WDOG_ON || new_state == WDOG_OFF); 62781c42de6dSgd78059 62791c42de6dSgd78059 watchdog_activated = new_state; 6280*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'X', "bscv_watchdog_cfg_request", 62811c42de6dSgd78059 "watchdog_activated=%d", watchdog_activated); 62821c42de6dSgd78059 bscv_write_wdog_cfg(ssp, 62831c42de6dSgd78059 bscv_watchdog_timeout_seconds, 62841c42de6dSgd78059 new_state, 62851c42de6dSgd78059 wdog_reset_on_timeout); 62861c42de6dSgd78059 } 62871c42de6dSgd78059 62881c42de6dSgd78059 /* 62891c42de6dSgd78059 * function - bscv_set_watchdog_timer 62901c42de6dSgd78059 * description - setup the heartbeat timeout value 62911c42de6dSgd78059 * inputs - timeout value in seconds 62921c42de6dSgd78059 * outputs - zero if the value was not changed 62931c42de6dSgd78059 * otherwise the current value 62941c42de6dSgd78059 */ 62951c42de6dSgd78059 static uint_t 62961c42de6dSgd78059 bscv_set_watchdog_timer(bscv_soft_state_t *ssp, uint_t timeoutval) 62971c42de6dSgd78059 { 6298*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'X', "bscv_set_watchdog_timer:", 62991c42de6dSgd78059 "timeout=%d", timeoutval); 63001c42de6dSgd78059 63011c42de6dSgd78059 /* 63021c42de6dSgd78059 * We get started during bscv_attach only 63031c42de6dSgd78059 * if bscv_watchdog_enable is set. 63041c42de6dSgd78059 */ 63051c42de6dSgd78059 if (bscv_watchdog_available && (!watchdog_activated || 63061c42de6dSgd78059 (watchdog_activated && 63071c42de6dSgd78059 (timeoutval != bscv_watchdog_timeout_seconds)))) { 63081c42de6dSgd78059 bscv_watchdog_timeout_seconds = timeoutval; 63091c42de6dSgd78059 bscv_watchdog_cfg_request(ssp, WDOG_ON); 63101c42de6dSgd78059 return (bscv_watchdog_timeout_seconds); 63111c42de6dSgd78059 } 63121c42de6dSgd78059 return (0); 63131c42de6dSgd78059 } 63141c42de6dSgd78059 63151c42de6dSgd78059 /* 63161c42de6dSgd78059 * function - bscv_clear_watchdog_timer 63171c42de6dSgd78059 * description - add the watchdog patter cyclic 63181c42de6dSgd78059 * inputs - driver soft state 63191c42de6dSgd78059 * outputs - value of watchdog timeout in seconds 63201c42de6dSgd78059 * 63211c42de6dSgd78059 * This function is a copy of the SPARC implementation 63221c42de6dSgd78059 * in the todblade clock driver. 63231c42de6dSgd78059 */ 63241c42de6dSgd78059 static void 63251c42de6dSgd78059 bscv_clear_watchdog_timer(bscv_soft_state_t *ssp) 63261c42de6dSgd78059 { 6327*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'X', "bscv_clear_watchdog_timer", ""); 63281c42de6dSgd78059 63291c42de6dSgd78059 if (bscv_watchdog_available && watchdog_activated) { 63301c42de6dSgd78059 bscv_watchdog_enable = 0; 63311c42de6dSgd78059 bscv_watchdog_cfg_request(ssp, WDOG_OFF); 63321c42de6dSgd78059 } 63331c42de6dSgd78059 } 63341c42de6dSgd78059 63351c42de6dSgd78059 /* 63361c42de6dSgd78059 * function - bscv_panic_callback 63371c42de6dSgd78059 * description - called when we panic so we can disabled the watchdog 63381c42de6dSgd78059 * inputs - driver soft state pointer 63391c42de6dSgd78059 * outputs - DDI_SUCCESS 63401c42de6dSgd78059 */ 63411c42de6dSgd78059 /*ARGSUSED1*/ 63421c42de6dSgd78059 static boolean_t 63431c42de6dSgd78059 bscv_panic_callback(void *arg, int code) 63441c42de6dSgd78059 { 63451c42de6dSgd78059 bscv_soft_state_t *ssp = (bscv_soft_state_t *)arg; 63461c42de6dSgd78059 6347*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'X', "bscv_panic_callback", 63481c42de6dSgd78059 "disabling watchdog"); 63491c42de6dSgd78059 63501c42de6dSgd78059 bscv_clear_watchdog_timer(ssp); 63511c42de6dSgd78059 /* 63521c42de6dSgd78059 * We dont get interrupts during the panic callback. But bscbus 63531c42de6dSgd78059 * takes care of all this 63541c42de6dSgd78059 */ 63551c42de6dSgd78059 bscv_full_stop(ssp); 63561c42de6dSgd78059 return (DDI_SUCCESS); 63571c42de6dSgd78059 } 63581c42de6dSgd78059 63591c42de6dSgd78059 /* 63601c42de6dSgd78059 * function - bscv_watchdog_cyclic_add 63611c42de6dSgd78059 * description - add the watchdog patter cyclic 63621c42de6dSgd78059 * inputs - driver soft state 63631c42de6dSgd78059 * outputs - none 63641c42de6dSgd78059 */ 63651c42de6dSgd78059 static void 63661c42de6dSgd78059 bscv_watchdog_cyclic_add(bscv_soft_state_t *ssp) 63671c42de6dSgd78059 { 6368dd4eeefdSeota if (ssp->periodic_id != NULL) { 63691c42de6dSgd78059 return; 63701c42de6dSgd78059 } 63711c42de6dSgd78059 6372dd4eeefdSeota ssp->periodic_id = ddi_periodic_add(bscv_watchdog_pat_request, ssp, 6373dd4eeefdSeota WATCHDOG_PAT_INTERVAL, DDI_IPL_10); 63741c42de6dSgd78059 6375*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'X', "bscv_watchdog_cyclic_add:", 63761c42de6dSgd78059 "cyclic added"); 63771c42de6dSgd78059 } 63781c42de6dSgd78059 63791c42de6dSgd78059 /* 63801c42de6dSgd78059 * function - bscv_watchdog_cyclic_remove 63811c42de6dSgd78059 * description - remove the watchdog patter cyclic 63821c42de6dSgd78059 * inputs - soft state ptr 63831c42de6dSgd78059 * outputs - none 63841c42de6dSgd78059 */ 63851c42de6dSgd78059 static void 63861c42de6dSgd78059 bscv_watchdog_cyclic_remove(bscv_soft_state_t *ssp) 63871c42de6dSgd78059 { 6388dd4eeefdSeota if (ssp->periodic_id == NULL) { 63891c42de6dSgd78059 return; 63901c42de6dSgd78059 } 6391dd4eeefdSeota ddi_periodic_delete(ssp->periodic_id); 6392dd4eeefdSeota ssp->periodic_id = NULL; 6393*1af83355Sandrew.rutz@sun.com BSCV_TRACE(ssp, 'X', "bscv_watchdog_cyclic_remove:", 63941c42de6dSgd78059 "cyclic removed"); 63951c42de6dSgd78059 } 63961c42de6dSgd78059 #endif /* __i386 || __amd64 */ 63971c42de6dSgd78059 63981c42de6dSgd78059 63991c42de6dSgd78059 /* 64001c42de6dSgd78059 * General utility routines ... 64011c42de6dSgd78059 */ 64021c42de6dSgd78059 64031c42de6dSgd78059 #ifdef DEBUG 64041c42de6dSgd78059 64051c42de6dSgd78059 static void 64061c42de6dSgd78059 bscv_trace(bscv_soft_state_t *ssp, char code, const char *caller, 64071c42de6dSgd78059 const char *fmt, ...) 64081c42de6dSgd78059 { 64091c42de6dSgd78059 char buf[256]; 64101c42de6dSgd78059 char *p; 64111c42de6dSgd78059 va_list va; 64121c42de6dSgd78059 64131c42de6dSgd78059 if (ssp->debug & (1 << (code-'@'))) { 64141c42de6dSgd78059 p = buf; 64151c42de6dSgd78059 (void) snprintf(p, sizeof (buf) - (p - buf), 64161c42de6dSgd78059 "%s/%s: ", MYNAME, caller); 64171c42de6dSgd78059 p += strlen(p); 64181c42de6dSgd78059 64191c42de6dSgd78059 va_start(va, fmt); 64201c42de6dSgd78059 (void) vsnprintf(p, sizeof (buf) - (p - buf), fmt, va); 64211c42de6dSgd78059 va_end(va); 64221c42de6dSgd78059 64231c42de6dSgd78059 buf[sizeof (buf) - 1] = '\0'; 64241c42de6dSgd78059 (void) strlog((short)ssp->majornum, (short)ssp->minornum, code, 64251c42de6dSgd78059 SL_TRACE, buf); 64261c42de6dSgd78059 } 64271c42de6dSgd78059 } 64281c42de6dSgd78059 64291c42de6dSgd78059 #else /* DEBUG */ 64301c42de6dSgd78059 64311c42de6dSgd78059 _NOTE(ARGSUSED(0)) 64321c42de6dSgd78059 static void 64331c42de6dSgd78059 bscv_trace(bscv_soft_state_t *ssp, char code, const char *caller, 64341c42de6dSgd78059 const char *fmt, ...) 64351c42de6dSgd78059 { 64361c42de6dSgd78059 } 64371c42de6dSgd78059 64381c42de6dSgd78059 #endif /* DEBUG */ 6439