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