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