xref: /titanic_51/usr/src/uts/sun4u/montecarlo/io/scsb.c (revision 07d06da50d310a325b457d6330165aebab1e0064)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
23*07d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel /*
2803831d35Sstevel  * Netra ct800 and Netra ct400 (MonteCarlo/Tonga)
2903831d35Sstevel  * System Controller and Status Boards STREAMS driver.
3003831d35Sstevel  *
3103831d35Sstevel  * This driver handles all communications with the Netra ct400 and ct800
3203831d35Sstevel  * System Controller Boards.
3303831d35Sstevel  * I/O to the SCB is through the PCF8584 I2C controller.
3403831d35Sstevel  * The SCB I2C interface and driver interface are provided by the
3503831d35Sstevel  * Xilinx XCS40XL.
3603831d35Sstevel  *
3703831d35Sstevel  * N.B.: The design choice of using STREAMS was dictated because
3803831d35Sstevel  *	 the original system monitor card had to multiplex 2 pcf8574's
3903831d35Sstevel  *	 as one device.
4003831d35Sstevel  */
4103831d35Sstevel 
4203831d35Sstevel #include <sys/types.h>
4303831d35Sstevel #include <sys/param.h>
4403831d35Sstevel #include <sys/cred.h>
4503831d35Sstevel #include <sys/log.h>
4603831d35Sstevel #include <sys/uio.h>
4703831d35Sstevel #include <sys/stat.h>
4803831d35Sstevel #include <sys/vnode.h>
4903831d35Sstevel #include <sys/file.h>
5003831d35Sstevel #include <sys/open.h>
5103831d35Sstevel #include <sys/kmem.h>
5203831d35Sstevel #include <sys/kstat.h>
5303831d35Sstevel #include <sys/signal.h>
5403831d35Sstevel 
5503831d35Sstevel #include <sys/stream.h>
5603831d35Sstevel #include <sys/strsubr.h>
5703831d35Sstevel #include <sys/strsun.h>
5803831d35Sstevel #include <sys/poll.h>
5903831d35Sstevel 
6003831d35Sstevel #include <sys/debug.h>
6103831d35Sstevel 
6203831d35Sstevel #include <sys/conf.h>
6303831d35Sstevel #include <sys/ddi.h>
6403831d35Sstevel #include <sys/sunddi.h>
6503831d35Sstevel #include <sys/modctl.h>
6603831d35Sstevel 
6703831d35Sstevel #include <sys/i2c/misc/i2c_svc.h>
6803831d35Sstevel 
6903831d35Sstevel #include <sys/mct_topology.h>
7003831d35Sstevel #include <sys/netract_gen.h>
7103831d35Sstevel #include <sys/scsbioctl.h>
7203831d35Sstevel #include <sys/scsb.h>
7303831d35Sstevel #include <sys/scsb_cbi.h>
7403831d35Sstevel 
7503831d35Sstevel #include <sys/hotplug/hpctrl.h>
7603831d35Sstevel #include <sys/hsc.h>
7703831d35Sstevel #include <sys/hscimpl.h>
7803831d35Sstevel 
7903831d35Sstevel #define	CPCI_HOTSWAP_SUPPORT
8003831d35Sstevel 
8103831d35Sstevel #define	ALARM_CARD_ON_SLOT	1
8203831d35Sstevel #define	SCSB_FRU_OP_GET_REG	1
8303831d35Sstevel #define	SCSB_FRU_OP_SET_REGBIT	2
8403831d35Sstevel #define	SCSB_FRU_OP_GET_BITVAL	3
8503831d35Sstevel #define	SCSB_FRU_OP_GET_REGDATA	4
8603831d35Sstevel 
8703831d35Sstevel /*
8803831d35Sstevel  * (internal only)
8903831d35Sstevel  * scsb build version format is "CCYYMMDD"
9003831d35Sstevel  * for integer compares.
9103831d35Sstevel  */
9203831d35Sstevel #define	SCSB_BUILD_VERSION	"20001206"
9303831d35Sstevel 
9403831d35Sstevel #define	MUTEX_UNINIT	0
9503831d35Sstevel #define	MUTEX_INIT	2
9603831d35Sstevel 
9703831d35Sstevel static	int scsb_err_threshold = 0; /* max allowed i2c errors */
9803831d35Sstevel static	int scsb_freeze_count = 3; /* #I2C errors to indicate SCB removal */
9903831d35Sstevel static	int scsb_shutdown_count = 5; /* #polls before passing shutdown evt */
10003831d35Sstevel static	int scsb_in_postintr = 0;	/* 1 if scsb is processing intr */
10103831d35Sstevel static	kmutex_t *scb_intr_mutex;	 /* SCSB interrupt mutex */
10203831d35Sstevel static	int	nct_mutex_init = MUTEX_UNINIT;
10303831d35Sstevel 
10403831d35Sstevel extern	int	scsb_hsc_board_healthy();
10503831d35Sstevel 
10603831d35Sstevel static	char	*scsb_name = SCSB_DEVICE_NAME;
10703831d35Sstevel static	char	*scsb_clone_name = SCSB_DEVICE_NAME "clone";
10803831d35Sstevel static	char	*scsb_build_version = SCSB_BUILD_VERSION;
10903831d35Sstevel /*
11003831d35Sstevel  * cb_ops section of scsb driver.
11103831d35Sstevel  */
11203831d35Sstevel static	int	sm_open(queue_t *, dev_t *, int, int, cred_t *);
11303831d35Sstevel static	int	sm_close(queue_t *, int, int, cred_t *);
11403831d35Sstevel 
11503831d35Sstevel static	int	sm_rput(queue_t *, mblk_t *);	/* from i2c below */
11603831d35Sstevel static	int	sm_wput(queue_t *, mblk_t *);	/* from above */
11703831d35Sstevel 
11803831d35Sstevel uint_t	scsb_intr_preprocess(caddr_t arg);
11903831d35Sstevel void	scsb_intr(caddr_t arg);
12003831d35Sstevel static	void	smf_ioctl(queue_t *, mblk_t *);
12103831d35Sstevel static	void	sm_ioc_rdwr(queue_t *, mblk_t *, int);
12203831d35Sstevel 
12303831d35Sstevel static int scsb_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
12403831d35Sstevel static int scsb_attach(dev_info_t *, ddi_attach_cmd_t);
12503831d35Sstevel static int scsb_detach(dev_info_t *, ddi_detach_cmd_t);
12603831d35Sstevel static int initialize_scb(scsb_state_t *);
12703831d35Sstevel 
12803831d35Sstevel static dev_info_t *scsb_dip;		/* private copy of devinfo pointer */
12903831d35Sstevel 
13003831d35Sstevel static struct module_info info = {
13103831d35Sstevel 	0, SCSB_DEVICE_NAME, 0, INFPSZ, 512, 128
13203831d35Sstevel };
13303831d35Sstevel 
13403831d35Sstevel static struct qinit sm_rinit = {
13503831d35Sstevel 	sm_rput, NULL, sm_open, sm_close, NULL, &info
13603831d35Sstevel };
13703831d35Sstevel 
13803831d35Sstevel static struct qinit sm_winit = {
13903831d35Sstevel 	sm_wput, NULL, sm_open, sm_close, NULL, &info
14003831d35Sstevel };
14103831d35Sstevel 
14203831d35Sstevel struct streamtab sm_st  = {
14303831d35Sstevel 	&sm_rinit, &sm_winit, NULL, NULL
14403831d35Sstevel };
14503831d35Sstevel 
14603831d35Sstevel static struct cb_ops scsb_cb_ops = {
14703831d35Sstevel 
14803831d35Sstevel 	nulldev,		/* open */
14903831d35Sstevel 	nulldev,		/* close */
15003831d35Sstevel 	nodev,			/* strategy */
15103831d35Sstevel 	nodev,			/* print */
15203831d35Sstevel 	nodev,			/* dump */
15303831d35Sstevel 	nodev,			/* read */
15403831d35Sstevel 	nodev,			/* write */
15503831d35Sstevel 	nodev,			/* ioctl */
15603831d35Sstevel 	nodev,			/* devmap */
15703831d35Sstevel 	nodev,			/* mmap */
15803831d35Sstevel 	nodev, 			/* segmap */
15903831d35Sstevel 	nochpoll,		/* poll */
16003831d35Sstevel 	ddi_prop_op,		/* cb_prop_op */
16103831d35Sstevel 	&sm_st,			/* streamtab  */
16203831d35Sstevel 	D_MP,			/* Driver compatibility flag */
16303831d35Sstevel 	CB_REV,				/* rev */
16403831d35Sstevel 	nodev,				/* int (*cb_aread)() */
16503831d35Sstevel 	nodev				/* int (*cb_awrite)() */
16603831d35Sstevel };
16703831d35Sstevel 
16803831d35Sstevel static struct dev_ops scsb_ops = {
16903831d35Sstevel 
17003831d35Sstevel 	DEVO_REV,		/* devo_rev, */
17103831d35Sstevel 	0,			/* refcnt  */
17203831d35Sstevel 	scsb_info,		/* info */
17303831d35Sstevel 	nulldev,		/* identify */
17403831d35Sstevel 	nulldev,		/* probe */
17503831d35Sstevel 	scsb_attach,		/* attach */
17603831d35Sstevel 	scsb_detach,		/* detach */
17703831d35Sstevel 	nodev,			/* reset */
17803831d35Sstevel 	&scsb_cb_ops,		/* driver operations */
17919397407SSherry Moore 	(struct bus_ops *)0,	/* bus operations */
18019397407SSherry Moore 	NULL,			/* power */
18119397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
18203831d35Sstevel };
18303831d35Sstevel 
18403831d35Sstevel /*
18503831d35Sstevel  * Module linkage information for the kernel.
18603831d35Sstevel  */
18703831d35Sstevel 
18803831d35Sstevel static struct modldrv modldrv = {
18903831d35Sstevel 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
19003831d35Sstevel #ifdef DEBUG
19103831d35Sstevel 	"SCB/SSB driver DBG" SCSB_BUILD_VERSION,
19203831d35Sstevel #else
19319397407SSherry Moore 	"v1.33 Netra ct System Control/Status Board driver",
19403831d35Sstevel #endif
19503831d35Sstevel 	&scsb_ops,	/* driver ops */
19603831d35Sstevel };
19703831d35Sstevel 
19803831d35Sstevel static struct modlinkage modlinkage = {
19903831d35Sstevel 	MODREV_1,
20003831d35Sstevel 	(void *)&modldrv,
20103831d35Sstevel 	NULL
20203831d35Sstevel };
20303831d35Sstevel 
20403831d35Sstevel /*
20503831d35Sstevel  * local declarations and definitions
20603831d35Sstevel  */
20703831d35Sstevel #if defined(DEBUG)
20803831d35Sstevel 	uint32_t	scsb_debug = 0x00000000;
20903831d35Sstevel #else
21003831d35Sstevel static	uint32_t	scsb_debug = 0;
21103831d35Sstevel #endif
21203831d35Sstevel 
21303831d35Sstevel static	hrtime_t scb_pre_s, scb_pre_e, scb_post_s, scb_post_e;
21403831d35Sstevel 
21503831d35Sstevel static	int		scsb_pil = SCSB_INTR_PIL;
21603831d35Sstevel static	int		hsc_pil  = SCSB_INTR_PIL;
21703831d35Sstevel static 	void		*scsb_state;
21803831d35Sstevel static 	uint32_t	scsb_global_state;
21903831d35Sstevel static 	uint32_t	scsb_event_code;	/* for event polling */
22003831d35Sstevel static 	struct system_info	mct_system_info;
22103831d35Sstevel static 	int		scsb_healthy_poll_count = 16;
22203831d35Sstevel 
22303831d35Sstevel static fru_id_t		fru_id_table[MCT_MAX_FRUS];
22403831d35Sstevel static uchar_t		scb_intr_regs[SCTRL_MAX_GROUP_NUMREGS];
22503831d35Sstevel 
22603831d35Sstevel static	uint32_t	evc_fifo[EVC_FIFO_SIZE];
22703831d35Sstevel static	uint32_t	evc_fifo_count = 0;
22803831d35Sstevel static	uint32_t	*evc_rptr = evc_fifo;
22903831d35Sstevel static	uint32_t	*evc_wptr = evc_fifo;
23003831d35Sstevel static	void		*evc_procs[EVC_PROCS_MAX];
23103831d35Sstevel static	int		evc_proc_count = 0;
23203831d35Sstevel static timeout_id_t scsb_intr_tid;
23303831d35Sstevel 
23403831d35Sstevel int nct_i2c_transfer(i2c_client_hdl_t i2c_hdl, i2c_transfer_t *i2c_tran);
23503831d35Sstevel 
23603831d35Sstevel /*
23703831d35Sstevel  * kstat functions
23803831d35Sstevel  */
23903831d35Sstevel static	int	scsb_alloc_kstats(scsb_state_t *);
24003831d35Sstevel static	void	scsb_free_kstats(scsb_state_t *);
24103831d35Sstevel static	int	update_ks_leddata(kstat_t *, int);
24203831d35Sstevel static	int	update_ks_state(kstat_t *, int);
24303831d35Sstevel static	int	update_ks_topology(kstat_t *, int);
24403831d35Sstevel static	int	update_ks_evcreg(kstat_t *, int);
24503831d35Sstevel 
24603831d35Sstevel /*
24703831d35Sstevel  * local functions
24803831d35Sstevel  */
24903831d35Sstevel static	void	free_resources(dev_info_t *, scsb_state_t *, int);
25003831d35Sstevel static	i2c_transfer_t	*scsb_alloc_i2ctx(i2c_client_hdl_t, uint_t);
25103831d35Sstevel static	fru_info_t	*find_fru_info(fru_id_t fru_id);
25203831d35Sstevel static	int	scsb_fake_intr(scsb_state_t *, uint32_t);
25303831d35Sstevel static	int	scsb_get_status(scsb_state_t *, scsb_status_t *);
25403831d35Sstevel static	int	scsb_leds_switch(scsb_state_t *, scsb_ustate_t);
25503831d35Sstevel static	void	scsb_freeze(scsb_state_t *scsb);
25603831d35Sstevel static	void	scsb_freeze_check(scsb_state_t *scsb);
25703831d35Sstevel static	void	scsb_restore(scsb_state_t *scsb);
25803831d35Sstevel static	int	scsb_polled_int(scsb_state_t *, int, uint32_t *);
25903831d35Sstevel static	int	scsb_check_config_status(scsb_state_t *scsb);
26003831d35Sstevel static	int	scsb_set_scfg_pres_leds(scsb_state_t *, fru_info_t *);
26103831d35Sstevel static	void	scsb_set_topology(scsb_state_t *);
26203831d35Sstevel static	void	scsb_free_topology(scsb_state_t *);
26303831d35Sstevel int	scsb_read_bhealthy(scsb_state_t *scsb);
26403831d35Sstevel int	scsb_read_slot_health(scsb_state_t *, int);
26503831d35Sstevel static	void	tonga_slotnum_check(scsb_state_t *scsb, scsb_uinfo_t *suip);
26603831d35Sstevel static	int	tonga_psl_to_ssl(scsb_state_t *scsb, int slotnum);
26703831d35Sstevel static	uchar_t	tonga_slotnum_led_shift(scsb_state_t *scsb, uchar_t data);
26803831d35Sstevel static	int	scsb_clear_intptrs(scsb_state_t *scsb);
26903831d35Sstevel static	int	scsb_clear_intmasks(scsb_state_t *scsb);
27003831d35Sstevel static	int	scsb_setall_intmasks(scsb_state_t *scsb);
27103831d35Sstevel static	int	scsb_write_mask(scsb_state_t *, uchar_t, uchar_t, uchar_t,
27203831d35Sstevel 				uchar_t);
27303831d35Sstevel static	int	scsb_rdwr_register(scsb_state_t *, int, uchar_t, int,
27403831d35Sstevel 				uchar_t *, int);
27503831d35Sstevel static	int	scsb_readall_regs(scsb_state_t *);
27603831d35Sstevel static	int	scsb_get_led_regnum(scsb_state_t *, scsb_uinfo_t *, uchar_t *,
27703831d35Sstevel 				int *, scsb_led_t);
27803831d35Sstevel static	void	scsb_free_i2ctx(i2c_client_hdl_t, i2c_transfer_t *);
27903831d35Sstevel static	void	check_fru_info(scsb_state_t *, int);
28003831d35Sstevel static	void	update_fru_info(scsb_state_t *, fru_info_t *);
28103831d35Sstevel static	int	event_to_index(uint32_t);
28203831d35Sstevel static	void	add_event_code(scsb_state_t *, uint32_t);
28303831d35Sstevel static	uint32_t	del_event_code();
28403831d35Sstevel static	uint32_t	get_event_code();
28503831d35Sstevel static	int	add_event_proc(scsb_state_t *, pid_t);
28603831d35Sstevel static	int	del_event_proc(scsb_state_t *, pid_t);
28703831d35Sstevel static	void	rew_event_proc(scsb_state_t *);
28803831d35Sstevel static	int	event_proc_count(scsb_state_t *);
28903831d35Sstevel static	int	find_evc_proc(pid_t pid);
29003831d35Sstevel static	void	signal_evc_procs(scsb_state_t *);
29103831d35Sstevel static	int	check_event_procs();
29203831d35Sstevel static	int	scsb_is_alarm_card_slot(scsb_state_t *, int);
29303831d35Sstevel 	int	scsb_get_slot_state(scsb_state_t *, int, int *);
29403831d35Sstevel static	int	scsb_fru_op(scsb_state_t *, scsb_utype_t, int, int, int);
29503831d35Sstevel static	int	scsb_queue_put(queue_t *, int, uint32_t *, char *);
29603831d35Sstevel static	int	scsb_queue_ops(scsb_state_t *, int, int, void *, char *);
29703831d35Sstevel static	int scsb_blind_read(scsb_state_t *, int, uchar_t, int, uchar_t *, int);
29803831d35Sstevel static	int scsb_toggle_psmint(scsb_state_t *, int);
29903831d35Sstevel static	int scsb_quiesce_psmint(scsb_state_t *);
30003831d35Sstevel static	int scsb_invoke_intr_chain();
30103831d35Sstevel int	scsb_intr_register(int (*)(void *), void *, fru_id_t);
30203831d35Sstevel void scsb_intr_unregister(fru_id_t);
30303831d35Sstevel 
30403831d35Sstevel #ifdef	DEBUG
30503831d35Sstevel static	void	mct_topology_dump(scsb_state_t *, int);
30603831d35Sstevel static	void	scsb_failing_event(scsb_state_t *scsb);
30703831d35Sstevel #endif
30803831d35Sstevel 
30903831d35Sstevel int
31003831d35Sstevel _init(void)
31103831d35Sstevel {
31203831d35Sstevel 	int	i, status;
31303831d35Sstevel 
31403831d35Sstevel 	if (scsb_debug & 0x0005)
31503831d35Sstevel 		cmn_err(CE_NOTE, "scsb: _init()");
316*07d06da5SSurya Prakki 	(void) ddi_soft_state_init(&scsb_state, sizeof (scsb_state_t),
31703831d35Sstevel 	    SCSB_NO_OF_BOARDS);
318*07d06da5SSurya Prakki 	(void) hsc_init();
31903831d35Sstevel 	if ((status = mod_install(&modlinkage)) != 0) {
32003831d35Sstevel 		if (scsb_debug & 0x0006)
32103831d35Sstevel 			cmn_err(CE_NOTE, "scsb: _init(): mod_install failed");
32203831d35Sstevel 		ddi_soft_state_fini(&scsb_state);
323*07d06da5SSurya Prakki 		(void) hsc_fini();
32403831d35Sstevel 		return (status);
32503831d35Sstevel 	}
32603831d35Sstevel 	/*
32703831d35Sstevel 	 * initialize the FRU ID Table, using real FRU IDs where available
32803831d35Sstevel 	 * such as I2C Addresses for FRUs with I2C support
32903831d35Sstevel 	 */
33003831d35Sstevel 	for (i = 0; i < MCT_MAX_FRUS; ++i)
33103831d35Sstevel 		fru_id_table[i] = i + 1;
33203831d35Sstevel 	fru_id_table[event_to_index(SCTRL_EVENT_PS1)] = (fru_id_t)MCT_I2C_PS1;
33303831d35Sstevel 	fru_id_table[event_to_index(SCTRL_EVENT_PS2)] = (fru_id_t)MCT_I2C_PS2;
33403831d35Sstevel 	fru_id_table[event_to_index(SCTRL_EVENT_FAN1)] = (fru_id_t)MCT_I2C_FAN1;
33503831d35Sstevel 	fru_id_table[event_to_index(SCTRL_EVENT_FAN2)] = (fru_id_t)MCT_I2C_FAN2;
33603831d35Sstevel 	fru_id_table[event_to_index(SCTRL_EVENT_FAN3)] = (fru_id_t)MCT_I2C_FAN3;
33703831d35Sstevel 	fru_id_table[event_to_index(SCTRL_EVENT_SCB)] = (fru_id_t)MCT_I2C_SCB;
33803831d35Sstevel 	return (status);
33903831d35Sstevel }
34003831d35Sstevel 
34103831d35Sstevel int
34203831d35Sstevel _fini(void)
34303831d35Sstevel {
34403831d35Sstevel 	int	status;
34503831d35Sstevel 
34603831d35Sstevel 	if (scsb_debug & 0x0005)
34703831d35Sstevel 		cmn_err(CE_NOTE, "scsb: _fini()");
34803831d35Sstevel 
34903831d35Sstevel 	if ((status = mod_remove(&modlinkage)) == 0) {
35003831d35Sstevel 		ddi_soft_state_fini(&scsb_state);
351*07d06da5SSurya Prakki 		(void) hsc_fini();
35203831d35Sstevel 	}
35303831d35Sstevel 	if (scsb_debug & 0x0006)
35403831d35Sstevel 		cmn_err(CE_NOTE, "scsb: _fini, error %x\n", status);
35503831d35Sstevel 
35603831d35Sstevel 	return (status);
35703831d35Sstevel }
35803831d35Sstevel 
35903831d35Sstevel int
36003831d35Sstevel _info(struct modinfo *modinfop)
36103831d35Sstevel {
36203831d35Sstevel 	if (scsb_debug & 0x0005)
36303831d35Sstevel 		cmn_err(CE_NOTE, "scsb: _info()");
36403831d35Sstevel 
36503831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
36603831d35Sstevel }
36703831d35Sstevel 
36803831d35Sstevel static int
36903831d35Sstevel scsb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
37003831d35Sstevel {
37103831d35Sstevel 	int		instance;
37203831d35Sstevel 	scsb_state_t	*scsb;
37303831d35Sstevel 	register int	i;
37403831d35Sstevel 	int		*regs;
37503831d35Sstevel 	uint_t		len;
37603831d35Sstevel 	uchar_t		reg, wdata, rmask;
37703831d35Sstevel 
37803831d35Sstevel 	instance = ddi_get_instance(dip);
37903831d35Sstevel 
38003831d35Sstevel 	if (scsb_debug & 0x0005)
38103831d35Sstevel 		cmn_err(CE_NOTE, "scsb_attach[%d]", instance);
38203831d35Sstevel 
38303831d35Sstevel 	if (cmd != DDI_ATTACH) {
38403831d35Sstevel 		if (scsb_debug & 0x0006)
38503831d35Sstevel 			cmn_err(CE_NOTE,
38603831d35Sstevel 			    "scsb_attach[%d]: cmd 0x%x != DDI_ATTACH",
38703831d35Sstevel 			    instance, cmd);
38803831d35Sstevel 		return (DDI_FAILURE);
38903831d35Sstevel 	}
39003831d35Sstevel 
39103831d35Sstevel 	if (ddi_soft_state_zalloc(scsb_state, instance) != DDI_SUCCESS) {
39203831d35Sstevel 		cmn_err(CE_WARN, "scsb%d: cannot allocate soft state",
39303831d35Sstevel 		    instance);
39403831d35Sstevel 		return (DDI_FAILURE);
39503831d35Sstevel 	}
39603831d35Sstevel 
39703831d35Sstevel 	scsb = (scsb_state_t *)ddi_get_soft_state(scsb_state, instance);
39803831d35Sstevel 	if (scsb == NULL) {
39903831d35Sstevel 		cmn_err(CE_WARN, "scsb%d: cannot get soft state", instance);
40003831d35Sstevel 		ddi_soft_state_free(scsb_state, instance);
40103831d35Sstevel 		return (DDI_FAILURE);
40203831d35Sstevel 	}
40303831d35Sstevel 	scsb->scsb_instance = instance;
40403831d35Sstevel 	scsb->scsb_state = 0;	/* just checking strange mutex behavior */
40503831d35Sstevel 
40603831d35Sstevel 	/*
40703831d35Sstevel 	 * make sure this is the SCB's known address
40803831d35Sstevel 	 */
40903831d35Sstevel 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
41003831d35Sstevel 	    "reg", &regs, &len) != DDI_PROP_SUCCESS) {
41103831d35Sstevel 		cmn_err(CE_WARN,
41203831d35Sstevel 		    "scsb%d: Failed to get \"reg\" property", instance);
41303831d35Sstevel 		ddi_soft_state_free(scsb_state, instance);
41403831d35Sstevel 		return (DDI_FAILURE);
41503831d35Sstevel 	}
41603831d35Sstevel 	scsb->scsb_i2c_addr = regs[1] & SCSB_I2C_ADDR_MASK;
41703831d35Sstevel 	if (scsb->scsb_i2c_addr != SCSB_I2C_ADDR) {
41803831d35Sstevel 		cmn_err(CE_WARN, "scsb%d: I2C Addr reg %x %x must be %x",
41903831d35Sstevel 		    instance, regs[0], regs[1], SCSB_I2C_ADDR);
42003831d35Sstevel 		ddi_soft_state_free(scsb_state, instance);
42103831d35Sstevel 		ddi_prop_free(regs);
42203831d35Sstevel 		return (DDI_FAILURE);
42303831d35Sstevel 	}
42403831d35Sstevel 	/* done with array lookup, free resource */
42503831d35Sstevel 	ddi_prop_free(regs);
42603831d35Sstevel 	/*
42703831d35Sstevel 	 * initialize synchronization mutex and condition var.
42803831d35Sstevel 	 * for this instance.
42903831d35Sstevel 	 */
43003831d35Sstevel 	mutex_init(&scsb->scsb_mutex, NULL, MUTEX_DRIVER, NULL);
43103831d35Sstevel 	scsb->scsb_state |= SCSB_UMUTEX;
43203831d35Sstevel 	cv_init(&scsb->scsb_cv, NULL, CV_DRIVER, NULL);
43303831d35Sstevel 	scsb->scsb_state |= SCSB_CONDVAR;
43403831d35Sstevel 
43503831d35Sstevel 	/*
43603831d35Sstevel 	 * 1. Read interrupt property of the board and register its handler.
43703831d35Sstevel 	 * 2. Get scsb private handle for communication via I2C Services.
43803831d35Sstevel 	 * 3. Allocate and save an i2c_transfer_t for I2C transfers.
43903831d35Sstevel 	 */
44003831d35Sstevel 	/* 1 */
44103831d35Sstevel 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip,
44203831d35Sstevel 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
44303831d35Sstevel 	    "interrupt-priorities") != 1) {
44403831d35Sstevel 		int tmp[2];
44503831d35Sstevel 		tmp[0] = scsb_pil;
44603831d35Sstevel 		tmp[1] = hsc_pil;
44703831d35Sstevel 		(void) ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
44803831d35Sstevel 		"interrupt-priorities", tmp, 2);
44903831d35Sstevel 		scsb->scsb_state |= SCSB_PROP_CREATE;
45003831d35Sstevel 	}
45103831d35Sstevel 	if ((i = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
45203831d35Sstevel 	    DDI_PROP_DONTPASS, "interrupts", -1)) >= 0)
45303831d35Sstevel 		scsb->scsb_state |= SCSB_P06_INTR_ON;
45403831d35Sstevel 	else
45503831d35Sstevel 		scsb->scsb_state |= SCSB_P06_NOINT_KLUGE;
45603831d35Sstevel 
45703831d35Sstevel 	/*
45803831d35Sstevel 	 * Look for the device-err-threshold property which specifies
45903831d35Sstevel 	 * on how many errors will scsb send a warning event about it's
46003831d35Sstevel 	 * health. The scsb_err_threshold is 10 by default.
46103831d35Sstevel 	 */
46203831d35Sstevel 	if ((i = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
46303831d35Sstevel 	    DDI_PROP_DONTPASS, "device-err-threshold", -1)) >= 0) {
46403831d35Sstevel 		scsb_err_threshold = i;
46503831d35Sstevel #ifdef	DEBUG
46603831d35Sstevel 		cmn_err(CE_NOTE, "?scsb_attach: Found device-err-threshold"
46703831d35Sstevel 		    " property, value %d", scsb_err_threshold);
46803831d35Sstevel #endif
46903831d35Sstevel 	}
47003831d35Sstevel 	scsb->scsb_i2c_errcnt = 0;
47103831d35Sstevel 	scsb->scsb_err_flag = B_FALSE;
47203831d35Sstevel 	scsb->scsb_kstat_flag = B_FALSE;
47303831d35Sstevel 
47403831d35Sstevel 	/*
47503831d35Sstevel 	 * If all went well, create the minor node for user level access.
47603831d35Sstevel 	 */
47703831d35Sstevel 	if (ddi_create_minor_node(dip, scsb_name, S_IFCHR, instance,
47803831d35Sstevel 	    "ddi_ctl:pcihpc", NULL) == DDI_FAILURE) {
47903831d35Sstevel 		cmn_err(CE_WARN, "scsb_attach: Failed to create minor node");
48003831d35Sstevel 		free_resources(dip, scsb, instance);
48103831d35Sstevel 		return (DDI_FAILURE);
48203831d35Sstevel 	}
48303831d35Sstevel 	scsb->scsb_state |= SCSB_MINOR_NODE;
48403831d35Sstevel 	scsb->scsb_dev = dip;
48503831d35Sstevel 	if (ddi_create_minor_node(dip, scsb_clone_name, S_IFCHR,
48603831d35Sstevel 	    instance|SCSB_CLONE, "ddi_ctl:pcihpc", NULL)
48703831d35Sstevel 	    == DDI_FAILURE) {
48803831d35Sstevel 		cmn_err(CE_WARN, "scsb_attach: Failed to create clone node");
48903831d35Sstevel 		free_resources(dip, scsb, instance);
49003831d35Sstevel 		return (DDI_FAILURE);
49103831d35Sstevel 	}
49203831d35Sstevel 	/* CLONE */
49303831d35Sstevel 	bzero(scsb->clone_devs, sizeof (clone_dev_t) * SCSB_CLONES_MAX);
49403831d35Sstevel 	/* 2 */
49503831d35Sstevel 	if (i2c_client_register(dip, &scsb->scsb_phandle) != I2C_SUCCESS) {
49603831d35Sstevel 		cmn_err(CE_WARN,
49703831d35Sstevel 		    "scsb_attach: Failed I2C Services registration");
49803831d35Sstevel 		free_resources(dip, scsb, instance);
49903831d35Sstevel 		return (DDI_FAILURE);
50003831d35Sstevel 	}
50103831d35Sstevel 	scsb->scsb_state |= SCSB_I2C_PHANDLE;
50203831d35Sstevel 	/* 3 */
50303831d35Sstevel 	if ((scsb->scsb_i2ctp = scsb_alloc_i2ctx(scsb->scsb_phandle,
50403831d35Sstevel 	    I2C_SLEEP)) == NULL) {
50503831d35Sstevel 		cmn_err(CE_WARN,
50603831d35Sstevel 		    "scsb%d: i2c_transfer allocation failed", instance);
50703831d35Sstevel 		free_resources(dip, scsb, instance);
50803831d35Sstevel 		return (DDI_FAILURE);
50903831d35Sstevel 	}
51003831d35Sstevel 	scsb->scsb_state |= SCSB_I2C_TRANSFER;
51103831d35Sstevel 	/*
51203831d35Sstevel 	 * Now it's time to INITIALIZE the boards.
51303831d35Sstevel 	 *
51403831d35Sstevel 	 *  1. make sure we can do I2C bus transfers to/from the SCB.
51503831d35Sstevel 	 *	Read the SCB PROM version for a check.
51603831d35Sstevel 	 *  2. set SCB_INITIALIZED bit in SysCommand registers (SYS_CMD_BASE)
51703831d35Sstevel 	 *  3. clear all LED Data registers (8) by writing 0's to turn off
51803831d35Sstevel 	 *	all LEDs on the SSB.
51903831d35Sstevel 	 *  4. read System Configuration Status registers (SCTRL_CFG)
52003831d35Sstevel 	 *	to find present FRUs and set corresponding FRU bits at
52103831d35Sstevel 	 *	LED_DATA_BASE.
52203831d35Sstevel 	 *	Also enable devices in Topology map for the current MP_ID
52303831d35Sstevel 	 *	and set the OK LEDs on the SSB.
52403831d35Sstevel 	 *  5. read Brd_Hlthy registers (2 @ BRD_HLTHY_BASE)
52503831d35Sstevel 	 *  6. Disable PSM Interrupts during initialization, mask all
52603831d35Sstevel 	 *	interrupts, and clear Interrupt Pointer registers
52703831d35Sstevel 	 *	by writing 0xFF to each register.
52803831d35Sstevel 	 *  7. set SCB EEPROM address bits SPA2-SPA0 at SYS_CMD_BASE + 1
52903831d35Sstevel 	 *  8. Install the interrupt handler if appropriate.
53003831d35Sstevel 	 *  9. clear appropriate bits in Interrupt Mask register for those
53103831d35Sstevel 	 *	devices that can be present for this MP_ID Topology.
53203831d35Sstevel 	 * 10. enable PSM Interrupt by writing '1' to PSM_INT_EN bit at
53303831d35Sstevel 	 *	SYS_CMD_BASE + 1
53403831d35Sstevel 	 *	Also update all shadow registers for test utility
53503831d35Sstevel 	 *	if scsb_debug is set.
53603831d35Sstevel 	 * 11. Check if Alarm Card present at boot and set flags
53703831d35Sstevel 	 * 12. Call hsc_attach() for slot registration.
53803831d35Sstevel 	 * 13. Allocate, initialze, and install the kstat structures.
53903831d35Sstevel 	 * 14. Set scsb_state_t flags to indicate SCB is ready
54003831d35Sstevel 	 *	and announce the driver is loaded.
54103831d35Sstevel 	 */
54203831d35Sstevel 
54303831d35Sstevel 	/* 1. through 7. */
54403831d35Sstevel 	if (initialize_scb(scsb) != DDI_SUCCESS) {
54503831d35Sstevel 		if (!(scsb_debug)) {
54603831d35Sstevel 			free_resources(dip, scsb, instance);
54703831d35Sstevel 			return (DDI_FAILURE);
54803831d35Sstevel 		}
54903831d35Sstevel 	}
55003831d35Sstevel 	/* 8. */
55103831d35Sstevel 	/*
55203831d35Sstevel 	 * P0.6 No Interrupt Support
55303831d35Sstevel 	 * Instead of installing the handler, it will be called from a user
55403831d35Sstevel 	 * program via smf_ioctl().  This flag provides knowledge of the
55503831d35Sstevel 	 * necessary workarounds to several scsb routines.
55603831d35Sstevel 	 */
55703831d35Sstevel 	/*
55803831d35Sstevel 	 * Now Install interrupt handler
55903831d35Sstevel 	 */
56003831d35Sstevel 	if (scsb->scsb_state & SCSB_P06_INTR_ON) {
56103831d35Sstevel 		if (ddi_get_iblock_cookie(dip, instance,
56203831d35Sstevel 		    &scsb->scsb_iblock) == DDI_SUCCESS) {
56303831d35Sstevel 			mutex_init(&scsb->scsb_imutex, NULL, MUTEX_DRIVER,
56403831d35Sstevel 			    (void *)scsb->scsb_iblock);
56503831d35Sstevel 			scsb->scsb_state |= SCSB_IMUTEX;
56603831d35Sstevel 			if (ddi_add_intr(dip, instance, &scsb->scsb_iblock,
56703831d35Sstevel 			    NULL, scsb_intr_preprocess,
56803831d35Sstevel 			    (caddr_t)scsb) != DDI_SUCCESS) {
56903831d35Sstevel 				cmn_err(CE_WARN,
57003831d35Sstevel 				    "scsb_attach: failed interrupt "
57103831d35Sstevel 				    "handler registration");
57203831d35Sstevel 				free_resources(dip, scsb, instance);
57303831d35Sstevel 				return (DDI_FAILURE);
57403831d35Sstevel 			}
57503831d35Sstevel 			scb_intr_mutex = &scsb->scsb_imutex;
57603831d35Sstevel 			nct_mutex_init |= MUTEX_INIT;
57703831d35Sstevel 		} else {
57803831d35Sstevel 			cmn_err(CE_WARN, "scsb_attach: failed interrupt "
57903831d35Sstevel 			    "mutex initialization");
58003831d35Sstevel 			if (scsb_debug) {
58103831d35Sstevel 				scsb->scsb_state |= SCSB_P06_NOINT_KLUGE;
58203831d35Sstevel 				scsb->scsb_state &= ~SCSB_P06_INTR_ON;
58303831d35Sstevel 			} else {
58403831d35Sstevel 				free_resources(dip, scsb, instance);
58503831d35Sstevel 				return (DDI_FAILURE);
58603831d35Sstevel 			}
58703831d35Sstevel 		}
58803831d35Sstevel 	}
58903831d35Sstevel 	/* 9. */
59003831d35Sstevel 	if (i = scsb_clear_intmasks(scsb)) {
59103831d35Sstevel 		cmn_err(CE_WARN,
59203831d35Sstevel 		    "scsb%d: I2C TRANSFER Failed", instance);
59303831d35Sstevel 		if (!scsb_debug) {
59403831d35Sstevel 			free_resources(dip, scsb, instance);
59503831d35Sstevel 			return (DDI_FAILURE);
59603831d35Sstevel 		}
59703831d35Sstevel 	}
59803831d35Sstevel 
59903831d35Sstevel 	/* 10. */
60003831d35Sstevel 	/*
60103831d35Sstevel 	 * For P0.6 No Interrupt Support, don't enable PSM Interrupt
60203831d35Sstevel 	 */
60303831d35Sstevel 	if (!(scsb->scsb_state & SCSB_P06_NOINT_KLUGE)) {
60403831d35Sstevel 		rmask = 0x00;
60503831d35Sstevel 		wdata = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
60603831d35Sstevel 		i = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE,
60703831d35Sstevel 		    SCTRL_SYS_CMD_BASE);
60803831d35Sstevel 		reg = SCSB_REG_ADDR(i);
60903831d35Sstevel 		if (i = scsb_write_mask(scsb, reg, rmask, wdata, (uchar_t)0)) {
61003831d35Sstevel 			cmn_err(CE_WARN,
61103831d35Sstevel 			    "scsb%d: I2C TRANSFER Failed", instance);
61203831d35Sstevel 			if (!scsb_debug) {
61303831d35Sstevel 				free_resources(dip, scsb, instance);
61403831d35Sstevel 				return (DDI_FAILURE);
61503831d35Sstevel 			}
61603831d35Sstevel 		} else
61703831d35Sstevel 			scsb->scsb_state |= SCSB_PSM_INT_ENABLED;
61803831d35Sstevel 	}
61903831d35Sstevel 	if (scsb_debug) {
62003831d35Sstevel 		/*
62103831d35Sstevel 		 * For smctrl test utility,
62203831d35Sstevel 		 * so all data is available in shadow registers
62303831d35Sstevel 		 *
62403831d35Sstevel 		 * DEBUG_MODE enables private testing interfaces
62503831d35Sstevel 		 * DIAGS_MODE permits limited testing interfaces
62603831d35Sstevel 		 */
62703831d35Sstevel 		scsb->scsb_state |= SCSB_DEBUG_MODE;
62803831d35Sstevel 		mutex_enter(&scsb->scsb_mutex);
62903831d35Sstevel 		if (scsb_readall_regs(scsb))
63003831d35Sstevel 			cmn_err(CE_WARN,
63103831d35Sstevel 			    "scsb_attach: scsb_readall FAILED");
63203831d35Sstevel 		mutex_exit(&scsb->scsb_mutex);
63303831d35Sstevel 	}
63403831d35Sstevel 	/* 11. */
63503831d35Sstevel 	/* Check if Alarm Card present at boot and set flags */
63603831d35Sstevel 	if (scsb_fru_op(scsb, ALARM, 1, SCTRL_SYSCFG_BASE,
63703831d35Sstevel 	    SCSB_FRU_OP_GET_BITVAL))
63803831d35Sstevel 		scsb->scsb_hsc_state |= SCSB_ALARM_CARD_PRES;
63903831d35Sstevel 
64003831d35Sstevel 	/* 12. */
64103831d35Sstevel 	if (scsb_debug & 0x0004)
64203831d35Sstevel 		cmn_err(CE_NOTE,
64303831d35Sstevel 		    "scsb_attach: registering cPCI slots");
64403831d35Sstevel 	if (scsb_hsc_attach(dip, scsb, instance) != DDI_SUCCESS) {
64503831d35Sstevel 		if (scsb_debug & 0x00008000) {
64603831d35Sstevel 			cmn_err(CE_WARN,
64703831d35Sstevel 			"scsb: Hotswap controller initialisation"
64803831d35Sstevel 			    " failed\n");
64903831d35Sstevel 		}
65003831d35Sstevel 	} else
65103831d35Sstevel 		scsb->scsb_hsc_state |= SCSB_HSC_INIT;
65203831d35Sstevel 	/* 13. */
65303831d35Sstevel 	/*
65403831d35Sstevel 	 * allocate and install the kstat data structures
65503831d35Sstevel 	 */
65603831d35Sstevel 	if (scsb_alloc_kstats(scsb) != DDI_SUCCESS) {
65703831d35Sstevel 		if (scsb_debug & 0x0006)
65803831d35Sstevel 			cmn_err(CE_WARN, "scsb_attach: ERROR adding kstats");
65903831d35Sstevel 	}
66003831d35Sstevel 	/* 14. */
66103831d35Sstevel 	scsb->scsb_state |= SCSB_UP;
66203831d35Sstevel 	scsb_global_state |= SCSB_UP;
66303831d35Sstevel 	ddi_report_dev(scsb->scsb_dev);
66403831d35Sstevel 	cmn_err(CE_CONT, "?%s%d: "
66503831d35Sstevel 	"Prom Version %s, Midplane Id %x\n",
66603831d35Sstevel 	    ddi_driver_name(scsb->scsb_dev),
66703831d35Sstevel 	    scsb->scsb_instance,
66803831d35Sstevel 	    (scsb->scsb_state & SCSB_P06_PROM) ? "0.6" :
66903831d35Sstevel 	    (scsb->scsb_state & SCSB_P10_PROM) ? "1.0" :
67003831d35Sstevel 	    (scsb->scsb_state & SCSB_P15_PROM) ? "1.5" :
67103831d35Sstevel 	    (scsb->scsb_state & SCSB_P20_PROM) ? "2.0" : "Unknown",
67203831d35Sstevel 	    mct_system_info.mid_plane.fru_id);
67303831d35Sstevel 	return (DDI_SUCCESS);
67403831d35Sstevel }
67503831d35Sstevel 
67603831d35Sstevel /*
67703831d35Sstevel  * This funciton is called from scsb_attach(), and from scsb_intr() as part
67803831d35Sstevel  * of Hot Insertion support, to check the SCB PROM ID register and set
67903831d35Sstevel  * scsb_state bits and register table pointers as necessary.
68003831d35Sstevel  */
68103831d35Sstevel static int
68203831d35Sstevel scb_check_version(scsb_state_t *scsb)
68303831d35Sstevel {
68403831d35Sstevel 	int		hotswap = 0;
68503831d35Sstevel 	uchar_t		data;
68603831d35Sstevel 	if (scsb->scsb_state & SCSB_UP) {
68703831d35Sstevel 		/*
68803831d35Sstevel 		 * If driver is UP, then this call is from scsb_intr()
68903831d35Sstevel 		 * as part of Hot Insertion support.
69003831d35Sstevel 		 */
69103831d35Sstevel 		hotswap = 1;
69203831d35Sstevel 	}
69303831d35Sstevel 	/* Read the SCB PROM ID */
69403831d35Sstevel 	if (scsb_rdwr_register(scsb, I2C_WR_RD, (uchar_t)SCTRL_PROM_VERSION, 1,
69503831d35Sstevel 	    &data, 1)) {
69603831d35Sstevel 		if (!(hotswap && scsb->scsb_state & SCSB_FROZEN))
69703831d35Sstevel 			cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
69803831d35Sstevel 			    scsb->scsb_instance);
69903831d35Sstevel 		if (scsb_debug & 0x0006) {
70003831d35Sstevel 				cmn_err(CE_WARN,
70103831d35Sstevel 				    "scsb_attach(%d): failed read of PROM ID",
70203831d35Sstevel 				    scsb->scsb_instance);
70303831d35Sstevel 		}
70403831d35Sstevel 		return (DDI_FAILURE);
70503831d35Sstevel 	}
70603831d35Sstevel 	/*
70703831d35Sstevel 	 * compare with stored version number, and if different,
70803831d35Sstevel 	 * report a warning and keep the driver FROZEN
70903831d35Sstevel 	 */
71003831d35Sstevel 	if (hotswap) {
71103831d35Sstevel 		if (((mct_system_info.fru_info_list[SCB])[0].fru_version & 0xf)
71203831d35Sstevel 		    == (data & 0xf)) {
71303831d35Sstevel 			return (DDI_SUCCESS);
71403831d35Sstevel 		}
71503831d35Sstevel 		if (scsb_debug & 0x00020000) {
71603831d35Sstevel 			cmn_err(CE_NOTE,
71703831d35Sstevel 			    "scb_check_version: SCB version %d "
71803831d35Sstevel 			    "replacing version %d", data,
71903831d35Sstevel 			    (mct_system_info.fru_info_list[SCB])[0].
72003831d35Sstevel 			    fru_version & 0xf);
72103831d35Sstevel 		}
72203831d35Sstevel 	}
72303831d35Sstevel 	if ((data & 0xf) == SCTRL_PROM_P06) {
72403831d35Sstevel 		scsb->scsb_state |= SCSB_P06_PROM;
72503831d35Sstevel 	} else if ((data & 0xf) == SCTRL_PROM_P10) {
72603831d35Sstevel 		scsb->scsb_state |= SCSB_P10_PROM;
72703831d35Sstevel 	} else if ((data & 0xf) == SCTRL_PROM_P15) {
72803831d35Sstevel 		scsb->scsb_state |= SCSB_P15_PROM;
72903831d35Sstevel 	} else if ((data & 0xf) == SCTRL_PROM_P20) {
73003831d35Sstevel 		scsb->scsb_state |= SCSB_P20_PROM;
73103831d35Sstevel 	}
73203831d35Sstevel 	if (!(scsb->scsb_state & SCSB_SCB_PRESENT))
73303831d35Sstevel 		scsb->scsb_state |= SCSB_SCB_PRESENT;
73403831d35Sstevel 	if (IS_SCB_P10) {
73503831d35Sstevel 		scb_reg_index  = scb_10_reg_index;
73603831d35Sstevel 		scb_numregs    = scb_10_numregs;
73703831d35Sstevel 		scb_fru_offset = scb_10_fru_offset;
73803831d35Sstevel 		scb_sys_offset = scb_10_sys_offset;
73903831d35Sstevel 	} else { /* if (IS_SCB_P15) */
74003831d35Sstevel 		scb_reg_index  = scb_15_reg_index;
74103831d35Sstevel 		scb_numregs    = scb_15_numregs;
74203831d35Sstevel 		scb_fru_offset = scb_15_fru_offset;
74303831d35Sstevel 		scb_sys_offset = scb_15_sys_offset;
74403831d35Sstevel 	}
74503831d35Sstevel 	if (!(IS_SCB_P15) && !(IS_SCB_P10)) {
74603831d35Sstevel 		cmn_err(CE_WARN, "scsb%d: SCB Version %d not recognized",
74703831d35Sstevel 		    scsb->scsb_instance, data);
74803831d35Sstevel 		if (hotswap)
74903831d35Sstevel 			scsb->scsb_state |= SCSB_FROZEN;
75003831d35Sstevel 		if (!(scsb_debug)) {
75103831d35Sstevel 			return (DDI_FAILURE);
75203831d35Sstevel 		}
75303831d35Sstevel 		/*
75403831d35Sstevel 		 * DEBUG: Assume SCB15
75503831d35Sstevel 		 */
75603831d35Sstevel 		scsb->scsb_state |= SCSB_P15_PROM;
75703831d35Sstevel 	}
75803831d35Sstevel 	return (DDI_SUCCESS);
75903831d35Sstevel }
76003831d35Sstevel 
76103831d35Sstevel /*
76203831d35Sstevel  * SCB initialization steps to be called from scsb_attach()
76303831d35Sstevel  * or from scsb_intr() calling scsb_restore() on Hot Insertion.
76403831d35Sstevel  */
76503831d35Sstevel static int
76603831d35Sstevel initialize_scb(scsb_state_t *scsb)
76703831d35Sstevel {
76803831d35Sstevel 	register int	i;
76903831d35Sstevel 	uchar_t		reg, wdata, rmask;
77003831d35Sstevel 	/*
77103831d35Sstevel 	 * If called from scsb_intr(), we've already done this
77203831d35Sstevel 	 */
77303831d35Sstevel 	if (!(scsb->scsb_state & SCSB_IN_INTR))
77403831d35Sstevel 		if (scb_check_version(scsb) != DDI_SUCCESS)
77503831d35Sstevel 			return (DDI_FAILURE);
77603831d35Sstevel 	/*
77703831d35Sstevel 	 * 2. Set the SCB_INIT bit in the System Command register
77803831d35Sstevel 	 */
77903831d35Sstevel 	rmask = 0x00;	/* P1.0: 0x60; */
78003831d35Sstevel 	wdata = 1 << SYS_OFFSET(SCTRL_SYS_SCB_INIT);
78103831d35Sstevel 	i = SYS_REG_INDEX(SCTRL_SYS_SCB_INIT, SCTRL_SYS_CMD_BASE);
78203831d35Sstevel 	reg = SCSB_REG_ADDR(i);
78303831d35Sstevel 	if (i = scsb_write_mask(scsb, reg, rmask, wdata, 0)) {
78403831d35Sstevel 		cmn_err(CE_WARN,
78503831d35Sstevel 		    "scsb%d: I2C TRANSFER Failed", scsb->scsb_instance);
78603831d35Sstevel 		if (scsb_debug & 0x0006) {
78703831d35Sstevel 			cmn_err(CE_NOTE,
78803831d35Sstevel 			"scsb_attach: failed to set SCB_INIT");
78903831d35Sstevel 		}
79003831d35Sstevel 		return (DDI_FAILURE);
79103831d35Sstevel 	}
79203831d35Sstevel 	/* 3. For P1.0 and previous system, turn off all LEDs */
79303831d35Sstevel 	if (IS_SCB_P10) {
79403831d35Sstevel 		if (scsb_debug & 0x0004) {
79503831d35Sstevel 			cmn_err(CE_NOTE, "scsb_attach(%d): turning LEDs off",
79603831d35Sstevel 			    scsb->scsb_instance);
79703831d35Sstevel 		}
79803831d35Sstevel 		if (i = scsb_leds_switch(scsb, OFF)) {
79903831d35Sstevel 			cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
80003831d35Sstevel 			    scsb->scsb_instance);
80103831d35Sstevel 			return (DDI_FAILURE);
80203831d35Sstevel 		}
80303831d35Sstevel 	}
80403831d35Sstevel 	/* 4. Read the SYSCFG registers, update FRU info and SSB LEDs */
80503831d35Sstevel 	if (scsb_debug & 0x0004)
80603831d35Sstevel 		cmn_err(CE_NOTE, "scsb_attach(%d): reading config registers",
80703831d35Sstevel 		    scsb->scsb_instance);
80803831d35Sstevel 	if ((i = scsb_check_config_status(scsb)) == 0) {
80903831d35Sstevel 		if (!(scsb->scsb_state & SCSB_TOPOLOGY)) {
81003831d35Sstevel 			scsb_set_topology(scsb);
81103831d35Sstevel 			if (scsb_debug & 0x0004)
81203831d35Sstevel 				cmn_err(CE_NOTE, "scsb_attach(%d): mpid = 0x%x",
81303831d35Sstevel 				    scsb->scsb_instance,
81403831d35Sstevel 				    mct_system_info.mid_plane.fru_id);
81503831d35Sstevel 		} else {
81603831d35Sstevel 			fru_info_t	*fru_ptr;
81703831d35Sstevel 			/*
81803831d35Sstevel 			 * walk through FRUs and update FRU info
81903831d35Sstevel 			 */
82003831d35Sstevel 			for (i = 0; i < SCSB_UNIT_TYPES; ++i) {
82103831d35Sstevel 				fru_ptr = mct_system_info.fru_info_list[i];
82203831d35Sstevel 				while (fru_ptr != NULL) {
82303831d35Sstevel 					update_fru_info(scsb, fru_ptr);
82403831d35Sstevel 					fru_ptr = fru_ptr->next;
82503831d35Sstevel 				}
82603831d35Sstevel 			}
82703831d35Sstevel 		}
82803831d35Sstevel 		i = scsb_set_scfg_pres_leds(scsb, NULL);
82903831d35Sstevel 	}
83003831d35Sstevel 	if (i) {
83103831d35Sstevel 		cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
83203831d35Sstevel 		    scsb->scsb_instance);
83303831d35Sstevel 		return (DDI_FAILURE);
83403831d35Sstevel 	}
83503831d35Sstevel 	/* 5. read the Board Healthy registers */
83603831d35Sstevel 	if (scsb_debug & 0x0004)
83703831d35Sstevel 		cmn_err(CE_NOTE, "scsb_attach(%d): reading Brd_Hlthy registers",
83803831d35Sstevel 		    scsb->scsb_instance);
83903831d35Sstevel 	i = scsb_read_bhealthy(scsb);
84003831d35Sstevel 	if (i) {
84103831d35Sstevel 		cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
84203831d35Sstevel 		    scsb->scsb_instance);
84303831d35Sstevel 		return (DDI_FAILURE);
84403831d35Sstevel 	}
84503831d35Sstevel 	/* 6. Clear Interrupt Source registers */
84603831d35Sstevel 	/*
84703831d35Sstevel 	 * Due to some registration problems, we must first disable
84803831d35Sstevel 	 * global interrupts which may be the default reset value
84903831d35Sstevel 	 * itself. However, this is a safe step to do in case of
85003831d35Sstevel 	 * implementation changes.
85103831d35Sstevel 	 *
85203831d35Sstevel 	 * Disable Global SCB Interrupts now
85303831d35Sstevel 	 */
85403831d35Sstevel 	rmask = 0x00;	/* P1.0: 0x60; */
85503831d35Sstevel 	wdata = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
85603831d35Sstevel 	i = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE, SCTRL_SYS_CMD_BASE);
85703831d35Sstevel 	reg = SCSB_REG_ADDR(i);
85803831d35Sstevel 	if (i = scsb_write_mask(scsb, reg, rmask, (uchar_t)0, wdata)) {
85903831d35Sstevel 		cmn_err(CE_WARN, "scsb%d: Cannot turn off PSM_INT",
86003831d35Sstevel 		    scsb->scsb_instance);
86103831d35Sstevel 		return (DDI_FAILURE);
86203831d35Sstevel 	}
86303831d35Sstevel 	/* Mask all interrupt sources */
86403831d35Sstevel 	if (i = scsb_setall_intmasks(scsb)) {
86503831d35Sstevel 		cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
86603831d35Sstevel 		    scsb->scsb_instance);
86703831d35Sstevel 		return (DDI_FAILURE);
86803831d35Sstevel 	}
86903831d35Sstevel 	/* Clear any latched interrupts */
87003831d35Sstevel 	if (i = scsb_clear_intptrs(scsb)) {
87103831d35Sstevel 		cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
87203831d35Sstevel 		    scsb->scsb_instance);
87303831d35Sstevel 		return (DDI_FAILURE);
87403831d35Sstevel 	}
87503831d35Sstevel 	/* 7. set SCB EEPROM address: NOT USED */
87603831d35Sstevel 	return (DDI_SUCCESS);
87703831d35Sstevel }
87803831d35Sstevel 
87903831d35Sstevel /*
88003831d35Sstevel  * Based on MC conditions, scsb_detach should eventually be made to always
88103831d35Sstevel  * return FAILURE, as the driver should not be allowed to detach after some
88203831d35Sstevel  * hs slots have been used.
88303831d35Sstevel  */
88403831d35Sstevel static int
88503831d35Sstevel scsb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
88603831d35Sstevel {
88703831d35Sstevel 	int		instance;
88803831d35Sstevel 	scsb_state_t	*scsb;
88903831d35Sstevel 	uchar_t		reg, wdata;
89003831d35Sstevel 
89103831d35Sstevel 	/*
89203831d35Sstevel 	 * TBD: make sure there are no outstanding operations on the system
89303831d35Sstevel 	 * monitor card before detaching.
89403831d35Sstevel 	 */
89503831d35Sstevel 	instance = ddi_get_instance(dip);
89603831d35Sstevel 	if (scsb_debug & 0x0005)
89703831d35Sstevel 		cmn_err(CE_NOTE, "scsb_detach[%d]", instance);
89803831d35Sstevel 	if (cmd != DDI_DETACH) {
89903831d35Sstevel 		if (scsb_debug & 0x0006)
90003831d35Sstevel 			cmn_err(CE_NOTE,
90103831d35Sstevel 			    "scsb_detach(%d): command %x is not DDI_DETACH\n",
90203831d35Sstevel 			    instance, cmd);
90303831d35Sstevel 		return (DDI_FAILURE);
90403831d35Sstevel 	}
90503831d35Sstevel 	scsb = (scsb_state_t *)ddi_get_soft_state(scsb_state, instance);
90603831d35Sstevel 	scsb->scsb_state &= ~SCSB_UP;
90703831d35Sstevel 	scsb_global_state &= ~SCSB_UP;
90803831d35Sstevel 	if (scsb->scsb_hsc_state & SCSB_HSC_INIT) {
909*07d06da5SSurya Prakki 		(void) scsb_hsc_detach(dip, scsb, instance);
91003831d35Sstevel 		scsb->scsb_hsc_state &= ~SCSB_HSC_INIT;
91103831d35Sstevel 	}
91203831d35Sstevel 	if (scsb->scsb_state & SCSB_PSM_INT_ENABLED) {
91303831d35Sstevel 		/*
91403831d35Sstevel 		 * Disable Global SCB Interrupts now
91503831d35Sstevel 		 */
91603831d35Sstevel 		wdata = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
91703831d35Sstevel 		reg = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE,
91803831d35Sstevel 		    SCTRL_SYS_CMD_BASE);
91903831d35Sstevel 		if (scsb_write_mask(scsb, reg, (uchar_t)0, (uchar_t)0, wdata)) {
92003831d35Sstevel 			cmn_err(CE_WARN,
92103831d35Sstevel 			    "scsb%d: Cannot turn off PSM_INT", instance);
92203831d35Sstevel 			if (!scsb_debug) {
92303831d35Sstevel 				(void) free_resources(dip, scsb, instance);
92403831d35Sstevel 				return (DDI_FAILURE);
92503831d35Sstevel 			}
92603831d35Sstevel 		}
92703831d35Sstevel 		/* Mask all interrupts */
92803831d35Sstevel 		if (scsb_setall_intmasks(scsb)) {
92903831d35Sstevel 			cmn_err(CE_WARN,
93003831d35Sstevel 			    "scsb%d: I2C TRANSFER Failed", instance);
93103831d35Sstevel 			if (!scsb_debug) {
93203831d35Sstevel 				(void) free_resources(dip, scsb, instance);
93303831d35Sstevel 				return (DDI_FAILURE);
93403831d35Sstevel 			}
93503831d35Sstevel 		}
93603831d35Sstevel 		/* Clear all latched interrupts */
93703831d35Sstevel 		if (scsb_clear_intptrs(scsb)) {
93803831d35Sstevel 			cmn_err(CE_WARN,
93903831d35Sstevel 			    "scsb%d: I2C TRANSFER Failed", instance);
94003831d35Sstevel 			if (!scsb_debug) {
94103831d35Sstevel 				(void) free_resources(dip, scsb, instance);
94203831d35Sstevel 				return (DDI_FAILURE);
94303831d35Sstevel 			}
94403831d35Sstevel 		}
94503831d35Sstevel 	}
94603831d35Sstevel 	if (scsb->scsb_opens && scsb->scsb_rq != NULL)
94703831d35Sstevel 		qprocsoff(scsb->scsb_rq);
94803831d35Sstevel 	/* CLONE */
94903831d35Sstevel 	(void) scsb_queue_ops(scsb, QPROCSOFF, 0, NULL, NULL);
95003831d35Sstevel 	/*
95103831d35Sstevel 	 * free the allocated resources
95203831d35Sstevel 	 */
95303831d35Sstevel 	free_resources(dip, scsb, instance);
95403831d35Sstevel 	return (DDI_SUCCESS);
95503831d35Sstevel }
95603831d35Sstevel 
95703831d35Sstevel static void
95803831d35Sstevel free_resources(dev_info_t *dip, scsb_state_t *scsb, int instance)
95903831d35Sstevel {
96003831d35Sstevel 	if (scsb_debug & 0x0005) {
96103831d35Sstevel 		cmn_err(CE_NOTE, "free_resources[%d], scsb_state=0x%x",
96203831d35Sstevel 		    instance, scsb->scsb_state);
96303831d35Sstevel 		drv_usecwait(500000);
96403831d35Sstevel 	}
96503831d35Sstevel 	if (scsb->scsb_state & SCSB_P06_INTR_ON &&
96603831d35Sstevel 	    scsb->scsb_state & SCSB_IMUTEX) {
96703831d35Sstevel 		scsb->scsb_state &= ~SCSB_P06_INTR_ON;
96803831d35Sstevel 		ddi_remove_intr(dip, 0, scsb->scsb_iblock);
96903831d35Sstevel 	}
97003831d35Sstevel 	if (scsb->scsb_state & SCSB_KSTATS) {
97103831d35Sstevel 		scsb_free_kstats(scsb);
97203831d35Sstevel 		scsb->scsb_state &= ~SCSB_KSTATS;
97303831d35Sstevel 	}
97403831d35Sstevel 	if (scsb->scsb_state & SCSB_TOPOLOGY) {
97503831d35Sstevel 		scsb_free_topology(scsb);
97603831d35Sstevel 		scsb->scsb_state &= ~SCSB_TOPOLOGY;
97703831d35Sstevel 	}
97803831d35Sstevel 
97903831d35Sstevel 	nct_mutex_init = MUTEX_UNINIT;
98003831d35Sstevel 	if (scsb->scsb_state & SCSB_IMUTEX) {
98103831d35Sstevel 		scsb->scsb_state &= ~SCSB_IMUTEX;
98203831d35Sstevel 		mutex_destroy(&scsb->scsb_imutex);
98303831d35Sstevel 	}
98403831d35Sstevel 	if (scsb->scsb_state & SCSB_I2C_TRANSFER) {
98503831d35Sstevel 		scsb->scsb_state &= ~SCSB_I2C_TRANSFER;
98603831d35Sstevel 		i2c_transfer_free(scsb->scsb_phandle, scsb->scsb_i2ctp);
98703831d35Sstevel 	}
98803831d35Sstevel 	if (scsb->scsb_state & SCSB_I2C_PHANDLE) {
98903831d35Sstevel 		scsb->scsb_state &= ~SCSB_I2C_PHANDLE;
99003831d35Sstevel 		i2c_client_unregister(scsb->scsb_phandle);
99103831d35Sstevel 	}
99203831d35Sstevel 	if (scsb->scsb_state & SCSB_MINOR_NODE) {
99303831d35Sstevel 		scsb->scsb_state &= ~SCSB_MINOR_NODE;
99403831d35Sstevel 		ddi_remove_minor_node(dip, NULL);
99503831d35Sstevel 	}
99603831d35Sstevel 	if (scsb->scsb_state & SCSB_PROP_CREATE) {
99703831d35Sstevel 		scsb->scsb_state &= ~SCSB_PROP_CREATE;
99803831d35Sstevel 		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
99903831d35Sstevel 		    "interrupt-priorities");
100003831d35Sstevel 	}
100103831d35Sstevel 	/* ddi_prop_remove_all(dip); */
100203831d35Sstevel 	if (scsb->scsb_state & SCSB_CONDVAR) {
100303831d35Sstevel 		scsb->scsb_state &= ~SCSB_CONDVAR;
100403831d35Sstevel 		cv_destroy(&scsb->scsb_cv);
100503831d35Sstevel 	}
100603831d35Sstevel 	if (scsb->scsb_state & SCSB_UMUTEX) {
100703831d35Sstevel 		scsb->scsb_state &= ~SCSB_UMUTEX;
100803831d35Sstevel 		mutex_destroy(&scsb->scsb_mutex);
100903831d35Sstevel 	}
101003831d35Sstevel 	ddi_soft_state_free(scsb_state, instance);
101103831d35Sstevel }
101203831d35Sstevel 
101303831d35Sstevel /*
101403831d35Sstevel  * Just for testing scsb's poll function
101503831d35Sstevel  */
101603831d35Sstevel static int
101703831d35Sstevel scsb_fake_intr(scsb_state_t *scsb, uint32_t evcode)
101803831d35Sstevel {
101903831d35Sstevel 	if (evcode == 0)
102003831d35Sstevel 		evcode = scsb_event_code;
102103831d35Sstevel 	else
102203831d35Sstevel 		scsb_event_code = evcode;
102303831d35Sstevel 	if (scsb_debug & 0x4001) {
102403831d35Sstevel 		cmn_err(CE_NOTE, "scsb_fake_intr: event = 0x%x, scsb_rq=0x%p",
1025*07d06da5SSurya Prakki 		    scsb_event_code, (void *)scsb->scsb_rq);
102603831d35Sstevel 	}
102703831d35Sstevel 	/*
102803831d35Sstevel 	 * Allow access to shadow registers even though SCB is removed
102903831d35Sstevel 	 *
103003831d35Sstevel 	 * if (scsb->scsb_state & SCSB_FROZEN) {
103103831d35Sstevel 	 *	return (EAGAIN);
103203831d35Sstevel 	 * }
103303831d35Sstevel 	 */
103403831d35Sstevel 	if (scsb_debug & 0x00040000) {
103503831d35Sstevel 		check_fru_info(scsb, evcode);
103603831d35Sstevel 		add_event_code(scsb, evcode);
103703831d35Sstevel 	}
103803831d35Sstevel 	/* just inform user-level via poll about this event */
103903831d35Sstevel 	if (scsb_queue_ops(scsb, QPUT_INT32, 1, &evcode, "scsb_fake_intr")
104003831d35Sstevel 	    == QOP_FAILED)
104103831d35Sstevel 		return (ENOMEM);
104203831d35Sstevel 	return (0);
104303831d35Sstevel }
104403831d35Sstevel 
104503831d35Sstevel /* ARGSUSED */
104603831d35Sstevel static int
104703831d35Sstevel scsb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
104803831d35Sstevel {
104903831d35Sstevel 	int	retval = DDI_FAILURE;
105003831d35Sstevel 
105103831d35Sstevel 	if (scsb_debug & 0x0001)
105203831d35Sstevel 		cmn_err(CE_NOTE, "scsb_info()");
105303831d35Sstevel 
105403831d35Sstevel 	switch (infocmd) {
105503831d35Sstevel 	case DDI_INFO_DEVT2DEVINFO:
105603831d35Sstevel 		if (getminor((dev_t)arg) == 0 && scsb_dip != NULL) {
105703831d35Sstevel 			*result = (void *) scsb_dip;
105803831d35Sstevel 			retval = DDI_SUCCESS;
105903831d35Sstevel 		}
106003831d35Sstevel 		break;
106103831d35Sstevel 
106203831d35Sstevel 	case DDI_INFO_DEVT2INSTANCE:
106303831d35Sstevel 		if (getminor((dev_t)arg) == 0) {
106403831d35Sstevel 			*result = (void *)0;
106503831d35Sstevel 			retval = DDI_SUCCESS;
106603831d35Sstevel 		}
106703831d35Sstevel 		break;
106803831d35Sstevel 
106903831d35Sstevel 	default:
107003831d35Sstevel 		break;
107103831d35Sstevel 	}
107203831d35Sstevel 
107303831d35Sstevel 	return (retval);
107403831d35Sstevel }
107503831d35Sstevel 
107603831d35Sstevel 
107703831d35Sstevel /*
107803831d35Sstevel  * SCSB STREAMS routines
107903831d35Sstevel  */
108003831d35Sstevel /*ARGSUSED*/
108103831d35Sstevel static int
108203831d35Sstevel sm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
108303831d35Sstevel {
108403831d35Sstevel 	int		instance, clone;
108503831d35Sstevel 	minor_t		minor_dev;
108603831d35Sstevel 	clone_dev_t	*clptr;
108703831d35Sstevel 	scsb_state_t	*scsb;
108803831d35Sstevel 
108903831d35Sstevel 	minor_dev = getminor(*devp);
109003831d35Sstevel 	instance = SCSB_GET_INSTANCE(minor_dev);
109103831d35Sstevel 	scsb = ddi_get_soft_state(scsb_state, instance);
109203831d35Sstevel 	if (scsb == NULL)
109303831d35Sstevel 		return (ENXIO);
109403831d35Sstevel 
109503831d35Sstevel 	if (scsb_debug & 0x0009) {
1096*07d06da5SSurya Prakki 		cmn_err(CE_NOTE, "sm_open(%d) q=0x%p", instance, (void *)q);
109703831d35Sstevel 	}
109803831d35Sstevel 	if (!(scsb->scsb_state & SCSB_UP)) {
109903831d35Sstevel 		return (ENODEV);
110003831d35Sstevel 	}
110103831d35Sstevel 	/*
110203831d35Sstevel 	 * Don't fail the open if SCB removed since we still want to satisfy
110303831d35Sstevel 	 * read requests from the shadow registers, the last know register
110403831d35Sstevel 	 * contents.  On new SCB insertion, all will be re-initialized,
110503831d35Sstevel 	 * including envmond and it's policies.
110603831d35Sstevel 	 *
110703831d35Sstevel 	 * if (scsb->scsb_state & SCSB_FROZEN) {
110803831d35Sstevel 	 *	return (EAGAIN);
110903831d35Sstevel 	 * }
111003831d35Sstevel 	 */
111103831d35Sstevel 	ASSERT(credp != NULL);
111203831d35Sstevel 	/*
111303831d35Sstevel 	 * XXX check for root access here, return EPERM if not root open
111403831d35Sstevel 	 */
111503831d35Sstevel 	if (sflag == MODOPEN) {
111603831d35Sstevel 		/* scsb module is being pushed */
111703831d35Sstevel 		if (scsb_debug & 0x0008)
111803831d35Sstevel 			cmn_err(CE_NOTE, "sm_open(%d): MODOPEN", instance);
111903831d35Sstevel 		/*
112003831d35Sstevel 		 * this is no longer supported
112103831d35Sstevel 		 */
112203831d35Sstevel 		return (ENXIO);
112303831d35Sstevel 	} else if (sflag == CLONEOPEN) {
112403831d35Sstevel 		/* scsb is being opened as a clonable driver */
112503831d35Sstevel 		if (scsb_debug & 0x0008)
112603831d35Sstevel 			cmn_err(CE_NOTE, "sm_open(%d): CLONEOPEN", instance);
112703831d35Sstevel 		/*
112803831d35Sstevel 		 * The cloned stream is not handled via the clone driver.
112903831d35Sstevel 		 * See the minor device code below.
113003831d35Sstevel 		 */
113103831d35Sstevel 		return (ENXIO);
113203831d35Sstevel 	} else if (minor_dev & SCSB_CLONE) {
113303831d35Sstevel 		/*
113403831d35Sstevel 		 * First check for the SCSB_CLONE device.
113503831d35Sstevel 		 *	Find an available clone_devs[] entry, or return ENXIO.
113603831d35Sstevel 		 *	Make new dev_t and store in *devp.
113703831d35Sstevel 		 */
113803831d35Sstevel 		if (scsb_debug & 0x0008)
113903831d35Sstevel 			cmn_err(CE_NOTE,
114003831d35Sstevel 			    "sm_open(%d): SCSB_CLONE OPEN", instance);
114103831d35Sstevel 		mutex_enter(&scsb->scsb_mutex);
114203831d35Sstevel 		if ((clone = scsb_queue_ops(scsb, QFIRST_AVAILABLE, 0, NULL,
114303831d35Sstevel 		"scsb_open")) == QOP_FAILED) {
114403831d35Sstevel 			mutex_exit(&scsb->scsb_mutex);
114503831d35Sstevel 			return (ENXIO);
114603831d35Sstevel 		}
114703831d35Sstevel 		clptr = &scsb->clone_devs[clone];
114803831d35Sstevel 		clptr->cl_flags = SCSB_OPEN;
114903831d35Sstevel 		clptr->cl_rq = RD(q);
115003831d35Sstevel 		clptr->cl_minor = SCSB_MAKE_MINOR(instance, clone);
115103831d35Sstevel 		*devp = makedevice(getmajor(*devp), clptr->cl_minor);
115203831d35Sstevel 		scsb->scsb_clopens++;
115303831d35Sstevel 		if (scsb_debug & 0x0008)
115403831d35Sstevel 			cmn_err(CE_NOTE,
115503831d35Sstevel 			    "sm_open(%d): new clone device minor: 0x%x"
115603831d35Sstevel 			    " stream queue is 0x%p",
1157*07d06da5SSurya Prakki 			    instance, clptr->cl_minor, (void *)q);
115803831d35Sstevel 	} else {
115903831d35Sstevel 		/* scsb is being opened as a regular driver */
116003831d35Sstevel 		if (scsb_debug & 0x0008)
116103831d35Sstevel 			cmn_err(CE_NOTE, "sm_open(%d): DEVOPEN", instance);
116203831d35Sstevel 		mutex_enter(&scsb->scsb_mutex);
116303831d35Sstevel 		if (scsb->scsb_state & SCSB_EXCL) {
116403831d35Sstevel 			if (scsb_debug & 0x0008)
116503831d35Sstevel 				cmn_err(CE_NOTE,
116603831d35Sstevel 				    "sm_open(%d): can't open, state is EXCL",
116703831d35Sstevel 				    instance);
116803831d35Sstevel 			mutex_exit(&scsb->scsb_mutex);
116903831d35Sstevel 			return (EBUSY);
117003831d35Sstevel 		}
117103831d35Sstevel 		if (flag & FEXCL) {
117203831d35Sstevel 			if (scsb_debug & 0x0008)
117303831d35Sstevel 				cmn_err(CE_NOTE, "sm_open(%d): is EXCL",
117403831d35Sstevel 				    instance);
117503831d35Sstevel 			if (scsb->scsb_state & SCSB_OPEN) {
117603831d35Sstevel 				if (scsb_debug & 0x0008)
117703831d35Sstevel 					cmn_err(CE_NOTE,
117803831d35Sstevel 					    "sm_open(%d): cannot open EXCL",
117903831d35Sstevel 					    instance);
118003831d35Sstevel 				mutex_exit(&scsb->scsb_mutex);
118103831d35Sstevel 				return (EBUSY);
118203831d35Sstevel 			}
118303831d35Sstevel 			scsb->scsb_state |= SCSB_EXCL;
118403831d35Sstevel 		}
118503831d35Sstevel 		if (scsb->scsb_opens && scsb->scsb_rq != NULL &&
118603831d35Sstevel 		    scsb->scsb_rq != RD(q)) {
118703831d35Sstevel 			if (scsb_debug & 0x000a)
118803831d35Sstevel 				cmn_err(CE_WARN, "sm_open[%d]: q (0x%p) != "
118903831d35Sstevel 				    "scsb_rq (0x%p)",
1190*07d06da5SSurya Prakki 				    instance, (void *)RD(q),
1191*07d06da5SSurya Prakki 				    (void *)scsb->scsb_rq);
119203831d35Sstevel 		}
119303831d35Sstevel 		scsb->scsb_rq = RD(q);
119403831d35Sstevel 		scsb->scsb_opens++;
119503831d35Sstevel 	}
119603831d35Sstevel 	scsb->scsb_state |= SCSB_OPEN;
119703831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
119803831d35Sstevel 	RD(q)->q_ptr = WR(q)->q_ptr = scsb;
119903831d35Sstevel 	qprocson(q);
120003831d35Sstevel 	return (0);
120103831d35Sstevel }
120203831d35Sstevel 
120303831d35Sstevel /*ARGSUSED*/
120403831d35Sstevel static int
120503831d35Sstevel sm_close(queue_t *q, int flag, int otyp, cred_t *credp)
120603831d35Sstevel {
120703831d35Sstevel 	scsb_state_t	*scsb;
120803831d35Sstevel 	int		clone;
120903831d35Sstevel 	clone_dev_t	*clptr = NULL;
121003831d35Sstevel 
121103831d35Sstevel 	scsb = (scsb_state_t *)q->q_ptr;
121203831d35Sstevel 	if (scsb_debug & 0x0009)
1213*07d06da5SSurya Prakki 		cmn_err(CE_NOTE, "sm_close[%d](0x%p)", scsb->scsb_instance,
1214*07d06da5SSurya Prakki 		    (void *)q);
121503831d35Sstevel 	if (scsb->scsb_clopens) {
121603831d35Sstevel 		mutex_enter(&scsb->scsb_mutex);
121703831d35Sstevel 		if ((clone = scsb_queue_ops(scsb, QFIND_QUEUE, 0,
121803831d35Sstevel 		    (void *) RD(q), "scsb_close")) != QOP_FAILED) {
121903831d35Sstevel 			clptr = &scsb->clone_devs[clone];
122003831d35Sstevel 			clptr->cl_flags = 0;
122103831d35Sstevel 			clptr->cl_rq = NULL;
122203831d35Sstevel 			scsb->scsb_clopens--;
122303831d35Sstevel 		}
122403831d35Sstevel 		mutex_exit(&scsb->scsb_mutex);
122503831d35Sstevel 		if (scsb_debug & 0x0008 && clone < SCSB_CLONES_MAX &&
122603831d35Sstevel 		    clone >= SCSB_CLONES_FIRST)
122703831d35Sstevel 			cmn_err(CE_NOTE, "sm_close(%d): SCSB_CLONE 0x%x",
122803831d35Sstevel 			    scsb->scsb_instance, clptr->cl_minor);
122903831d35Sstevel 	}
123003831d35Sstevel 	if (clptr == NULL && scsb->scsb_opens) {
123103831d35Sstevel 		if (scsb_debug & 0x0008)
123203831d35Sstevel 			cmn_err(CE_NOTE, "sm_close(%d): DEVOPEN, opens=%d",
123303831d35Sstevel 			    scsb->scsb_instance, scsb->scsb_opens);
123403831d35Sstevel 		if (RD(q) != scsb->scsb_rq) {
123503831d35Sstevel 			if (scsb_debug & 0x0008)
123603831d35Sstevel 				cmn_err(CE_WARN,
123703831d35Sstevel 				    "sm_close(%d): DEVOPEN, q != scsb_rq",
123803831d35Sstevel 				    scsb->scsb_instance);
123903831d35Sstevel 		}
124003831d35Sstevel 		mutex_enter(&scsb->scsb_mutex);
124103831d35Sstevel 		scsb->scsb_opens = 0;
124203831d35Sstevel 		if (scsb->scsb_state & SCSB_EXCL) {
124303831d35Sstevel 			scsb->scsb_state &= ~SCSB_EXCL;
124403831d35Sstevel 		}
124503831d35Sstevel 		scsb->scsb_rq = (queue_t *)NULL;
124603831d35Sstevel 		mutex_exit(&scsb->scsb_mutex);
124703831d35Sstevel 	}
124803831d35Sstevel 	if (scsb->scsb_opens == 0 && scsb->scsb_clopens == 0) {
124903831d35Sstevel 		scsb->scsb_state &= ~SCSB_OPEN;
125003831d35Sstevel 	}
125103831d35Sstevel 	RD(q)->q_ptr = WR(q)->q_ptr = NULL;
125203831d35Sstevel 	qprocsoff(q);
125303831d35Sstevel 	return (0);
125403831d35Sstevel }
125503831d35Sstevel 
125603831d35Sstevel /*ARGSUSED*/
125703831d35Sstevel static int
125803831d35Sstevel sm_rput(queue_t *q, mblk_t *mp)
125903831d35Sstevel {
126003831d35Sstevel 	if (scsb_debug & 0x0010)
126103831d35Sstevel 		cmn_err(CE_NOTE, "sm_rput");
126203831d35Sstevel 	return (0);
126303831d35Sstevel }
126403831d35Sstevel 
126503831d35Sstevel static int
126603831d35Sstevel sm_wput(queue_t *q, mblk_t *mp)
126703831d35Sstevel {
126803831d35Sstevel 	scsb_state_t	*scsb = (scsb_state_t *)WR(q)->q_ptr;
126903831d35Sstevel 
127003831d35Sstevel 	if (scsb_debug & 0x0010)
1271*07d06da5SSurya Prakki 		cmn_err(CE_NOTE, "sm_wput(%d): mp %p", scsb->scsb_instance,
1272*07d06da5SSurya Prakki 		    (void *)mp);
127303831d35Sstevel 
127403831d35Sstevel 	switch (mp->b_datap->db_type) {
127503831d35Sstevel 	default:
127603831d35Sstevel 		freemsg(mp);
127703831d35Sstevel 		break;
127803831d35Sstevel 
127903831d35Sstevel 	case M_FLUSH:	/* canonical flush handling */
128003831d35Sstevel 		if (*mp->b_rptr & FLUSHW) {
128103831d35Sstevel 			flushq(q, FLUSHDATA);
128203831d35Sstevel 			/* free any messages tied to scsb */
128303831d35Sstevel 		}
128403831d35Sstevel 
128503831d35Sstevel 		if (*mp->b_rptr & FLUSHR) {
128603831d35Sstevel 			*mp->b_rptr &= ~FLUSHW;
128703831d35Sstevel 			qreply(q, mp);
128803831d35Sstevel 		} else
128903831d35Sstevel 			freemsg(mp);
129003831d35Sstevel 		break;
129103831d35Sstevel 
129203831d35Sstevel 	case M_IOCTL:
129303831d35Sstevel 		if (scsb_debug & 0x0010)
129403831d35Sstevel 			cmn_err(CE_NOTE, "sm_wput(%d): M_IOCTL",
129503831d35Sstevel 			    scsb->scsb_instance);
129603831d35Sstevel 		/* do ioctl */
129703831d35Sstevel 		smf_ioctl(q, mp);
129803831d35Sstevel 		break;
129903831d35Sstevel 
130003831d35Sstevel 	case M_DATA:
130103831d35Sstevel 		if (scsb_debug & 0x0010)
130203831d35Sstevel 			cmn_err(CE_NOTE, "sm_wput(%d): M_DATA",
130303831d35Sstevel 			    scsb->scsb_instance);
130403831d35Sstevel 		if (!(scsb->scsb_state & SCSB_UP)) {
130503831d35Sstevel 			freemsg(mp);
130603831d35Sstevel 			return (0);
130703831d35Sstevel 		}
130803831d35Sstevel 		freemsg(mp);
130903831d35Sstevel 		break;
131003831d35Sstevel 
131103831d35Sstevel 	case M_CTL:
131203831d35Sstevel 		if (scsb_debug & 0x0010)
131303831d35Sstevel 			cmn_err(CE_NOTE, "sm_wput(%d): M_CTL",
131403831d35Sstevel 			    scsb->scsb_instance);
131503831d35Sstevel 		freemsg(mp);
131603831d35Sstevel 		break;
131703831d35Sstevel 	}
131803831d35Sstevel 
131903831d35Sstevel 	return (0);
132003831d35Sstevel }
132103831d35Sstevel 
132203831d35Sstevel 
132303831d35Sstevel /*
132403831d35Sstevel  * These are the system monitor upper ioctl functions.
132503831d35Sstevel  */
132603831d35Sstevel static void
132703831d35Sstevel smf_ioctl(queue_t *q, mblk_t *mp)
132803831d35Sstevel {
132903831d35Sstevel 	scsb_state_t	*scsb = (scsb_state_t *)q->q_ptr;
133003831d35Sstevel 	struct iocblk	*iocp = (struct iocblk *)mp->b_rptr;
133103831d35Sstevel 
133203831d35Sstevel 	if (scsb_debug & 0x0020)
133303831d35Sstevel 		cmn_err(CE_NOTE, "smf_ioctl(%d): (%p)->cmd=%x",
1334*07d06da5SSurya Prakki 		    scsb->scsb_instance, (void *)mp, iocp->ioc_cmd);
133503831d35Sstevel 
133603831d35Sstevel 	if (!(scsb->scsb_state & SCSB_UP)) {
133703831d35Sstevel 		miocnak(q, mp, 0, ENXIO);
133803831d35Sstevel 		return;
133903831d35Sstevel 	}
134003831d35Sstevel 	/*
134103831d35Sstevel 	 * Don't fail ALL commands if the SCB removed, since we still want to
134203831d35Sstevel 	 * satisfy some requests from the shadow registers, the last known
134303831d35Sstevel 	 * register contents.
134403831d35Sstevel 	 *
134503831d35Sstevel 	 * if (scsb->scsb_state & SCSB_FROZEN) {
134603831d35Sstevel 	 *	iocp->ioc_error = EAGAIN;
134703831d35Sstevel 	 *	mp->b_datap->db_type = M_IOCNAK;
134803831d35Sstevel 	 *	qreply(q, mp);
134903831d35Sstevel 	 *	return;
135003831d35Sstevel 	 * }
135103831d35Sstevel 	 */
135203831d35Sstevel 
135303831d35Sstevel 	iocp->ioc_error = 0;
135403831d35Sstevel 	switch (iocp->ioc_cmd) {
135503831d35Sstevel 	default:
135603831d35Sstevel 		/* if we don't understand the ioctl */
135703831d35Sstevel 		if (scsb_debug & 0x0022)
135803831d35Sstevel 			cmn_err(CE_NOTE, "smf_ioctl(%d):unkown ioctl %x",
135903831d35Sstevel 			    scsb->scsb_instance, iocp->ioc_cmd);
136003831d35Sstevel 		iocp->ioc_error = EINVAL;
136103831d35Sstevel 		break;
136203831d35Sstevel 
136303831d35Sstevel 	case ENVC_IOC_GETMODE:
136403831d35Sstevel 	{
136503831d35Sstevel 		uint8_t *curr_mode;
136603831d35Sstevel 
136703831d35Sstevel 		iocp->ioc_error = miocpullup(mp, sizeof (uint8_t));
136803831d35Sstevel 		if (iocp->ioc_error != 0)
136903831d35Sstevel 			break;
137003831d35Sstevel 
137103831d35Sstevel 		curr_mode = (uint8_t *)mp->b_cont->b_rptr;
137203831d35Sstevel 		if (scsb->scsb_state & SCSB_DEBUG_MODE)
137303831d35Sstevel 			*curr_mode = (uint8_t)ENVC_DEBUG_MODE;
137403831d35Sstevel 		else if (scsb->scsb_state & SCSB_DIAGS_MODE)
137503831d35Sstevel 			*curr_mode = (uint8_t)ENVCTRL_DIAG_MODE;
137603831d35Sstevel 		else
137703831d35Sstevel 			*curr_mode = (uint8_t)ENVCTRL_NORMAL_MODE;
137803831d35Sstevel 
137903831d35Sstevel 		if (scsb_debug & 0x20) {
138003831d35Sstevel 			cmn_err(CE_NOTE, "IOC_GETMODE: returning mode 0x%x",
138103831d35Sstevel 			    *curr_mode);
138203831d35Sstevel 		}
138303831d35Sstevel 		break;
138403831d35Sstevel 	}
138503831d35Sstevel 
138603831d35Sstevel 	case ENVC_IOC_SETMODE:
138703831d35Sstevel 	{
138803831d35Sstevel 		uint8_t	*curr_mode;
138903831d35Sstevel 
139003831d35Sstevel 		iocp->ioc_error = miocpullup(mp, sizeof (uint8_t));
139103831d35Sstevel 		if (iocp->ioc_error != 0)
139203831d35Sstevel 			break;
139303831d35Sstevel 
139403831d35Sstevel 		curr_mode = (uint8_t *)mp->b_cont->b_rptr;
139503831d35Sstevel 		switch (*curr_mode) {
139603831d35Sstevel 		case ENVCTRL_NORMAL_MODE:
139703831d35Sstevel 			scsb->scsb_state &=
139803831d35Sstevel 			    ~(SCSB_DEBUG_MODE | SCSB_DIAGS_MODE);
139903831d35Sstevel 			break;
140003831d35Sstevel 		case ENVCTRL_DIAG_MODE:
140103831d35Sstevel 			scsb->scsb_state |=  SCSB_DIAGS_MODE;
140203831d35Sstevel 			scsb->scsb_state &= ~SCSB_DEBUG_MODE;
140303831d35Sstevel 			break;
140403831d35Sstevel 		case ENVC_DEBUG_MODE:
140503831d35Sstevel 			if (scsb->scsb_state &
140603831d35Sstevel 			    (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)) {
140703831d35Sstevel 				scsb->scsb_state &= ~SCSB_DIAGS_MODE;
140803831d35Sstevel 				scsb->scsb_state |=  SCSB_DEBUG_MODE;
140903831d35Sstevel 			} else {
141003831d35Sstevel 				iocp->ioc_error = EACCES;
141103831d35Sstevel 			}
141203831d35Sstevel 			break;
141303831d35Sstevel 		default:
141403831d35Sstevel 			if (scsb_debug & 0x22) {
141503831d35Sstevel 				cmn_err(CE_WARN,
141603831d35Sstevel 				    "IOC_SETMODE: Invalid mode 0x%x",
141703831d35Sstevel 				    *curr_mode);
141803831d35Sstevel 			}
141903831d35Sstevel 			iocp->ioc_error = EINVAL;
142003831d35Sstevel 			break;
142103831d35Sstevel 		}
142203831d35Sstevel 		break;
142303831d35Sstevel 	}
142403831d35Sstevel 
142503831d35Sstevel 	case ENVC_IOC_ACQUIRE_SLOT_LED_CTRL:
142603831d35Sstevel 		if (scsb->scsb_state & SCSB_APP_SLOTLED_CTRL)
142703831d35Sstevel 			iocp->ioc_error = EAGAIN;
142803831d35Sstevel 		else {
142903831d35Sstevel 			scsb->scsb_state |= SCSB_APP_SLOTLED_CTRL;
143003831d35Sstevel 			iocp->ioc_error = 0;
143103831d35Sstevel 		}
143203831d35Sstevel 		break;
143303831d35Sstevel 
143403831d35Sstevel 	case ENVC_IOC_RELEASE_SLOT_LED_CTRL:
143503831d35Sstevel 		scsb->scsb_state &= ~SCSB_APP_SLOTLED_CTRL;
143603831d35Sstevel 		iocp->ioc_error = 0;
143703831d35Sstevel 		break;
143803831d35Sstevel 
143903831d35Sstevel 	/*
144003831d35Sstevel 	 * Not an exposed interface, only used by development utilities.
144103831d35Sstevel 	 */
144203831d35Sstevel 	case SCSBIOC_GET_VERSIONS:
144303831d35Sstevel 	{
144403831d35Sstevel 		uint8_t *ppromid, promid;
144503831d35Sstevel 		scsb_ids_t *sids;
144603831d35Sstevel 
144703831d35Sstevel 		if (iocp->ioc_count == sizeof (uint8_t)) {
144803831d35Sstevel 			iocp->ioc_error = miocpullup(mp, sizeof (uint8_t));
144903831d35Sstevel 			if (iocp->ioc_error != 0)
145003831d35Sstevel 				break;
145103831d35Sstevel 
145203831d35Sstevel 			ppromid = (uint8_t *)mp->b_cont->b_rptr;
145303831d35Sstevel 			*ppromid = (uint8_t)(mct_system_info.
145403831d35Sstevel 			    fru_info_list[SCB])->fru_version;
145503831d35Sstevel 			promid = *ppromid;
145603831d35Sstevel 		} else {
145703831d35Sstevel 			iocp->ioc_error = miocpullup(mp, sizeof (scsb_ids_t));
145803831d35Sstevel 			if (iocp->ioc_error != 0)
145903831d35Sstevel 				break;
146003831d35Sstevel 
146103831d35Sstevel 			sids = (scsb_ids_t *)mp->b_cont->b_rptr;
146203831d35Sstevel 			bcopy(modldrv.drv_linkinfo, sids->modldrv_string,
146303831d35Sstevel 			    SCSB_MODSTR_LEN);
146403831d35Sstevel 			bcopy(scsb_build_version, sids->scsb_version,
146503831d35Sstevel 			    SCSB_VERSTR_LEN);
146603831d35Sstevel 			sids->promid = (uint8_t)(mct_system_info.
146703831d35Sstevel 			    fru_info_list[SCB])->fru_version;
146803831d35Sstevel 
146903831d35Sstevel 			promid = sids->promid;
147003831d35Sstevel 			if (scsb_debug & 0x20) {
147103831d35Sstevel 				cmn_err(CE_NOTE,
147203831d35Sstevel 				    "IOC_GET_VERSIONS: sizeof(scsb_ids_t) "
147303831d35Sstevel 				    "= %lu", sizeof (scsb_ids_t));
147403831d35Sstevel 			}
147503831d35Sstevel 		}
147603831d35Sstevel 		if (scsb_debug & 0x20) {
147703831d35Sstevel 			cmn_err(CE_NOTE,
147803831d35Sstevel 			    "IOC_GET_VERSIONS: SCB PROMID = 0x%x", promid);
147903831d35Sstevel 		}
148003831d35Sstevel 		break;
148103831d35Sstevel 	}
148203831d35Sstevel 
148303831d35Sstevel #ifdef	DEBUG
148403831d35Sstevel 	case ENVC_IOC_REGISTER_PID:
148503831d35Sstevel 		iocp->ioc_error = miocpullup(mp, sizeof (pid_t));
148603831d35Sstevel 		if (iocp->ioc_error == 0) {
148703831d35Sstevel 			if (add_event_proc(scsb, *(pid_t *)mp->b_cont->b_rptr))
148803831d35Sstevel 				iocp->ioc_error = ENOMEM;
148903831d35Sstevel 		}
149003831d35Sstevel 		break;
149103831d35Sstevel 
149203831d35Sstevel 	case ENVC_IOC_UNREGISTER_PID:
149303831d35Sstevel 		iocp->ioc_error = miocpullup(mp, sizeof (pid_t));
149403831d35Sstevel 		if (iocp->ioc_error == 0) {
149503831d35Sstevel 			if (del_event_proc(scsb, *(pid_t *)mp->b_cont->b_rptr))
149603831d35Sstevel 				iocp->ioc_error = EINVAL;
149703831d35Sstevel 		}
149803831d35Sstevel 		break;
149903831d35Sstevel 
150003831d35Sstevel 	case SCSBIOC_VALUE_MODE:
150103831d35Sstevel 	{
150203831d35Sstevel 		uint32_t *mode_vals;
150303831d35Sstevel 		int	three_vals = 0;
150403831d35Sstevel 
150503831d35Sstevel 		if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) {
150603831d35Sstevel 			iocp->ioc_error = EINVAL;
150703831d35Sstevel 			break;
150803831d35Sstevel 		}
150903831d35Sstevel 
151003831d35Sstevel 		if (iocp->ioc_count == sizeof (uint32_t) * 3)
151103831d35Sstevel 			three_vals = 1;
151203831d35Sstevel 		else if (iocp->ioc_count != sizeof (uint32_t) * 2) {
151303831d35Sstevel 			iocp->ioc_error = EINVAL;
151403831d35Sstevel 			break;
151503831d35Sstevel 		}
151603831d35Sstevel 
151703831d35Sstevel 		iocp->ioc_error = miocpullup(mp, iocp->ioc_count);
151803831d35Sstevel 		if (iocp->ioc_error != 0)
151903831d35Sstevel 			break;
152003831d35Sstevel 
152103831d35Sstevel 		/*
152203831d35Sstevel 		 * check mode_vals[0] for get/set option.  setting
152303831d35Sstevel 		 * scsb_state is not valid for now.  0 == GET, 1 == SET
152403831d35Sstevel 		 */
152503831d35Sstevel 		mode_vals = (uint32_t *)mp->b_cont->b_rptr;
152603831d35Sstevel 		if (mode_vals[0]) {
152703831d35Sstevel 			scsb_debug = mode_vals[1];
152803831d35Sstevel 		} else {
152903831d35Sstevel 			mode_vals[0] = scsb->scsb_state;
153003831d35Sstevel 			if (three_vals) {
153103831d35Sstevel 				mode_vals[1] = scsb->scsb_hsc_state;
153203831d35Sstevel 				mode_vals[2] = scsb_debug;
153303831d35Sstevel 			} else
153403831d35Sstevel 				mode_vals[1] = scsb_debug;
153503831d35Sstevel 		}
153603831d35Sstevel 		if ((scsb_debug & 0x20) && three_vals) {
153703831d35Sstevel 			cmn_err(CE_NOTE, "IOC_VALUE_MODE: mode_vals: "
153803831d35Sstevel 			    "0x%x/0x%x/0x%x; ioc_count = 0x%lx",
153903831d35Sstevel 			    mode_vals[0], mode_vals[1], mode_vals[2],
154003831d35Sstevel 			    iocp->ioc_count);
154103831d35Sstevel 		}
154203831d35Sstevel 		break;
154303831d35Sstevel 	}
154403831d35Sstevel 
154503831d35Sstevel #ifdef DEBUG
154603831d35Sstevel 	case SCSBIOC_GET_SLOT_INFO:
154703831d35Sstevel 	{
154803831d35Sstevel 		hsc_slot_t	*slot_info = NULL;
154903831d35Sstevel 		uint32_t	*slot_vals;
155003831d35Sstevel 		int		pslotnum;
155103831d35Sstevel 
155203831d35Sstevel 		if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) {
155303831d35Sstevel 			iocp->ioc_error = EINVAL;
155403831d35Sstevel 			break;
155503831d35Sstevel 		}
155603831d35Sstevel 
155703831d35Sstevel 		iocp->ioc_error = miocpullup(mp, sizeof (uint32_t) * 2);
155803831d35Sstevel 		if (iocp->ioc_error != 0)
155903831d35Sstevel 			break;
156003831d35Sstevel 
156103831d35Sstevel 		slot_vals = (uint32_t *)mp->b_cont->b_rptr;
156203831d35Sstevel 		pslotnum = (int)*slot_vals;
1563*07d06da5SSurya Prakki 		hsc_ac_op((int)scsb->scsb_instance, pslotnum,
156403831d35Sstevel 		    SCSB_HSC_AC_GET_SLOT_INFO, &slot_info);
156503831d35Sstevel 		if (slot_info == NULL) {
156603831d35Sstevel 			iocp->ioc_error = ENODEV;
156703831d35Sstevel 			break;
156803831d35Sstevel 		}
156903831d35Sstevel 		*slot_vals = (uint32_t)slot_info->hs_flags;
157003831d35Sstevel 		*(++slot_vals) = (uint32_t)slot_info->hs_slot_state;
157103831d35Sstevel 		if (scsb_debug & 0x20) {
157203831d35Sstevel 			cmn_err(CE_NOTE, "IOC_GET_SLOT_STATE: slot_vals: "
157303831d35Sstevel 			    "0x%x/0x%x; ioc_count = 0x%lx",
157403831d35Sstevel 			    slot_vals[0], slot_vals[1], iocp->ioc_count);
157503831d35Sstevel 		}
157603831d35Sstevel 		break;
157703831d35Sstevel 	}
157803831d35Sstevel #endif /* DEBUG */
157903831d35Sstevel 
158003831d35Sstevel 	case SCSBIOC_GET_FAN_STATUS:
158103831d35Sstevel 	case SCSBIOC_GET_INTR_ARRAY:
158203831d35Sstevel 		/* for now we don't understand these ioctls */
158303831d35Sstevel 		if (scsb_debug & 0x0022)
158403831d35Sstevel 			cmn_err(CE_NOTE, "smf_ioctl(%d):unknown ioctl %x",
158503831d35Sstevel 			    scsb->scsb_instance, iocp->ioc_cmd);
158603831d35Sstevel 		iocp->ioc_error = EINVAL;
158703831d35Sstevel 		break;
158803831d35Sstevel #endif	/* DEBUG */
158903831d35Sstevel 
159003831d35Sstevel 	case SCSBIOC_LED_OK_GET:
159103831d35Sstevel 	case SCSBIOC_LED_NOK_GET:
159203831d35Sstevel 	case SCSBIOC_LED_OK_SET:
159303831d35Sstevel 	case SCSBIOC_LED_NOK_SET:
159403831d35Sstevel 	case SCSBIOC_BHEALTHY_GET:
159503831d35Sstevel 	case SCSBIOC_SLOT_OCCUPANCY:
159603831d35Sstevel 	case SCSBIOC_RESET_UNIT:
159703831d35Sstevel 		if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) {
159803831d35Sstevel 			iocp->ioc_error = EACCES;
159903831d35Sstevel 			break;
160003831d35Sstevel 		}
160103831d35Sstevel 		/*FALLTHROUGH*/
160203831d35Sstevel 
160303831d35Sstevel 	case ENVC_IOC_GETDSKLED:
160403831d35Sstevel 	case ENVC_IOC_SETDSKLED:
160503831d35Sstevel 	case ENVC_IOC_SETFSP:
160603831d35Sstevel 	{
160703831d35Sstevel 		scsb_uinfo_t *suip;
160803831d35Sstevel 
160903831d35Sstevel 		iocp->ioc_error = miocpullup(mp, sizeof (scsb_uinfo_t));
161003831d35Sstevel 		if (iocp->ioc_error != 0)
161103831d35Sstevel 			break;
161203831d35Sstevel 
161303831d35Sstevel 		suip = (scsb_uinfo_t *)mp->b_cont->b_rptr;
161403831d35Sstevel 		switch (iocp->ioc_cmd) {
161503831d35Sstevel 		case SCSBIOC_LED_OK_GET:
161603831d35Sstevel 			iocp->ioc_error = scsb_led_get(scsb, suip, OK);
161703831d35Sstevel 			break;
161803831d35Sstevel 		case SCSBIOC_LED_NOK_GET:
161903831d35Sstevel 			iocp->ioc_error = scsb_led_get(scsb, suip, NOK);
162003831d35Sstevel 			break;
162103831d35Sstevel 		case SCSBIOC_LED_OK_SET:
162203831d35Sstevel 			iocp->ioc_error = scsb_led_set(scsb, suip, OK);
162303831d35Sstevel 			break;
162403831d35Sstevel 		case SCSBIOC_LED_NOK_SET:
162503831d35Sstevel 			iocp->ioc_error = scsb_led_set(scsb, suip, NOK);
162603831d35Sstevel 			break;
162703831d35Sstevel 		case SCSBIOC_BHEALTHY_GET:
162803831d35Sstevel 			iocp->ioc_error = scsb_bhealthy_slot(scsb, suip);
162903831d35Sstevel 			break;
163003831d35Sstevel 		case SCSBIOC_SLOT_OCCUPANCY:
163103831d35Sstevel 			iocp->ioc_error = scsb_slot_occupancy(scsb, suip);
163203831d35Sstevel 			break;
163303831d35Sstevel 		case SCSBIOC_RESET_UNIT:
163403831d35Sstevel 			iocp->ioc_error = scsb_reset_unit(scsb, suip);
163503831d35Sstevel 			break;
163603831d35Sstevel 		case ENVC_IOC_GETDSKLED:
163703831d35Sstevel 			if (suip->unit_type != DISK) {
163803831d35Sstevel 				iocp->ioc_error = EINVAL;
163903831d35Sstevel 				break;
164003831d35Sstevel 			}
164103831d35Sstevel 			iocp->ioc_error = scsb_led_get(scsb, suip, NOUSE);
164203831d35Sstevel 			break;
164303831d35Sstevel 		case ENVC_IOC_SETDSKLED:
164403831d35Sstevel 			if (suip->unit_type != DISK) {
164503831d35Sstevel 				iocp->ioc_error = EINVAL;
164603831d35Sstevel 				break;
164703831d35Sstevel 			}
164803831d35Sstevel 			iocp->ioc_error = scsb_led_set(scsb, suip, NOUSE);
164903831d35Sstevel 			break;
165003831d35Sstevel 		case ENVC_IOC_SETFSP:
165103831d35Sstevel 			if (scsb->scsb_state & SCSB_FROZEN) {
165203831d35Sstevel 				iocp->ioc_error = EAGAIN;
165303831d35Sstevel 				break;
165403831d35Sstevel 			}
165503831d35Sstevel 			iocp->ioc_error = scsb_led_set(scsb, suip, NOUSE);
165603831d35Sstevel 			break;
165703831d35Sstevel 		}
165803831d35Sstevel 		break;
165903831d35Sstevel 	}
166003831d35Sstevel 
166103831d35Sstevel 	case SCSBIOC_FAKE_INTR: {
166203831d35Sstevel 		uint32_t	ui;
166303831d35Sstevel 
166403831d35Sstevel 		if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) {
166503831d35Sstevel 			iocp->ioc_error = EINVAL;
166603831d35Sstevel 			break;
166703831d35Sstevel 		}
166803831d35Sstevel 		if (mp->b_cont == NULL)
166903831d35Sstevel 			ui = 0;
167003831d35Sstevel 		else {
167103831d35Sstevel 			iocp->ioc_error = miocpullup(mp, sizeof (uint32_t));
167203831d35Sstevel 			if (iocp->ioc_error != 0)
167303831d35Sstevel 				break;
167403831d35Sstevel 			ui = *(uint32_t *)mp->b_cont->b_rptr;
167503831d35Sstevel 		}
167603831d35Sstevel 		iocp->ioc_error = scsb_fake_intr(scsb, ui);
167703831d35Sstevel 		break;
167803831d35Sstevel 	}
167903831d35Sstevel 
168003831d35Sstevel 	case SCSBIOC_GET_STATUS :
168103831d35Sstevel 		if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) {
168203831d35Sstevel 			iocp->ioc_error = EINVAL;
168303831d35Sstevel 			break;
168403831d35Sstevel 		}
168503831d35Sstevel 		iocp->ioc_error = miocpullup(mp, sizeof (scsb_status_t));
168603831d35Sstevel 		if (iocp->ioc_error == 0)
168703831d35Sstevel 			iocp->ioc_error = scsb_get_status(scsb,
168803831d35Sstevel 			    (scsb_status_t *)mp->b_cont->b_rptr);
168903831d35Sstevel 		break;
169003831d35Sstevel 
169103831d35Sstevel 	case SCSBIOC_ALL_LEDS_ON :
169203831d35Sstevel 		if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)))
169303831d35Sstevel 			iocp->ioc_error = EACCES;
169403831d35Sstevel 		else
169503831d35Sstevel 			iocp->ioc_error = scsb_leds_switch(scsb, ON);
169603831d35Sstevel 		break;
169703831d35Sstevel 
169803831d35Sstevel 	case SCSBIOC_ALL_LEDS_OFF :
169903831d35Sstevel 		if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)))
170003831d35Sstevel 			iocp->ioc_error = EACCES;
170103831d35Sstevel 		else
170203831d35Sstevel 			iocp->ioc_error = scsb_leds_switch(scsb, OFF);
170303831d35Sstevel 		break;
170403831d35Sstevel 
170503831d35Sstevel 	case SCSBIOC_REG_READ:
170603831d35Sstevel 	case SCSBIOC_REG_WRITE:
170703831d35Sstevel 		if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) {
170803831d35Sstevel 			iocp->ioc_error = EACCES;
170903831d35Sstevel 		} else {
171003831d35Sstevel 			scsb_ioc_rdwr_t	*iocrdwrp;
171103831d35Sstevel 
171203831d35Sstevel 			if (scsb->scsb_state & SCSB_FROZEN &&
171303831d35Sstevel 			    !(scsb->scsb_state & SCSB_DEBUG_MODE)) {
171403831d35Sstevel 				iocp->ioc_error = EAGAIN;
171503831d35Sstevel 				break;
171603831d35Sstevel 			}
171703831d35Sstevel 
171803831d35Sstevel 			iocp->ioc_error = miocpullup(mp, sizeof (*iocrdwrp));
171903831d35Sstevel 			if (iocp->ioc_error == 0) {
172003831d35Sstevel 				iocrdwrp =
172103831d35Sstevel 				    (scsb_ioc_rdwr_t *)mp->b_cont->b_rptr;
172203831d35Sstevel 
172303831d35Sstevel 				if (iocp->ioc_cmd == SCSBIOC_REG_READ) {
172403831d35Sstevel 					if (iocrdwrp->ioc_rlen > 0) {
172503831d35Sstevel 						sm_ioc_rdwr(q, mp, I2C_WR_RD);
172603831d35Sstevel 						return;
172703831d35Sstevel 					}
172803831d35Sstevel 				} else {
172903831d35Sstevel 					if (iocrdwrp->ioc_wlen > 0) {
173003831d35Sstevel 						sm_ioc_rdwr(q, mp, I2C_WR);
173103831d35Sstevel 						return;
173203831d35Sstevel 					}
173303831d35Sstevel 				}
173403831d35Sstevel 				iocp->ioc_error = EINVAL;
173503831d35Sstevel 				break;
173603831d35Sstevel 			}
173703831d35Sstevel 		}
173803831d35Sstevel 		break;
173903831d35Sstevel 
174003831d35Sstevel 	case SCSBIOC_SHUTDOWN_POLL:
174103831d35Sstevel 	case SCSBIOC_INTEVENT_POLL:
174203831d35Sstevel 		if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) {
174303831d35Sstevel 			iocp->ioc_error = EINVAL;
174403831d35Sstevel 			break;
174503831d35Sstevel 		}
174603831d35Sstevel 		iocp->ioc_error = miocpullup(mp, sizeof (uint32_t));
174703831d35Sstevel 		if (iocp->ioc_error == 0)
174803831d35Sstevel 			iocp->ioc_error = scsb_polled_int(scsb, iocp->ioc_cmd,
174903831d35Sstevel 			    (uint32_t *)mp->b_cont->b_rptr);
175003831d35Sstevel 		break;
175103831d35Sstevel 
175203831d35Sstevel 	case SCSBIOC_RESTORE :
175303831d35Sstevel 		if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)))
175403831d35Sstevel 			iocp->ioc_error = EACCES;
175503831d35Sstevel 		else {
175603831d35Sstevel 			scsb_restore(scsb);
1757*07d06da5SSurya Prakki 			(void) scsb_toggle_psmint(scsb, 1);
175803831d35Sstevel 			iocp->ioc_error = 0;
175903831d35Sstevel 		}
176003831d35Sstevel 		break;
176103831d35Sstevel 
176203831d35Sstevel 	case SCSBIOC_FREEZE :
176303831d35Sstevel 		if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)))
176403831d35Sstevel 			iocp->ioc_error = EACCES;
176503831d35Sstevel 		else {
176603831d35Sstevel 			scsb_freeze_check(scsb);
176703831d35Sstevel 			scsb_freeze(scsb);
176803831d35Sstevel 			iocp->ioc_error = 0;
176903831d35Sstevel 		}
177003831d35Sstevel 		break;
177103831d35Sstevel 
177203831d35Sstevel 	/*
177303831d35Sstevel 	 * envmond:alarmcard.so response to SCTRL_EVENT_ALARM_INSERTION
177403831d35Sstevel 	 */
177503831d35Sstevel 	case ENVC_IOC_ACCONF_RESTORED:
177603831d35Sstevel 		(void) scsb_hsc_ac_op(scsb, scsb->ac_slotnum,
177703831d35Sstevel 		    SCSB_HSC_AC_SET_BUSY);
177803831d35Sstevel 		break;
177903831d35Sstevel 
178003831d35Sstevel 	/*
178103831d35Sstevel 	 * envmond:alarmcard.so response to SCTRL_EVENT_ALARM_REMOVAL
178203831d35Sstevel 	 */
178303831d35Sstevel 	case ENVC_IOC_ACCONF_STORED:
178403831d35Sstevel 		if (scsb->scsb_state & SCSB_FROZEN) {
178503831d35Sstevel 			iocp->ioc_error = EAGAIN;
178603831d35Sstevel 			break;
178703831d35Sstevel 		}
178803831d35Sstevel 		(void) scsb_hsc_ac_op(scsb, scsb->ac_slotnum,
178903831d35Sstevel 		    SCSB_HSC_AC_UNCONFIGURE);
179003831d35Sstevel 		break;
179103831d35Sstevel 
179203831d35Sstevel #ifdef	DEBUG
179303831d35Sstevel 	case SCSBIOC_TOPOLOGY_DUMP:
179403831d35Sstevel 		if (!(scsb->scsb_state & SCSB_DEBUG_MODE))
179503831d35Sstevel 			iocp->ioc_error = EINVAL;
179603831d35Sstevel 		else {
179703831d35Sstevel 			mct_topology_dump(scsb, 1);
179803831d35Sstevel 			iocp->ioc_error = 0;
179903831d35Sstevel 		}
180003831d35Sstevel 		break;
180103831d35Sstevel #endif
180203831d35Sstevel 	}
180303831d35Sstevel 	if (iocp->ioc_error)
180403831d35Sstevel 		mp->b_datap->db_type = M_IOCNAK;
180503831d35Sstevel 	else
180603831d35Sstevel 		mp->b_datap->db_type = M_IOCACK;
180703831d35Sstevel 	qreply(q, mp);
180803831d35Sstevel }
180903831d35Sstevel 
181003831d35Sstevel static fru_info_t *
181103831d35Sstevel find_fru_info(fru_id_t fru_id)
181203831d35Sstevel {
181303831d35Sstevel 	int		i;
181403831d35Sstevel 	fru_info_t	*fru_ptr;
181503831d35Sstevel 
181603831d35Sstevel 	if (scsb_debug & 0x00100001)
181703831d35Sstevel 		cmn_err(CE_NOTE, "find_fru_info(0x%x)", fru_id);
181803831d35Sstevel 	if (fru_id == (fru_id_t)0)
181903831d35Sstevel 		return ((fru_info_t *)NULL);
182003831d35Sstevel 	for (i = 0; i < SCSB_UNIT_TYPES; ++i) {
182103831d35Sstevel 		fru_ptr = mct_system_info.fru_info_list[i];
182203831d35Sstevel 		while (fru_ptr != NULL) {
182303831d35Sstevel 			if (fru_ptr->fru_id == fru_id)
182403831d35Sstevel 				return (fru_ptr);
182503831d35Sstevel 			fru_ptr = fru_ptr->next;
182603831d35Sstevel 		}
182703831d35Sstevel 	}
182803831d35Sstevel 	return ((fru_info_t *)NULL);
182903831d35Sstevel }
183003831d35Sstevel 
183103831d35Sstevel 
183203831d35Sstevel struct scsb_cb_entry {
183303831d35Sstevel 	void			*cb_softstate_ptr;
183403831d35Sstevel 	fru_id_t		cb_fru_id;
183503831d35Sstevel 	scsb_fru_event_t	cb_event;
183603831d35Sstevel 	void			(*cb_func)
183703831d35Sstevel 				(void *, scsb_fru_event_t, scsb_fru_status_t);
183803831d35Sstevel 	fru_info_t		*cb_fru_ptr;
183903831d35Sstevel 	struct scsb_cb_entry	*cb_next;
184003831d35Sstevel };
184103831d35Sstevel 
184203831d35Sstevel #ifdef DEBUG
184303831d35Sstevel int	scsb_cb_count = 0;
184403831d35Sstevel #else
184503831d35Sstevel static
184603831d35Sstevel #endif
184703831d35Sstevel struct scsb_cb_entry	*scsb_cb_table;
184803831d35Sstevel 
184903831d35Sstevel /*
185003831d35Sstevel  * global function for interested FRU drivers to register a callback function,
185103831d35Sstevel  * to be called when FRU presence status changes.
185203831d35Sstevel  */
185303831d35Sstevel scsb_fru_status_t
185403831d35Sstevel scsb_fru_register(void (*cb_func)(void *, scsb_fru_event_t, scsb_fru_status_t),
185503831d35Sstevel 			void *soft_ptr, fru_id_t fru_id)
185603831d35Sstevel {
185703831d35Sstevel 	struct scsb_cb_entry	*cbe_ptr;
185803831d35Sstevel 
185903831d35Sstevel 	if (scsb_debug & 0x00800001) {
186003831d35Sstevel 		cmn_err(CE_NOTE,
186103831d35Sstevel 		    "scsb_fru_register: FRU_ID 0x%x", (int)fru_id);
186203831d35Sstevel 	}
186303831d35Sstevel 	if (!(scsb_global_state & SCSB_UP)) {
186403831d35Sstevel 		return (FRU_NOT_AVAILABLE);
186503831d35Sstevel 	}
186603831d35Sstevel 	if (cb_func == NULL || fru_id == (fru_id_t)0)
186703831d35Sstevel 		return (FRU_NOT_AVAILABLE);
186803831d35Sstevel 	if (scsb_cb_table == NULL)
186903831d35Sstevel 		scsb_cb_table = (struct scsb_cb_entry *)
187003831d35Sstevel 		    kmem_zalloc(sizeof (struct scsb_cb_entry), KM_SLEEP);
187103831d35Sstevel 	cbe_ptr = scsb_cb_table;
187203831d35Sstevel 	while (cbe_ptr->cb_softstate_ptr != NULL) {
187303831d35Sstevel 		if (cbe_ptr->cb_next == (struct scsb_cb_entry *)NULL) {
187403831d35Sstevel 			cbe_ptr->cb_next = (struct scsb_cb_entry *)
187503831d35Sstevel 			    kmem_zalloc(sizeof (struct scsb_cb_entry),
187603831d35Sstevel 			    KM_SLEEP);
187703831d35Sstevel 			cbe_ptr = cbe_ptr->cb_next;
187803831d35Sstevel 			break;
187903831d35Sstevel 		}
188003831d35Sstevel 		cbe_ptr = cbe_ptr->cb_next;
188103831d35Sstevel 	}
188203831d35Sstevel 	cbe_ptr->cb_softstate_ptr = soft_ptr;
188303831d35Sstevel 	cbe_ptr->cb_fru_id = fru_id;
188403831d35Sstevel 	cbe_ptr->cb_func = cb_func;
188503831d35Sstevel 	cbe_ptr->cb_next = (struct scsb_cb_entry *)NULL;
188603831d35Sstevel 	cbe_ptr->cb_fru_ptr = find_fru_info(fru_id);
188703831d35Sstevel #ifdef DEBUG
188803831d35Sstevel 	scsb_cb_count++;
188903831d35Sstevel #endif
189003831d35Sstevel 	if (scsb_debug & 0x00800000) {
189103831d35Sstevel 		cmn_err(CE_NOTE,
189203831d35Sstevel 		    "scsb_fru_register: FRU_ID 0x%x, status=%d",
189303831d35Sstevel 		    (int)fru_id,
189403831d35Sstevel 		    (cbe_ptr->cb_fru_ptr == (fru_info_t *)NULL) ?
189503831d35Sstevel 		    0xff : cbe_ptr->cb_fru_ptr->fru_status);
189603831d35Sstevel 	}
189703831d35Sstevel 	if (cbe_ptr->cb_fru_ptr == (fru_info_t *)NULL)
189803831d35Sstevel 		return (FRU_NOT_AVAILABLE);
189903831d35Sstevel 	if (cbe_ptr->cb_fru_ptr->fru_status & FRU_PRESENT)
190003831d35Sstevel 		return (FRU_PRESENT);
190103831d35Sstevel 	return (FRU_NOT_PRESENT);
190203831d35Sstevel }
190303831d35Sstevel 
190403831d35Sstevel void
190503831d35Sstevel scsb_fru_unregister(void *soft_ptr, fru_id_t fru_id)
190603831d35Sstevel {
190703831d35Sstevel 	struct scsb_cb_entry	*prev_ptr, *cbe_ptr;
190803831d35Sstevel 
190903831d35Sstevel 	if (scsb_debug & 0x00800001) {
191003831d35Sstevel 		cmn_err(CE_NOTE, "scsb_fru_unregister(0x%p, 0x%x)",
191103831d35Sstevel 		    soft_ptr, (int)fru_id);
191203831d35Sstevel 	}
191303831d35Sstevel 	if ((cbe_ptr = scsb_cb_table) == NULL || fru_id == (fru_id_t)0)
191403831d35Sstevel 		return;
191503831d35Sstevel 	prev_ptr = cbe_ptr;
191603831d35Sstevel 	do {
191703831d35Sstevel 		if (cbe_ptr->cb_softstate_ptr == soft_ptr &&
191803831d35Sstevel 		    cbe_ptr->cb_fru_id == fru_id) {
191903831d35Sstevel 			if (cbe_ptr == scsb_cb_table)
192003831d35Sstevel 				scsb_cb_table = cbe_ptr->cb_next;
192103831d35Sstevel 			else
192203831d35Sstevel 				prev_ptr->cb_next = cbe_ptr->cb_next;
192303831d35Sstevel 			kmem_free(cbe_ptr, sizeof (struct scsb_cb_entry));
192403831d35Sstevel #ifdef DEBUG
192503831d35Sstevel 			scsb_cb_count--;
192603831d35Sstevel #endif
192703831d35Sstevel 			return;
192803831d35Sstevel 		}
192903831d35Sstevel 		prev_ptr = cbe_ptr;
193003831d35Sstevel 	} while ((cbe_ptr = cbe_ptr->cb_next) != NULL);
193103831d35Sstevel }
193203831d35Sstevel 
193303831d35Sstevel /*
193403831d35Sstevel  * global function for interested FRU drivers to call to check
193503831d35Sstevel  * FRU presence status.
193603831d35Sstevel  */
193703831d35Sstevel scsb_fru_status_t
193803831d35Sstevel scsb_fru_status(uchar_t fru_id)
193903831d35Sstevel {
194003831d35Sstevel 	fru_info_t		*fru_ptr;
194103831d35Sstevel 
194203831d35Sstevel 	fru_ptr = find_fru_info(fru_id);
194303831d35Sstevel 	if (scsb_debug & 0x00800001) {
194403831d35Sstevel 		cmn_err(CE_NOTE, "scsb_fru_status(0x%x): status=0x%x",
194503831d35Sstevel 		    fru_id, (fru_ptr == (fru_info_t *)NULL) ? 0xff :
194603831d35Sstevel 		    (int)fru_ptr->fru_status);
194703831d35Sstevel 	}
194803831d35Sstevel 	if (fru_ptr == (fru_info_t *)NULL)
194903831d35Sstevel 		return (FRU_NOT_AVAILABLE);
195003831d35Sstevel 	return (fru_ptr->fru_status);
195103831d35Sstevel }
195203831d35Sstevel 
195303831d35Sstevel /*
195403831d35Sstevel  * Global function for the other interruptible FRU device sharing the
195503831d35Sstevel  * same interrupt line to register the interrupt handler with scsb.
195603831d35Sstevel  * This enables all the handlers to be called whenever the interrupt
195703831d35Sstevel  * line is asserted by anyone shaing the interrupt line.
195803831d35Sstevel  */
195903831d35Sstevel 
196003831d35Sstevel /*
196103831d35Sstevel  * The interrupt handler table is currently a linked list. probably a
196203831d35Sstevel  * hash table will be more efficient. Usage of these facilities can
196303831d35Sstevel  * happen even before scsb is attached, so do not depend on scsb
196403831d35Sstevel  * structure being present.
196503831d35Sstevel  */
196603831d35Sstevel struct fru_intr_entry {
196703831d35Sstevel 	void	*softstate_ptr;
196803831d35Sstevel 	int	(*fru_intr_handler)(void *);
196903831d35Sstevel 	fru_id_t	fru_id;
197003831d35Sstevel 	struct fru_intr_entry	*fru_intr_next;
197103831d35Sstevel } *fru_intr_table = NULL;
197203831d35Sstevel 
197303831d35Sstevel int
197403831d35Sstevel scsb_intr_register(int (*intr_handler)(void *), void * soft_ptr,
197503831d35Sstevel 		fru_id_t fru_id)
197603831d35Sstevel {
197703831d35Sstevel 	struct fru_intr_entry *intr_table_entry;
197803831d35Sstevel 	intr_table_entry = (struct fru_intr_entry *)
197903831d35Sstevel 	    kmem_zalloc(sizeof (struct fru_intr_entry), KM_SLEEP);
198003831d35Sstevel 
198103831d35Sstevel 	if (intr_table_entry == NULL) {
198203831d35Sstevel 		return (DDI_FAILURE);
198303831d35Sstevel 	}
198403831d35Sstevel 
198503831d35Sstevel 	if (intr_handler == NULL || soft_ptr == NULL || fru_id == 0) {
198603831d35Sstevel 		kmem_free(intr_table_entry, sizeof (struct fru_intr_entry));
198703831d35Sstevel 		return (DDI_FAILURE);
198803831d35Sstevel 	}
198903831d35Sstevel 
199003831d35Sstevel 	intr_table_entry->softstate_ptr = soft_ptr;
199103831d35Sstevel 	intr_table_entry->fru_intr_handler = intr_handler;
199203831d35Sstevel 	intr_table_entry->fru_id = fru_id;
199303831d35Sstevel 	intr_table_entry->fru_intr_next = fru_intr_table;
199403831d35Sstevel 	fru_intr_table = intr_table_entry;
199503831d35Sstevel 
199603831d35Sstevel 	return (DDI_SUCCESS);
199703831d35Sstevel }
199803831d35Sstevel 
199903831d35Sstevel /*
200003831d35Sstevel  * Removed interrupt_handler of fru from interrupt call chain
200103831d35Sstevel  */
200203831d35Sstevel void
200303831d35Sstevel scsb_intr_unregister(fru_id_t fru_id)
200403831d35Sstevel {
200503831d35Sstevel 	struct fru_intr_entry *intr_entry = fru_intr_table,
200603831d35Sstevel 	    *prev_entry = intr_entry;
200703831d35Sstevel 
200803831d35Sstevel 	if (fru_id == 0) {
200903831d35Sstevel 		return;
201003831d35Sstevel 	}
201103831d35Sstevel 
201203831d35Sstevel 	do {
201303831d35Sstevel 		if (intr_entry->fru_id == fru_id) {
201403831d35Sstevel 			/* found a match, remove entry */
201503831d35Sstevel 			if (intr_entry == fru_intr_table)
201603831d35Sstevel 				fru_intr_table = intr_entry->fru_intr_next;
201703831d35Sstevel 			else
201803831d35Sstevel 				prev_entry->fru_intr_next =
201903831d35Sstevel 				    intr_entry->fru_intr_next;
202003831d35Sstevel 
202103831d35Sstevel 			kmem_free(intr_entry,
202203831d35Sstevel 			    sizeof (struct fru_intr_entry));
202303831d35Sstevel 			return;
202403831d35Sstevel 		}
202503831d35Sstevel 		prev_entry = intr_entry;
202603831d35Sstevel 
202703831d35Sstevel 	} while ((intr_entry = intr_entry->fru_intr_next) != NULL);
202803831d35Sstevel }
202903831d35Sstevel 
203003831d35Sstevel /*
203103831d35Sstevel  * Invoke all the registered interrupt handlers, whenever scsb_intr
203203831d35Sstevel  * is called. This function will go through the list of entries
203303831d35Sstevel  * in the fru interrupt table and invoke each function. Returns
203403831d35Sstevel  * whether interrupt is claimed or unclaimed.
203503831d35Sstevel  */
203603831d35Sstevel static int
203703831d35Sstevel scsb_invoke_intr_chain()
203803831d35Sstevel {
203903831d35Sstevel 	int retval = DDI_INTR_UNCLAIMED;
204003831d35Sstevel 	struct fru_intr_entry *intr_entry = fru_intr_table;
204103831d35Sstevel 
204203831d35Sstevel 	while (intr_entry != NULL) {
204303831d35Sstevel 		retval = (*intr_entry->
204403831d35Sstevel 		    fru_intr_handler)(intr_entry->softstate_ptr);
204503831d35Sstevel 		if (retval == DDI_INTR_CLAIMED) {
204603831d35Sstevel 			return (retval);
204703831d35Sstevel 		}
204803831d35Sstevel 
204903831d35Sstevel 		intr_entry = intr_entry->fru_intr_next;
205003831d35Sstevel 	}
205103831d35Sstevel 
205203831d35Sstevel 	return (retval);
205303831d35Sstevel }
205403831d35Sstevel 
205503831d35Sstevel 
205603831d35Sstevel /*
205703831d35Sstevel  * The scsb_ioc_rdwr_t is similar enough to an i2c_transfer_t that we can
205803831d35Sstevel  * translate the structures and use the i2c_transfer() service.
205903831d35Sstevel  */
206003831d35Sstevel static void
206103831d35Sstevel sm_ioc_rdwr(queue_t *q, mblk_t *mp, int op)
206203831d35Sstevel {
206303831d35Sstevel 	scsb_state_t	*scsb = (scsb_state_t *)q->q_ptr;
206403831d35Sstevel 	struct iocblk	*iocp = (struct iocblk *)mp->b_rptr;
206503831d35Sstevel 	scsb_ioc_rdwr_t	*iocrdwrp;
206603831d35Sstevel 	int		len, error;
206703831d35Sstevel 	uchar_t		*uc, reg;
206803831d35Sstevel 
206903831d35Sstevel 	if (scsb_debug & 0x0040)
207003831d35Sstevel 		cmn_err(CE_CONT, "sm_ioc_rdwr[%d]:", scsb->scsb_instance);
207103831d35Sstevel 	iocrdwrp  = (scsb_ioc_rdwr_t *)mp->b_cont->b_rptr;
207203831d35Sstevel 	if (op == I2C_WR) {
207303831d35Sstevel 		len = iocrdwrp->ioc_wlen;
207403831d35Sstevel 		uc = iocrdwrp->ioc_wbuf;
207503831d35Sstevel 	} else {
207603831d35Sstevel 		len = iocrdwrp->ioc_rlen;
207703831d35Sstevel 		uc = iocrdwrp->ioc_rbuf;
207803831d35Sstevel 	}
207903831d35Sstevel 	/*
208003831d35Sstevel 	 * Check SCB register index boundries and requested len of read/write
208103831d35Sstevel 	 */
208203831d35Sstevel 	reg = iocrdwrp->ioc_regindex;
208303831d35Sstevel 	if (reg < SCSB_REG_ADDR_START || (reg + len) >
208403831d35Sstevel 	    (SCSB_REG_ADDR_START + SCTRL_TOTAL_NUMREGS))
208503831d35Sstevel 		error = EINVAL;
208603831d35Sstevel 	else
208703831d35Sstevel 		error = scsb_rdwr_register(scsb, op, reg, len, uc, 1);
208803831d35Sstevel 	if (error) {
208903831d35Sstevel 		if (scsb_debug & 0x0042)
209003831d35Sstevel 			cmn_err(CE_WARN,
209103831d35Sstevel 			    "sm_ioc_rdwr: rdwr_register failure: %d", error);
209203831d35Sstevel 		mp->b_datap->db_type = M_IOCNAK;
209303831d35Sstevel 	} else
209403831d35Sstevel 		mp->b_datap->db_type = M_IOCACK;
209503831d35Sstevel 	iocp->ioc_error = error;
209603831d35Sstevel 	qreply(q, mp);
209703831d35Sstevel }
209803831d35Sstevel 
209903831d35Sstevel /*
210003831d35Sstevel  * names for (scsb_utype_t) FRU types
210103831d35Sstevel  */
210203831d35Sstevel static char *led_name[SCSB_LED_TYPES] = { "NOK", "OK" };
210303831d35Sstevel static char *unit_type_name[SCSB_UNIT_TYPES] = {
210403831d35Sstevel 	"SLOT", "PDU", "POWER SUPPLY", "DISK", "FAN", "ALARM",
210503831d35Sstevel 	"SCB",  "SSB", "CFTM", "CRTM", "PRTM"
210603831d35Sstevel };
210703831d35Sstevel 
210803831d35Sstevel /*
210903831d35Sstevel  * Discover the register and bit-offset for LEDs and Reset registers,
211003831d35Sstevel  * according to unit_type, unit_number, and led_type.
211103831d35Sstevel  */
211203831d35Sstevel static int
211303831d35Sstevel scsb_get_led_regnum(scsb_state_t	*scsb,
211403831d35Sstevel 		    scsb_uinfo_t	*suip,
211503831d35Sstevel 		    uchar_t		*regptr,
211603831d35Sstevel 		    int			*unitptr,
211703831d35Sstevel 		    scsb_led_t		led_type)
211803831d35Sstevel {
211903831d35Sstevel 	int		code, base, error;
212003831d35Sstevel 
212103831d35Sstevel 	/* OK here means presence (OK) LEDs */
212203831d35Sstevel 	if (led_type == OK)
212303831d35Sstevel 		base = (SCTRL_LED_OK_BASE);
212403831d35Sstevel 	else
212503831d35Sstevel 		base = (SCTRL_LED_NOK_BASE);
212603831d35Sstevel 	error = 0;
212703831d35Sstevel 	if (scsb_debug & 0x0100) {
212803831d35Sstevel 		cmn_err(CE_NOTE, "get_led_regnum: suip <%x, %x, %x, %x>\n",
212903831d35Sstevel 		    suip->unit_type, suip->unit_number,
213003831d35Sstevel 		    led_type, suip->unit_state);
213103831d35Sstevel 	}
213203831d35Sstevel 	/*
213303831d35Sstevel 	 * It was requested that the scsb driver allow accesses to SCB device
213403831d35Sstevel 	 * registers for FRUs that cannot be present.
213503831d35Sstevel 	 * So except for SLOTs, if the unit_number check fails, we now
213603831d35Sstevel 	 * just log a message, but ONLY if scsb_debug error messages are
213703831d35Sstevel 	 * enabled.
213803831d35Sstevel 	 */
213903831d35Sstevel 	switch (suip->unit_type) {
214003831d35Sstevel 	case SLOT:
214103831d35Sstevel 		if (suip->unit_number < 1 || suip->unit_number >
214203831d35Sstevel 		    ((scsb->scsb_state & SCSB_IS_TONGA) ?
214303831d35Sstevel 		    TG_MAX_SLOTS : MC_MAX_SLOTS)) {
214403831d35Sstevel 			error = EINVAL;
214503831d35Sstevel 			break;
214603831d35Sstevel 		}
214703831d35Sstevel 		code = FRU_UNIT_TO_EVCODE(SLOT, suip->unit_number);
214803831d35Sstevel 		break;
214903831d35Sstevel 
215003831d35Sstevel 	case PDU:
215103831d35Sstevel 		if (suip->unit_number < 1 || suip->unit_number >
215203831d35Sstevel 		    ((scsb->scsb_state & SCSB_IS_TONGA) ?
215303831d35Sstevel 		    TG_MAX_PDU : MC_MAX_PDU)) {
215403831d35Sstevel 			if (scsb_debug & 0x0002) {
215503831d35Sstevel 				cmn_err(CE_WARN,
215603831d35Sstevel 				    "get_led_regnum: unit number %d "
215703831d35Sstevel 				    "is out of range", suip->unit_number);
215803831d35Sstevel 			}
215903831d35Sstevel 			error = EINVAL;
216003831d35Sstevel 			break;
216103831d35Sstevel 		}
216203831d35Sstevel 		code = FRU_UNIT_TO_EVCODE(PDU, suip->unit_number);
216303831d35Sstevel 		break;
216403831d35Sstevel 
216503831d35Sstevel 	case PS:
216603831d35Sstevel 		if ((suip->unit_number < 1 || suip->unit_number >
216703831d35Sstevel 		    ((scsb->scsb_state & SCSB_IS_TONGA) ?
216803831d35Sstevel 		    TG_MAX_PS : MC_MAX_PS))) {
216903831d35Sstevel 			if (scsb_debug & 0x0002) {
217003831d35Sstevel 				cmn_err(CE_WARN,
217103831d35Sstevel 				    "get_led_regnum: unit number %d "
217203831d35Sstevel 				    "is out of range", suip->unit_number);
217303831d35Sstevel 			}
217403831d35Sstevel 			error = EINVAL;
217503831d35Sstevel 			break;
217603831d35Sstevel 		}
217703831d35Sstevel 		code = FRU_UNIT_TO_EVCODE(PS, suip->unit_number);
217803831d35Sstevel 		break;
217903831d35Sstevel 
218003831d35Sstevel 	case DISK:
218103831d35Sstevel 		if ((suip->unit_number < 1 || suip->unit_number >
218203831d35Sstevel 		    ((scsb->scsb_state & SCSB_IS_TONGA) ?
218303831d35Sstevel 		    TG_MAX_DISK : MC_MAX_DISK))) {
218403831d35Sstevel 			if (scsb_debug & 0x0002) {
218503831d35Sstevel 				cmn_err(CE_WARN,
218603831d35Sstevel 				    "get_led_regnum: unit number %d "
218703831d35Sstevel 				    "is out of range", suip->unit_number);
218803831d35Sstevel 			}
218903831d35Sstevel 			if (!(scsb_debug & 0x20000000)) {
219003831d35Sstevel 				error = EINVAL;
219103831d35Sstevel 				break;
219203831d35Sstevel 			}
219303831d35Sstevel 		}
219403831d35Sstevel 		code = FRU_UNIT_TO_EVCODE(DISK, suip->unit_number);
219503831d35Sstevel 		break;
219603831d35Sstevel 
219703831d35Sstevel 	case FAN:
219803831d35Sstevel 		if (suip->unit_number < 1 || suip->unit_number >
219903831d35Sstevel 		    ((scsb->scsb_state & SCSB_IS_TONGA) ?
220003831d35Sstevel 		    TG_MAX_FAN : MC_MAX_FAN)) {
220103831d35Sstevel 			if (scsb_debug & 0x0002) {
220203831d35Sstevel 				cmn_err(CE_WARN,
220303831d35Sstevel 				    "get_led_regnum: unit number %d "
220403831d35Sstevel 				    "is out of range", suip->unit_number);
220503831d35Sstevel 			}
220603831d35Sstevel 			error = EINVAL;
220703831d35Sstevel 			break;
220803831d35Sstevel 		}
220903831d35Sstevel 		code = FRU_UNIT_TO_EVCODE(FAN, suip->unit_number);
221003831d35Sstevel 		break;
221103831d35Sstevel 
221203831d35Sstevel 	case CFTM:
221303831d35Sstevel 		if (suip->unit_number < 1 || suip->unit_number >
221403831d35Sstevel 		    ((scsb->scsb_state & SCSB_IS_TONGA) ?
221503831d35Sstevel 		    TG_MAX_CFTM : MC_MAX_CFTM)) {
221603831d35Sstevel 			if (scsb_debug & 0x0002) {
221703831d35Sstevel 				cmn_err(CE_WARN,
221803831d35Sstevel 				    "get_led_regnum: unit number %d "
221903831d35Sstevel 				    "is out of range", suip->unit_number);
222003831d35Sstevel 			}
222103831d35Sstevel 			error = EINVAL;
222203831d35Sstevel 			break;
222303831d35Sstevel 		}
222403831d35Sstevel 		code = FRU_UNIT_TO_EVCODE(CFTM, suip->unit_number);
222503831d35Sstevel 		break;
222603831d35Sstevel 
222703831d35Sstevel 	case SCB:
222803831d35Sstevel 		if (suip->unit_number < 1 || suip->unit_number >
222903831d35Sstevel 		    ((scsb->scsb_state & SCSB_IS_TONGA) ?
223003831d35Sstevel 		    TG_MAX_SCB : MC_MAX_SCB)) {
223103831d35Sstevel 			if (scsb_debug & 0x0002) {
223203831d35Sstevel 				cmn_err(CE_WARN,
223303831d35Sstevel 				    "get_led_regnum: unit number %d "
223403831d35Sstevel 				    "is out of range", suip->unit_number);
223503831d35Sstevel 			}
223603831d35Sstevel 			error = EINVAL;
223703831d35Sstevel 			break;
223803831d35Sstevel 		}
223903831d35Sstevel 		code = FRU_UNIT_TO_EVCODE(SCB, suip->unit_number);
224003831d35Sstevel 		break;
224103831d35Sstevel 
224203831d35Sstevel 	case ALARM:
224303831d35Sstevel 		error = EINVAL;
224403831d35Sstevel 		break;
224503831d35Sstevel 
224603831d35Sstevel 	default:
224703831d35Sstevel 		if (scsb_debug & 0x0102) {
224803831d35Sstevel 			cmn_err(CE_WARN,
224903831d35Sstevel 			    "scsb_get_led_regnum(): unknown unit type %d",
225003831d35Sstevel 			    suip->unit_type);
225103831d35Sstevel 		}
225203831d35Sstevel 		error = EINVAL;
225303831d35Sstevel 		break;
225403831d35Sstevel 	}
225503831d35Sstevel 	if (!error) {
225603831d35Sstevel 		*unitptr = FRU_OFFSET(code, base);
225703831d35Sstevel 		*regptr = FRU_REG_ADDR(code, base);
225803831d35Sstevel 		if (scsb_debug & 0x0100) {
225903831d35Sstevel 			cmn_err(CE_NOTE, "get_led_regnum: unitptr=%x, "
226003831d35Sstevel 			    "regptr=%x, code = %x\n",
226103831d35Sstevel 			    *unitptr, *regptr, code);
226203831d35Sstevel 		}
226303831d35Sstevel 	}
226403831d35Sstevel 	return (error);
226503831d35Sstevel }
226603831d35Sstevel 
226703831d35Sstevel /*
226803831d35Sstevel  * P1.0 and P1.5
226903831d35Sstevel  * Map 1.0 Tonga Slot Numbers: SCB to user interface and back.
227003831d35Sstevel  * User interface means positional slot numbers, as on P1.0 SSB,
227103831d35Sstevel  * which are used by hpcsvc/hsc and kstat/ioctl interfaces.
227203831d35Sstevel  */
227303831d35Sstevel 
227403831d35Sstevel /* HSC slotnum (Positional SLotnum) to SCB CFG bit-offset */
227503831d35Sstevel static	int	psl2sco[TG_MAX_SLOTS + 1] = { -1 };
227603831d35Sstevel 
227703831d35Sstevel /*
227803831d35Sstevel  * MAP Positional (HSC) slot number to SCB CFG register bit-offset
227903831d35Sstevel  */
228003831d35Sstevel static int
228103831d35Sstevel tonga_pslotnum_to_cfgbit(scsb_state_t *scsb, int sln)
228203831d35Sstevel {
228303831d35Sstevel 	int	base = SCTRL_SYSCFG_BASE;
228403831d35Sstevel 	if (!(scsb->scsb_state & SCSB_IS_TONGA)) {
228503831d35Sstevel 		return (sln);
228603831d35Sstevel 	}
228703831d35Sstevel 	if (sln < 1 || sln > TG_MAX_SLOTS) {
228803831d35Sstevel 		return (sln);
228903831d35Sstevel 	}
229003831d35Sstevel 	/*
229103831d35Sstevel 	 * Should move this to _init(), but for now,
229203831d35Sstevel 	 * check for initialized table
229303831d35Sstevel 	 */
229403831d35Sstevel 	if (psl2sco[0]) {
229503831d35Sstevel 		psl2sco[0] = 0;
229603831d35Sstevel 		psl2sco[1] = FRU_OFFSET(SCTRL_EVENT_SLOT5, base);
229703831d35Sstevel 		psl2sco[2] = FRU_OFFSET(SCTRL_EVENT_SLOT2, base);
229803831d35Sstevel 		psl2sco[3] = FRU_OFFSET(SCTRL_EVENT_SLOT1, base);
229903831d35Sstevel 		psl2sco[4] = FRU_OFFSET(SCTRL_EVENT_SLOT3, base);
230003831d35Sstevel 		psl2sco[5] = FRU_OFFSET(SCTRL_EVENT_SLOT4, base);
230103831d35Sstevel 	}
230203831d35Sstevel #ifdef DEBUG
230303831d35Sstevel 	if (scsb_debug & 0x10000000) {
230403831d35Sstevel 		cmn_err(CE_NOTE, "tonga_pslotnum_to_cfgbit: old/new: %d/%d",
230503831d35Sstevel 		    sln, psl2sco[sln]);
230603831d35Sstevel 	}
230703831d35Sstevel #endif
230803831d35Sstevel 	return (psl2sco[sln]);
230903831d35Sstevel }
231003831d35Sstevel 
231103831d35Sstevel /* positional slotnum to SCB slotnum */
231203831d35Sstevel static	int	psl2ssl[6] = {
231303831d35Sstevel 	0, 5, 2, 1, 3, 4
231403831d35Sstevel };
231503831d35Sstevel 
231603831d35Sstevel /* SCB slotnum to positional slotnum */
231703831d35Sstevel static	int	ssl2psl[6] = {
231803831d35Sstevel 	0, 3, 2, 4, 5, 1
231903831d35Sstevel };
232003831d35Sstevel 
232103831d35Sstevel /*
232203831d35Sstevel  * P1.0 and P1.5
232303831d35Sstevel  * HSC Slot numbers (physical positions or positional slotnum)
232403831d35Sstevel  *  to
232503831d35Sstevel  * SCB slot numbers (reset,present,healthy)
232603831d35Sstevel  *
232703831d35Sstevel  * These requests come mainly from application interface and
232803831d35Sstevel  * HSC using the scsb_uinfo_t structure.
232903831d35Sstevel  */
233003831d35Sstevel static void
233103831d35Sstevel tonga_slotnum_check(scsb_state_t *scsb, scsb_uinfo_t *suip)
233203831d35Sstevel {
233303831d35Sstevel 	if (!(scsb->scsb_state & SCSB_IS_TONGA && scsb->scsb_state &
233403831d35Sstevel 	    (SCSB_P10_PROM | SCSB_P15_PROM | SCSB_P20_PROM))) {
233503831d35Sstevel 		return;
233603831d35Sstevel 	}
233703831d35Sstevel 	if (suip->unit_number < 1 || suip->unit_number > TG_MAX_SLOTS) {
233803831d35Sstevel 		return;
233903831d35Sstevel 	}
234003831d35Sstevel #ifdef DEBUG
234103831d35Sstevel 	if (scsb_debug & 0x10000000) {
234203831d35Sstevel 		cmn_err(CE_NOTE, "tonga_slotnum_check: old/new: %d/%d",
234303831d35Sstevel 		    suip->unit_number, psl2ssl[suip->unit_number]);
234403831d35Sstevel 	}
234503831d35Sstevel #endif
234603831d35Sstevel 	suip->unit_number = psl2ssl[suip->unit_number];
234703831d35Sstevel }
234803831d35Sstevel 
234903831d35Sstevel /*
235003831d35Sstevel  * P1.0 and P1.5
235103831d35Sstevel  */
235203831d35Sstevel static int
235303831d35Sstevel tonga_psl_to_ssl(scsb_state_t *scsb, int slotnum)
235403831d35Sstevel {
235503831d35Sstevel 	if (!(scsb->scsb_state & SCSB_IS_TONGA && scsb->scsb_state &
235603831d35Sstevel 	    (SCSB_P10_PROM | SCSB_P15_PROM | SCSB_P20_PROM))) {
235703831d35Sstevel 		return (slotnum);
235803831d35Sstevel 	}
235903831d35Sstevel 	if (slotnum < 1 || slotnum > TG_MAX_SLOTS) {
236003831d35Sstevel 		return (slotnum);
236103831d35Sstevel 	}
236203831d35Sstevel #ifdef DEBUG
236303831d35Sstevel 	if (scsb_debug & 0x10000000) {
236403831d35Sstevel 		cmn_err(CE_NOTE, "tonga_psl_to_ssl: old/new: %d/%d",
236503831d35Sstevel 		    slotnum, psl2ssl[slotnum]);
236603831d35Sstevel 	}
236703831d35Sstevel #endif
236803831d35Sstevel 	return (psl2ssl[slotnum]);
236903831d35Sstevel }
237003831d35Sstevel 
237103831d35Sstevel /*
237203831d35Sstevel  * P1.0 and P1.5
237303831d35Sstevel  */
237403831d35Sstevel static int
237503831d35Sstevel tonga_ssl_to_psl(scsb_state_t *scsb, int slotnum)
237603831d35Sstevel {
237703831d35Sstevel 	if (!(scsb->scsb_state & SCSB_IS_TONGA && scsb->scsb_state &
237803831d35Sstevel 	    (SCSB_P10_PROM | SCSB_P15_PROM | SCSB_P20_PROM))) {
237903831d35Sstevel 		return (slotnum);
238003831d35Sstevel 	}
238103831d35Sstevel 	if (slotnum < 1 || slotnum > TG_MAX_SLOTS) {
238203831d35Sstevel 		return (slotnum);
238303831d35Sstevel 	}
238403831d35Sstevel #ifdef DEBUG
238503831d35Sstevel 	if (scsb_debug & 0x10000000) {
238603831d35Sstevel 		cmn_err(CE_NOTE, "tonga_ssl_to_psl: old/new: %d/%d",
238703831d35Sstevel 		    slotnum, ssl2psl[slotnum]);
238803831d35Sstevel 	}
238903831d35Sstevel #endif
239003831d35Sstevel 	return (ssl2psl[slotnum]);
239103831d35Sstevel }
239203831d35Sstevel /*
239303831d35Sstevel  * tonga_slotnum_led_shift: this function remaps slot bits ONLY for Slots 1-5
239403831d35Sstevel  * and ONLY for the register sets in bit-offset groups 1,2:
239503831d35Sstevel  * LEDs, Confg/Status, Reset, BrdHlthy
239603831d35Sstevel  *
239703831d35Sstevel  * IN  bits: SCB slot numbers (led,reset,present,healthy)
239803831d35Sstevel  *  to
239903831d35Sstevel  * OUT bits: HSC Slot numbers (positional slot numbers as marked on the SSB)
240003831d35Sstevel  */
240103831d35Sstevel static uchar_t
240203831d35Sstevel tonga_slotnum_led_shift(scsb_state_t *scsb, uchar_t data)
240303831d35Sstevel {
240403831d35Sstevel 	int	i;
240503831d35Sstevel 	uchar_t mask, new_data = 0;
240603831d35Sstevel #ifdef DEBUG
240703831d35Sstevel 	uchar_t	old_data = data;
240803831d35Sstevel #endif
240903831d35Sstevel 	if (!(scsb->scsb_state & SCSB_IS_TONGA)) {
241003831d35Sstevel 		return (data);
241103831d35Sstevel 	}
241203831d35Sstevel 	/*
241303831d35Sstevel 	 * P1.0 and P1.5 slot 1-5 offsets are the same
241403831d35Sstevel 	 */
241503831d35Sstevel 	for (i = 1; i <= TG_MAX_SLOTS; ++i) {
241603831d35Sstevel 		mask = 1 << (i - 1);
241703831d35Sstevel 		switch (i) {
241803831d35Sstevel 		case 1:		/* map to slot 3 */
241903831d35Sstevel 			new_data |= (data & mask) << 2;
242003831d35Sstevel 			data &= ~(mask);
242103831d35Sstevel 			break;
242203831d35Sstevel 		case 2:		/* map to slot 2 */
242303831d35Sstevel 			new_data |= (data & mask);
242403831d35Sstevel 			data &= ~(mask);
242503831d35Sstevel 			break;
242603831d35Sstevel 		case 3:		/* map to slot 4 */
242703831d35Sstevel 		case 4:		/* map to slot 5 */
242803831d35Sstevel 			new_data |= (data & mask) << 1;
242903831d35Sstevel 			data &= ~(mask);
243003831d35Sstevel 			break;
243103831d35Sstevel 		case 5:		/* map to slot 1 */
243203831d35Sstevel 			new_data |= (data & mask) >> 4;
243303831d35Sstevel 			data &= ~(mask);
243403831d35Sstevel 			break;
243503831d35Sstevel 		}
243603831d35Sstevel 	}
243703831d35Sstevel 	new_data |= data;	/* set any remaining bits */
243803831d35Sstevel #ifdef DEBUG
243903831d35Sstevel 	if (scsb_debug & 0x10000000) {
244003831d35Sstevel 		cmn_err(CE_NOTE, "tonga_slotnum_led_shift: old/new: 0x%x/0x%x",
244103831d35Sstevel 		    old_data, new_data);
244203831d35Sstevel 	}
244303831d35Sstevel #endif
244403831d35Sstevel 	return (new_data);
244503831d35Sstevel }
244603831d35Sstevel 
244703831d35Sstevel /*
244803831d35Sstevel  * P1.0 and P1.5
244903831d35Sstevel  */
245003831d35Sstevel int
245103831d35Sstevel scsb_led_get(scsb_state_t *scsb, scsb_uinfo_t *suip, scsb_led_t led_type)
245203831d35Sstevel {
245303831d35Sstevel 	int		error;
245403831d35Sstevel 	int		unit_number;
245503831d35Sstevel 	uchar_t		reg;
245603831d35Sstevel 	int		index;
245703831d35Sstevel 
245803831d35Sstevel 	/*
245903831d35Sstevel 	 * Allow access to shadow registers even though SCB is removed
246003831d35Sstevel 	 *
246103831d35Sstevel 	 * if (scsb->scsb_state & SCSB_FROZEN) {
246203831d35Sstevel 	 *	return (EAGAIN);
246303831d35Sstevel 	 * }
246403831d35Sstevel 	 */
246503831d35Sstevel 	if (suip == NULL) {
246603831d35Sstevel 		return (EFAULT);
246703831d35Sstevel 	}
246803831d35Sstevel 	if (led_type == NOUSE) {
246903831d35Sstevel 		led_type = suip->led_type;
247003831d35Sstevel 	}
247103831d35Sstevel 	if (led_type != OK && led_type != NOK) {
247203831d35Sstevel 		cmn_err(CE_NOTE, "scsb_led_get(%d): unknown led type %x",
247303831d35Sstevel 		    scsb->scsb_instance, led_type);
247403831d35Sstevel 		return (EINVAL);
247503831d35Sstevel 	}
247603831d35Sstevel 	error = 0;
247703831d35Sstevel 	if (scsb_debug & 0x0100) {
247803831d35Sstevel 		cmn_err(CE_NOTE, "scsb_led_get: %s %s %d",
247903831d35Sstevel 		    led_name[led_type], unit_type_name[suip->unit_type],
248003831d35Sstevel 		    suip->unit_number);
248103831d35Sstevel 	}
248203831d35Sstevel 	/*
248303831d35Sstevel 	 * Map to Tonga Slot Number, if NOT P1.0 SCB
248403831d35Sstevel 	 * P1.0 SSB workaround
248503831d35Sstevel 	 */
248603831d35Sstevel 	if (suip->unit_type == SLOT && !(scsb->scsb_state & SCSB_P10_PROM)) {
248703831d35Sstevel 		tonga_slotnum_check(scsb, suip);
248803831d35Sstevel 	}
248903831d35Sstevel 	/* discover the register and index we need to operate on */
249003831d35Sstevel 	if ((error = scsb_get_led_regnum(scsb, suip, &reg, &unit_number,
249103831d35Sstevel 	    led_type)) == 0) {
249203831d35Sstevel 		index = SCSB_REG_INDEX(reg);
249303831d35Sstevel 		mutex_enter(&scsb->scsb_mutex);
249403831d35Sstevel 		if (scsb->scsb_data_reg[index] & (1 << unit_number)) {
249503831d35Sstevel 			suip->unit_state = ON;
249603831d35Sstevel 			if (led_type == OK) {
249703831d35Sstevel 				int code = FRU_UNIT_TO_EVCODE(suip->unit_type,
249803831d35Sstevel 				    suip->unit_number);
249903831d35Sstevel 				reg = FRU_REG_ADDR(code, SCTRL_BLINK_OK_BASE);
250003831d35Sstevel 				index = SCSB_REG_INDEX(reg);
250103831d35Sstevel 				if (scsb->scsb_data_reg[index] &
250203831d35Sstevel 				    (1 << unit_number))
250303831d35Sstevel 					suip->unit_state = BLINK;
250403831d35Sstevel 			}
250503831d35Sstevel 		} else {
250603831d35Sstevel 			suip->unit_state = OFF;
250703831d35Sstevel 		}
250803831d35Sstevel 		mutex_exit(&scsb->scsb_mutex);
250903831d35Sstevel 	}
251003831d35Sstevel 	return (error);
251103831d35Sstevel }
251203831d35Sstevel 
251303831d35Sstevel int
251403831d35Sstevel scsb_led_set(scsb_state_t *scsb, scsb_uinfo_t *suip, scsb_led_t led_type)
251503831d35Sstevel {
251603831d35Sstevel 	int		error;
251703831d35Sstevel 	int		unit_number;
251803831d35Sstevel 	uchar_t		reg;
251903831d35Sstevel 	int		code, index;
252003831d35Sstevel 
252103831d35Sstevel 	/* we should really allow led state changes while frozen... */
252203831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN)
252303831d35Sstevel 		return (EAGAIN);
252403831d35Sstevel 
252503831d35Sstevel 	if (suip == NULL) {
252603831d35Sstevel 		return (EFAULT);
252703831d35Sstevel 	}
252803831d35Sstevel 
252903831d35Sstevel 	/*
253003831d35Sstevel 	 * Sanity check, make sure we got plausible values for set command.
253103831d35Sstevel 	 * Also check for application only control of slot leds using NOUSE
253203831d35Sstevel 	 * interface
253303831d35Sstevel 	 */
253403831d35Sstevel 	if (led_type == NOUSE) {
253503831d35Sstevel 		led_type = suip->led_type;
253603831d35Sstevel 	} else if (suip->unit_type == SLOT &&
253703831d35Sstevel 	    scsb->scsb_state & SCSB_APP_SLOTLED_CTRL &&
253803831d35Sstevel 	    !(scsb->scsb_state &
253903831d35Sstevel 	    (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) {
254003831d35Sstevel 		/*
254103831d35Sstevel 		 * kernel modules using this interface need to think they are
254203831d35Sstevel 		 * succeeding, so we won't return an error for this
254303831d35Sstevel 		 * application configuration
254403831d35Sstevel 		 */
254503831d35Sstevel 		return (0);
254603831d35Sstevel 	}
254703831d35Sstevel 	if (led_type != OK && led_type != NOK) {
254803831d35Sstevel 		return (EINVAL);
254903831d35Sstevel 	}
255003831d35Sstevel 	if (suip->unit_state != OFF && suip->unit_state != ON &&
255103831d35Sstevel 	    suip->unit_state != BLINK) {
255203831d35Sstevel 		return (EINVAL);
255303831d35Sstevel 	}
255403831d35Sstevel 	if (suip->unit_state == BLINK) {
255503831d35Sstevel 		if (led_type != OK)
255603831d35Sstevel 			return (EINVAL);
255703831d35Sstevel 		if (suip->unit_type != SLOT && scsb->scsb_state &
255803831d35Sstevel 		    (SCSB_P06_PROM | SCSB_P10_PROM))
255903831d35Sstevel 			return (EINVAL);
256003831d35Sstevel 	}
256103831d35Sstevel 	if (scsb_debug & 0x0100) {
256203831d35Sstevel 		cmn_err(CE_NOTE,
256303831d35Sstevel 		    "scsb_led_set: led %s, type %s, unit %d, state %s",
256403831d35Sstevel 		    led_name[led_type],
256503831d35Sstevel 		    unit_type_name[suip->unit_type], suip->unit_number,
256603831d35Sstevel 		    suip->unit_state == ON ? "ON":
256703831d35Sstevel 		    suip->unit_state == OFF ? "OFF": "BLINK");
256803831d35Sstevel 	}
256903831d35Sstevel 	/*
257003831d35Sstevel 	 * Map to Tonga Slot Number, if NOT P1.0 SCB
257103831d35Sstevel 	 * P1.0 SSB workaround
257203831d35Sstevel 	 */
257303831d35Sstevel 	if (suip->unit_type == SLOT && !(scsb->scsb_state & SCSB_P10_PROM)) {
257403831d35Sstevel 		tonga_slotnum_check(scsb, suip);
257503831d35Sstevel 	}
257603831d35Sstevel 	/*
257703831d35Sstevel 	 * discover the register and index we need to access
257803831d35Sstevel 	 */
257903831d35Sstevel 	if ((error = scsb_get_led_regnum(scsb, suip, &reg, &unit_number,
258003831d35Sstevel 	    led_type)) == 0) {
258103831d35Sstevel 		index = SCSB_REG_INDEX(reg);
258203831d35Sstevel 		mutex_enter(&scsb->scsb_mutex);
258303831d35Sstevel 		if (suip->unit_state == ON || suip->unit_state == BLINK)
258403831d35Sstevel 			scsb->scsb_data_reg[index] |=  (1 << unit_number);
258503831d35Sstevel 		else
258603831d35Sstevel 			scsb->scsb_data_reg[index] &= ~(1 << unit_number);
258703831d35Sstevel 
258803831d35Sstevel 		if (scsb_debug & 0x0100) {
258903831d35Sstevel 			cmn_err(CE_NOTE, "Writing %x to Reg %x",
259003831d35Sstevel 			    scsb->scsb_data_reg[index], reg);
259103831d35Sstevel 		}
259203831d35Sstevel 		error = scsb_rdwr_register(scsb, I2C_WR, reg, 1,
259303831d35Sstevel 		    &scsb->scsb_data_reg[index], 1);
259403831d35Sstevel 		if (error) {
259503831d35Sstevel 			cmn_err(CE_WARN, "%s#%d: Could not Update %s LEDs.",
259603831d35Sstevel 			    ddi_driver_name(scsb->scsb_dev),
259703831d35Sstevel 			    ddi_get_instance(scsb->scsb_dev),
259803831d35Sstevel 			    led_name[led_type]);
259903831d35Sstevel 			goto ledset_done;
260003831d35Sstevel 		}
260103831d35Sstevel 		if (led_type != OK ||
260203831d35Sstevel 		    (IS_SCB_P10 && suip->unit_type != SLOT) ||
260303831d35Sstevel 		    suip->unit_type == ALARM ||
260403831d35Sstevel 		    suip->unit_type == SSB ||
260503831d35Sstevel 		    suip->unit_type == CRTM ||
260603831d35Sstevel 		    suip->unit_type == PRTM) {
260703831d35Sstevel 			goto ledset_done;
260803831d35Sstevel 		}
260903831d35Sstevel 		code = FRU_UNIT_TO_EVCODE(suip->unit_type, suip->unit_number);
261003831d35Sstevel 		reg = FRU_REG_ADDR(code, SCTRL_BLINK_OK_BASE);
261103831d35Sstevel 		index = SCSB_REG_INDEX(reg);
261203831d35Sstevel 		if (suip->unit_state == BLINK)
261303831d35Sstevel 			scsb->scsb_data_reg[index] |=  (1 << unit_number);
261403831d35Sstevel 		else
261503831d35Sstevel 			scsb->scsb_data_reg[index] &= ~(1 << unit_number);
261603831d35Sstevel 		if (scsb_debug & 0x0100) {
261703831d35Sstevel 			cmn_err(CE_NOTE, "Writing %x to Reg %x",
261803831d35Sstevel 			    scsb->scsb_data_reg[index], reg);
261903831d35Sstevel 		}
262003831d35Sstevel 		error = scsb_rdwr_register(scsb, I2C_WR, reg, 1,
262103831d35Sstevel 		    &scsb->scsb_data_reg[index], 1);
262203831d35Sstevel 		if (error) {
262303831d35Sstevel 			cmn_err(CE_WARN, "%s#%d: Could not Blink %s LEDs.",
262403831d35Sstevel 			    ddi_driver_name(scsb->scsb_dev),
262503831d35Sstevel 			    ddi_get_instance(scsb->scsb_dev),
262603831d35Sstevel 			    led_name[led_type]);
262703831d35Sstevel 		}
262803831d35Sstevel ledset_done:
262903831d35Sstevel 		mutex_exit(&scsb->scsb_mutex);
263003831d35Sstevel 	}
263103831d35Sstevel 	return (error);
263203831d35Sstevel }
263303831d35Sstevel 
263403831d35Sstevel struct ps_auto_on {
263503831d35Sstevel 	scsb_state_t	*scsb;
263603831d35Sstevel 	scsb_utype_t	utype;
263703831d35Sstevel 	scsb_unum_t	unit;
263803831d35Sstevel };
263903831d35Sstevel 
264003831d35Sstevel static struct ps_auto_on pao;
264103831d35Sstevel 
264203831d35Sstevel static void
264303831d35Sstevel scsb_ps_auto_on(void *arg)
264403831d35Sstevel {
264503831d35Sstevel 	struct ps_auto_on 	*ppao = (struct ps_auto_on *)arg;
264603831d35Sstevel 	uchar_t			rmask = 0;
264703831d35Sstevel 	uchar_t			ondata, sysreg;
264803831d35Sstevel 	int			tmp, bit_index;
264903831d35Sstevel 	/*
265003831d35Sstevel 	 * Turn on the PSU.
265103831d35Sstevel 	 * Notice: not checking Power Supply unit number
265203831d35Sstevel 	 */
265303831d35Sstevel 	bit_index = SCTRL_SYS_PS_ON_BASE + (ppao->unit - 1);
265403831d35Sstevel 	ondata = 1 << SYS_OFFSET(bit_index);
265503831d35Sstevel 	tmp = SYS_REG_INDEX(bit_index, SCTRL_SYS_CMD_BASE);
265603831d35Sstevel 	sysreg = SCSB_REG_ADDR(tmp);
265703831d35Sstevel 	if (scsb_write_mask(ppao->scsb, sysreg, rmask, ondata, (uchar_t)0)) {
265803831d35Sstevel 		cmn_err(CE_WARN, "scsb%d: " "I2C TRANSFER Failed",
265903831d35Sstevel 		    ppao->scsb->scsb_instance);
266003831d35Sstevel 	}
266103831d35Sstevel 	ppao->scsb->scsb_btid = 0;
266203831d35Sstevel }
266303831d35Sstevel 
266403831d35Sstevel /*
266503831d35Sstevel  * called with mutex held from
266603831d35Sstevel  * scsb_attach()	with int_fru_ptr == NULL
266703831d35Sstevel  * scsb_intr()		with int_fru_ptr == info for FRU that caused interrupt
266803831d35Sstevel  */
266903831d35Sstevel static int
267003831d35Sstevel scsb_set_scfg_pres_leds(scsb_state_t *scsb, fru_info_t *int_fru_ptr)
267103831d35Sstevel {
267203831d35Sstevel 	int		i, error = 0;
267303831d35Sstevel 	int		cfg_idx, led_idx, blink_idx, lid, bid;
267403831d35Sstevel 	int		cfg_bit, led_bit;
267503831d35Sstevel 	uchar_t		*puc, reg, led_reg, led_data[SCSB_LEDDATA_REGISTERS];
267603831d35Sstevel 	uchar_t		blink_bit, blink_reg, blink[SCSB_LEDDATA_REGISTERS];
267703831d35Sstevel 	uchar_t		update_reg = 0;
267803831d35Sstevel 	scsb_utype_t	fru_type;
267903831d35Sstevel 	fru_info_t	*fru_ptr;
268003831d35Sstevel 
268103831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN &&
268203831d35Sstevel 	    !(scsb->scsb_state & SCSB_IN_INTR)) {
268303831d35Sstevel 		return (EAGAIN);
268403831d35Sstevel 	}
268503831d35Sstevel 	for (i = 0; i < SCTRL_LED_OK_NUMREGS; ++i) {
268603831d35Sstevel 		led_data[i] = 0;
268703831d35Sstevel 		blink[i] = 0;
268803831d35Sstevel 	}
268903831d35Sstevel 	led_reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE);
269003831d35Sstevel 	reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE);
269103831d35Sstevel 	lid = SCSB_REG_INDEX(led_reg);		/* the LED Index Delta */
269203831d35Sstevel 	bid = SCSB_REG_INDEX(reg);		/* the Blink Index Delta */
269303831d35Sstevel 	blink_reg = 0;
269403831d35Sstevel 	if (int_fru_ptr != NULL) {
269503831d35Sstevel 		update_reg = int_fru_ptr->i2c_info->ledata_reg;
269603831d35Sstevel 	}
269703831d35Sstevel 	for (fru_type = 0; fru_type < SCSB_UNIT_TYPES; ++fru_type) {
269803831d35Sstevel 		int	is_present;
269903831d35Sstevel 		fru_ptr = mct_system_info.fru_info_list[fru_type];
270003831d35Sstevel 		for (; fru_ptr != NULL; fru_ptr = fru_ptr->next) {
270103831d35Sstevel 			is_present = 0;
270203831d35Sstevel 			if (fru_type == SLOT && (scsb->scsb_state &
270303831d35Sstevel 			    SCSB_APP_SLOTLED_CTRL))
270403831d35Sstevel 				break;
270503831d35Sstevel 			if (fru_ptr->i2c_info == NULL)
270603831d35Sstevel 				continue;
270703831d35Sstevel 			if ((led_reg = fru_ptr->i2c_info->ledata_reg) == 0) {
270803831d35Sstevel 				/*
270903831d35Sstevel 				 * No LED exceptions: SSB,CRTM,PRTM
271003831d35Sstevel 				 */
271103831d35Sstevel 				continue;
271203831d35Sstevel 			}
271303831d35Sstevel 			if (update_reg && update_reg != led_reg)
271403831d35Sstevel 				continue;
271503831d35Sstevel 			led_idx = SCSB_REG_INDEX(led_reg) - lid;
271603831d35Sstevel 			led_bit = fru_ptr->i2c_info->ledata_bit;
271703831d35Sstevel 			if ((reg = fru_ptr->i2c_info->syscfg_reg) == 0) {
271803831d35Sstevel 				if (fru_type != SCB)
271903831d35Sstevel 					continue;
272003831d35Sstevel 				/*
272103831d35Sstevel 				 * exception: SCB
272203831d35Sstevel 				 */
272303831d35Sstevel 				if (scsb->scsb_state & SCSB_SCB_PRESENT) {
272403831d35Sstevel 					led_data[led_idx] |= 1 << led_bit;
272503831d35Sstevel 					is_present = 1;
272603831d35Sstevel 				} else {
272703831d35Sstevel 					led_data[led_idx] &= ~(1 << led_bit);
272803831d35Sstevel 				}
272903831d35Sstevel 				if (IS_SCB_P10)
273003831d35Sstevel 					continue;
273103831d35Sstevel 			} else {
273203831d35Sstevel 				cfg_idx = SCSB_REG_INDEX(reg);
273303831d35Sstevel 				cfg_bit = fru_ptr->i2c_info->syscfg_bit;
273403831d35Sstevel 				if (scsb->scsb_data_reg[cfg_idx] &
273503831d35Sstevel 				    (1 << cfg_bit)) {
273603831d35Sstevel 					is_present = 1;
273703831d35Sstevel 				}
273803831d35Sstevel 			}
273903831d35Sstevel 			if (is_present) {
274003831d35Sstevel 				/*
274103831d35Sstevel 				 * If the FRU is a Power Supply, AND
274203831d35Sstevel 				 * the call is from scsb_attach() OR
274303831d35Sstevel 				 * from scsb_intr() and FRUs match,
274403831d35Sstevel 				 * turn it on.
274503831d35Sstevel 				 */
274603831d35Sstevel 				if (fru_type == PS && (int_fru_ptr == NULL ||
274703831d35Sstevel 				    (int_fru_ptr == fru_ptr))) {
274803831d35Sstevel 					pao.scsb = scsb;
274903831d35Sstevel 					pao.utype = fru_type;
275003831d35Sstevel 					pao.unit = fru_ptr->fru_unit;
275103831d35Sstevel #ifdef	PS_ON_DELAY
275203831d35Sstevel 					/*
275303831d35Sstevel 					 * HW recommended not implementing
275403831d35Sstevel 					 * this delay for now.
275503831d35Sstevel 					 * The code is tested on PSUs:
275603831d35Sstevel 					 *	-06
275703831d35Sstevel 					 *	-07 rev 2
275803831d35Sstevel 					 *	-08 plus
275903831d35Sstevel 					 */
276003831d35Sstevel 					if (int_fru_ptr) {
276103831d35Sstevel 						/*
276203831d35Sstevel 						 * Hot insertion, so give it
276303831d35Sstevel 						 * the 3 seconds it needs to
276403831d35Sstevel 						 * become stable
276503831d35Sstevel 						 */
276603831d35Sstevel 						if (!scsb->scsb_btid)
276703831d35Sstevel 							scsb->scsb_btid =
276819397407SSherry Moore 							    timeout(
276919397407SSherry Moore 							    scsb_ps_auto_on,
277003831d35Sstevel 							    &pao, (4 *
277119397407SSherry Moore 							    drv_usectohz(
277219397407SSherry Moore 							    1000000)));
277303831d35Sstevel 					} else
277403831d35Sstevel #endif	/* PS_ON_DELAY */
277503831d35Sstevel 						scsb_ps_auto_on((void *)&pao);
277603831d35Sstevel 				}
277703831d35Sstevel 				/*
277803831d35Sstevel 				 * Special SLOT handling.
277903831d35Sstevel 				 * Make sure the OK LED is on for the CPU Slot
278003831d35Sstevel 				 * and for the FTC (CFTM) Slot for MonteCarlo.
278103831d35Sstevel 				 * Both will report as FRU_PRESENT.
278203831d35Sstevel 				 */
278303831d35Sstevel 				if (fru_type != SLOT || (fru_type == SLOT &&
278403831d35Sstevel 				    (fru_ptr->fru_type ==
278503831d35Sstevel 				    (scsb_utype_t)OC_CPU ||
278603831d35Sstevel 				    fru_ptr->fru_type ==
278703831d35Sstevel 				    (scsb_utype_t)OC_CTC))) {
278803831d35Sstevel 					/*
278903831d35Sstevel 					 * Set OK (green) LED register bit
279003831d35Sstevel 					 */
279103831d35Sstevel 					led_data[led_idx] |= 1 << led_bit;
279203831d35Sstevel 				}
279303831d35Sstevel 				if (IS_SCB_P10)
279403831d35Sstevel 					continue;
279503831d35Sstevel 				/*
279603831d35Sstevel 				 * Turn off BLINK register bit.
279703831d35Sstevel 				 * If single register update, then save the
279803831d35Sstevel 				 * corresponding blink register in blink_reg.
279903831d35Sstevel 				 */
280003831d35Sstevel 				reg = fru_ptr->i2c_info->blink_reg;
280103831d35Sstevel 				if (!reg)
280203831d35Sstevel 					continue;
280303831d35Sstevel 				blink_bit = fru_ptr->i2c_info->blink_bit;
280403831d35Sstevel 				blink_idx = SCSB_REG_INDEX(reg) - bid;
280503831d35Sstevel 				blink[blink_idx] |= 1 << blink_bit;
280603831d35Sstevel 				if (update_reg && update_reg == led_reg)
280703831d35Sstevel 					blink_reg = reg;
280803831d35Sstevel 			}
280903831d35Sstevel 		}
281003831d35Sstevel 	}
281103831d35Sstevel 	if (update_reg) {
281203831d35Sstevel 		reg = update_reg;
281303831d35Sstevel 		i = SCSB_REG_INDEX(reg);
281403831d35Sstevel 		puc = &led_data[i - lid];
281503831d35Sstevel 		i = 1;
281603831d35Sstevel 	} else {
281703831d35Sstevel 		reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE);
281803831d35Sstevel 		puc = led_data;
281903831d35Sstevel 		i = SCTRL_LED_OK_NUMREGS;
282003831d35Sstevel 	}
282103831d35Sstevel 	if (scsb_debug & 0x0100) {
282203831d35Sstevel 		cmn_err(CE_NOTE, "scsb_set_scfg_pres(): writing %d bytes "
282303831d35Sstevel 		    "to 0x%x", i, reg);
282403831d35Sstevel 	}
282503831d35Sstevel 	if ((error = scsb_rdwr_register(scsb, I2C_WR, reg, i, puc, 1)) != 0) {
282603831d35Sstevel 		if (scsb_debug & 0x0102)
282703831d35Sstevel 			cmn_err(CE_NOTE, "scsb_set_scfg_pres(): "
282803831d35Sstevel 			    "I2C write to 0x%x failed", reg);
282903831d35Sstevel 		error = EIO;
283003831d35Sstevel 	} else {
283103831d35Sstevel 		/*
283203831d35Sstevel 		 * Now see which BLINK bits need to be turned off for the
283303831d35Sstevel 		 * corresponding OK LED bits.
283403831d35Sstevel 		 */
283503831d35Sstevel 		reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE);
283603831d35Sstevel 		for (i = 0; i < SCTRL_BLINK_NUMREGS; ++i, ++reg) {
283703831d35Sstevel 			if (blink_reg && blink_reg != reg)
283803831d35Sstevel 				continue;
283903831d35Sstevel 			if (!blink[i]) {
284003831d35Sstevel 				continue;
284103831d35Sstevel 			}
284203831d35Sstevel 			if (scsb_debug & 0x0100) {
284303831d35Sstevel 				cmn_err(CE_NOTE, "scsb_set_scfg_pres(): turn "
284403831d35Sstevel 				    "OFF Blink bits 0x%x in 0x%x",
284503831d35Sstevel 				    blink[i], reg);
284603831d35Sstevel 			}
284703831d35Sstevel 			if (scsb_write_mask(scsb, reg, 0, 0, blink[i])) {
284803831d35Sstevel 				if (scsb_debug & 0x0102)
284903831d35Sstevel 					cmn_err(CE_NOTE,
285003831d35Sstevel 					    "scsb_set_scfg_pres(): "
285103831d35Sstevel 					    "Write to 0x%x failed", reg);
285203831d35Sstevel 				error = EIO;
285303831d35Sstevel 				break;
285403831d35Sstevel 			}
285503831d35Sstevel 		}
285603831d35Sstevel 	}
285703831d35Sstevel 	return (error);
285803831d35Sstevel }
285903831d35Sstevel 
286003831d35Sstevel static int
286103831d35Sstevel scsb_check_config_status(scsb_state_t *scsb)
286203831d35Sstevel {
286303831d35Sstevel 	int		error;
286403831d35Sstevel 	uchar_t		reg;
286503831d35Sstevel 	int		index, p06;
286603831d35Sstevel 
286703831d35Sstevel 	if (scsb_debug & 0x0201) {
286803831d35Sstevel 		cmn_err(CE_NOTE, "scsb_check_config_status:");
286903831d35Sstevel 	}
287003831d35Sstevel 	/*
287103831d35Sstevel 	 * Base of register set
287203831d35Sstevel 	 */
287303831d35Sstevel 	reg = SCSB_REG_ADDR(SCTRL_SYSCFG_BASE);
287403831d35Sstevel 	index = SCSB_REG_INDEX(reg);
287503831d35Sstevel 	/*
287603831d35Sstevel 	 * SCB P0.6 workaround: read registers twice, use 2nd value set
287703831d35Sstevel 	 */
287803831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
287903831d35Sstevel 	p06 = 2;
288003831d35Sstevel 	do {
288103831d35Sstevel 		if (error = scsb_rdwr_register(scsb, I2C_WR_RD, reg,
288203831d35Sstevel 		    SCTRL_CFG_NUMREGS, &scsb->scsb_data_reg[index], 1)) {
288303831d35Sstevel 			break;
288403831d35Sstevel 		}
288503831d35Sstevel 		if (p06 == 1) {
288603831d35Sstevel 			if (scsb_debug & 0x0200)
288703831d35Sstevel 				cmn_err(CE_NOTE,
288803831d35Sstevel 				"scsb_check_config_status: P0.6 workaround");
288903831d35Sstevel 		}
289003831d35Sstevel 		/*
289103831d35Sstevel 		 * If not P0.6 PROM, just break here
289203831d35Sstevel 		 */
289303831d35Sstevel 		if (!(scsb->scsb_state & SCSB_P06_PROM))
289403831d35Sstevel 			break;
289503831d35Sstevel 	} while (--p06);
289603831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
289703831d35Sstevel 
289803831d35Sstevel 	if (error == 0) {
289903831d35Sstevel 		if (!(scsb->scsb_state & SCSB_SCB_PRESENT))
290003831d35Sstevel 			scsb->scsb_state |= SCSB_SCB_PRESENT;
290103831d35Sstevel 		if (scsb_fru_op(scsb, SSB, 1, SCTRL_SYSCFG_BASE,
290203831d35Sstevel 		    SCSB_FRU_OP_GET_BITVAL))
290303831d35Sstevel 			scsb->scsb_state |= SCSB_SSB_PRESENT;
290403831d35Sstevel 		else
290503831d35Sstevel 			scsb->scsb_state &= ~SCSB_SSB_PRESENT;
290603831d35Sstevel 	}
290703831d35Sstevel 	return (error);
290803831d35Sstevel }
290903831d35Sstevel 
291003831d35Sstevel static void
291103831d35Sstevel scsb_set_topology(scsb_state_t *scsb)
291203831d35Sstevel {
291303831d35Sstevel 	int		i, t, index, unit, is_tonga = 0;
291403831d35Sstevel 	int		alarm_slot_num, cpu_slot_num, ctc_slot_num;
291503831d35Sstevel 	fru_info_t	*fru_ptr, *last_ptr, *acslot_ptr, *ctcslot_ptr;
291603831d35Sstevel 	uchar_t		syscfg, led_reg, blink_reg, t_uchar;
291703831d35Sstevel 	uchar_t		bit_num, led_bit, blink_bit;
291803831d35Sstevel 	int		pad = 0;
291903831d35Sstevel 
292003831d35Sstevel 	/*
292103831d35Sstevel 	 * Get the presence status from the SysConfigStatus shadow registers
292203831d35Sstevel 	 * in scsb->scsb_data_reg[]
292303831d35Sstevel 	 */
292403831d35Sstevel 	/* Mid Plane */
292503831d35Sstevel 	i = SYS_REG_INDEX(SCTRL_CFG_MPID0, SCTRL_SYSCFG_BASE);
292603831d35Sstevel 	t_uchar = SCSB_REG_ADDR(i);
292703831d35Sstevel 	index = SCSB_REG_INDEX(t_uchar);
292803831d35Sstevel 	mct_system_info.mid_plane.fru_type = MIDPLANE;
292903831d35Sstevel 	mct_system_info.mid_plane.fru_version = (fru_version_t)0;
293003831d35Sstevel 	t = SYS_OFFSET(SCTRL_CFG_MPID0);
293103831d35Sstevel 	mct_system_info.mid_plane.fru_id = (int)((scsb->scsb_data_reg[index] &
293203831d35Sstevel 	    (SCTRL_MPID_MASK << t)) >> t);
293303831d35Sstevel 	switch (mct_system_info.mid_plane.fru_id) {
293403831d35Sstevel 	case SCTRL_MPID_HALF:		/* Monte Carlo		*/
293503831d35Sstevel 		if (scsb_debug & 0x00100005)
293603831d35Sstevel 			cmn_err(CE_NOTE, "scsb_set_topology: Monte Carlo");
293703831d35Sstevel 		cpu_slot_num = SC_MC_CPU_SLOT;
293803831d35Sstevel 		ctc_slot_num = SC_MC_CTC_SLOT;
293903831d35Sstevel 		alarm_slot_num = scsb->ac_slotnum = SC_MC_AC_SLOT;
294003831d35Sstevel 		mct_system_info.max_units[SLOT] = MC_MAX_SLOTS;
294103831d35Sstevel 		mct_system_info.max_units[ALARM] = MC_MAX_AC;
294203831d35Sstevel 		mct_system_info.max_units[DISK] = MC_MAX_DISK;
294303831d35Sstevel 		mct_system_info.max_units[FAN] = MC_MAX_FAN;
294403831d35Sstevel 		mct_system_info.max_units[PS] = MC_MAX_PS;
294503831d35Sstevel 		mct_system_info.max_units[PDU] = MC_MAX_PDU;
294603831d35Sstevel 		mct_system_info.max_units[SCB] = MC_MAX_SCB;
294703831d35Sstevel 		mct_system_info.max_units[SSB] = MC_MAX_SCB;
294803831d35Sstevel 		mct_system_info.max_units[CFTM] = MC_MAX_CFTM;
294903831d35Sstevel 		mct_system_info.max_units[CRTM] = MC_MAX_CRTM;
295003831d35Sstevel 		mct_system_info.max_units[PRTM] = MC_MAX_PRTM;
295103831d35Sstevel 		break;
295203831d35Sstevel 	case SCTRL_MPID_QUARTER_NODSK:	/* Tonga w/o disk	*/
295303831d35Sstevel 	case SCTRL_MPID_QUARTER:	/* Tonga w/  disk	*/
295403831d35Sstevel 		scsb->scsb_state |= SCSB_IS_TONGA;
295503831d35Sstevel 		is_tonga = 1;
295603831d35Sstevel 		ctc_slot_num = -1;
295703831d35Sstevel 		ctcslot_ptr = NULL;
295803831d35Sstevel 		if (scsb_debug & 0x00100005)
295903831d35Sstevel 			cmn_err(CE_NOTE, "scsb_set_topology: Tonga%s",
296003831d35Sstevel 			    mct_system_info.mid_plane.fru_id ==
296103831d35Sstevel 			    SCTRL_MPID_QUARTER_NODSK ?
296203831d35Sstevel 			    ", no disk" : " with disk");
296303831d35Sstevel 		cpu_slot_num = SC_TG_CPU_SLOT;
296403831d35Sstevel 		alarm_slot_num = scsb->ac_slotnum = SC_TG_AC_SLOT;
296503831d35Sstevel 		mct_system_info.max_units[SLOT] = TG_MAX_SLOTS;
296603831d35Sstevel 		mct_system_info.max_units[ALARM] = TG_MAX_AC;
296703831d35Sstevel 		mct_system_info.max_units[DISK] = TG_MAX_DISK;
296803831d35Sstevel 		mct_system_info.max_units[FAN] = TG_MAX_FAN;
296903831d35Sstevel 		mct_system_info.max_units[PS] = TG_MAX_PS;
297003831d35Sstevel 		mct_system_info.max_units[PDU] = TG_MAX_PDU;
297103831d35Sstevel 		mct_system_info.max_units[SCB] = TG_MAX_SCB;
297203831d35Sstevel 		mct_system_info.max_units[SSB] = TG_MAX_SCB;
297303831d35Sstevel 		mct_system_info.max_units[CFTM] = TG_MAX_CFTM;
297403831d35Sstevel 		mct_system_info.max_units[CRTM] = TG_MAX_CRTM;
297503831d35Sstevel 		mct_system_info.max_units[PRTM] = TG_MAX_PRTM;
297603831d35Sstevel 		break;
297703831d35Sstevel 	default:
297803831d35Sstevel 		cmn_err(CE_WARN, "%s#%d: Unknown MidPlane Id %x",
297903831d35Sstevel 		    ddi_driver_name(scsb->scsb_dev),
298003831d35Sstevel 		    ddi_get_instance(scsb->scsb_dev),
298103831d35Sstevel 		    mct_system_info.mid_plane.fru_id);
298203831d35Sstevel 		if (scsb_debug & 0x00100005)
298303831d35Sstevel 			cmn_err(CE_NOTE, "scsb_set_topology: 0x%x: unknown!",
298403831d35Sstevel 			    mct_system_info.mid_plane.fru_id);
298503831d35Sstevel 		return;
298603831d35Sstevel 	}
298703831d35Sstevel 	/*
298803831d35Sstevel 	 * cPCI Slots
298903831d35Sstevel 	 *
299003831d35Sstevel 	 * NOTE: The Tonga slot fru_unit needs to get mapped to the logical
299103831d35Sstevel 	 * slot number in slot_table[].  The field is not in the slot_table
299203831d35Sstevel 	 * at least until we know the format of the OBP slot table for the FCS
299303831d35Sstevel 	 * release.
299403831d35Sstevel 	 */
299503831d35Sstevel 	mct_system_info.fru_info_list[SLOT] = (fru_info_t *)
299603831d35Sstevel 	    kmem_zalloc(sizeof (fru_info_t) *
299719397407SSherry Moore 	    (mct_system_info.max_units[SLOT] + pad), KM_SLEEP);
299803831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[SLOT];
299903831d35Sstevel 	for (unit = 1; unit <= mct_system_info.max_units[SLOT]; ++unit) {
300003831d35Sstevel 		int	iunit;
300103831d35Sstevel 		if (unit == cpu_slot_num) {
300203831d35Sstevel 			fru_ptr->fru_type = (scsb_utype_t)OC_CPU;
300303831d35Sstevel 		} else if (unit == ctc_slot_num) {
300403831d35Sstevel 			/* fru_ptr saved for Transition Card Presence check */
300503831d35Sstevel 			ctcslot_ptr = fru_ptr;
300603831d35Sstevel 			fru_ptr->fru_type = (scsb_utype_t)OC_UNKN;
300703831d35Sstevel 		} else if (unit == alarm_slot_num) {
300803831d35Sstevel 			/* fru_ptr saved for Alarm Card Presence check below */
300903831d35Sstevel 			acslot_ptr = fru_ptr;
301003831d35Sstevel 			fru_ptr->fru_type = (scsb_utype_t)OC_UNKN;
301103831d35Sstevel 		} else {
301203831d35Sstevel 			fru_ptr->fru_type = (scsb_utype_t)OC_UNKN;
301303831d35Sstevel 		}
301403831d35Sstevel 		/*
301503831d35Sstevel 		 * Get the slot event code (t), then use it to get the
301603831d35Sstevel 		 * slot bit-offsets for LED, BLINK, and SYSCFG registers.
301703831d35Sstevel 		 * On a P1.5 Tonga, the internal slot number must be used to
301803831d35Sstevel 		 * find the event code.
301903831d35Sstevel 		 * The P1.0 Tonga does not get mapped due to a SSB difference.
302003831d35Sstevel 		 */
302103831d35Sstevel 		if (IS_SCB_P15) {
302203831d35Sstevel 			iunit = tonga_psl_to_ssl(scsb, unit);
302303831d35Sstevel 			t = FRU_UNIT_TO_EVCODE(SLOT, iunit);
302403831d35Sstevel 		} else {
302503831d35Sstevel 			t = FRU_UNIT_TO_EVCODE(SLOT, unit);
302603831d35Sstevel 		}
302703831d35Sstevel 		led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
302803831d35Sstevel 		blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
302903831d35Sstevel 		blink_reg = FRU_REG_ADDR(t, SCTRL_BLINK_OK_BASE);
303003831d35Sstevel 		if (is_tonga && unit <= TG_MAX_SLOTS) {
303103831d35Sstevel 			bit_num = tonga_pslotnum_to_cfgbit(scsb, unit);
303203831d35Sstevel 		} else {
303303831d35Sstevel 			bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
303403831d35Sstevel 		}
303503831d35Sstevel 		/*
303603831d35Sstevel 		 * get the registers addresses and shadow register index for
303703831d35Sstevel 		 * the SYSCFG register
303803831d35Sstevel 		 */
303903831d35Sstevel 		syscfg = FRU_REG_ADDR(t, SCTRL_SYSCFG_BASE);
304003831d35Sstevel 		index = SCSB_REG_INDEX(syscfg);
304103831d35Sstevel 		led_reg = FRU_REG_ADDR(t, SCTRL_LED_OK_BASE);
304203831d35Sstevel 		/*
304303831d35Sstevel 		 * check and set presence status
304403831d35Sstevel 		 */
304503831d35Sstevel 		if (scsb->scsb_state & SCSB_P06_PROM) {
304603831d35Sstevel 			fru_ptr->fru_status = FRU_NOT_PRESENT;
304703831d35Sstevel 		} else if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
304803831d35Sstevel 			fru_ptr->fru_status = FRU_PRESENT;
304903831d35Sstevel 		} else {
305003831d35Sstevel 			fru_ptr->fru_status = FRU_NOT_PRESENT;
305103831d35Sstevel 		}
305203831d35Sstevel 		fru_ptr->fru_unit = (scsb_unum_t)unit;
305303831d35Sstevel 		fru_ptr->fru_id = fru_id_table[event_to_index(
305403831d35Sstevel 		    FRU_UNIT_TO_EVCODE(SLOT, unit))];
305503831d35Sstevel 		fru_ptr->fru_version = (fru_version_t)0;
305603831d35Sstevel 		fru_ptr->type_list = (fru_options_t *)NULL;
305703831d35Sstevel 		fru_ptr->i2c_info = (fru_i2c_info_t *)
305803831d35Sstevel 		    kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
305903831d35Sstevel 		fru_ptr->i2c_info->syscfg_reg = syscfg;
306003831d35Sstevel 		fru_ptr->i2c_info->syscfg_bit = bit_num;
306103831d35Sstevel 		fru_ptr->i2c_info->ledata_reg = led_reg;
306203831d35Sstevel 		fru_ptr->i2c_info->ledata_bit = led_bit;
306303831d35Sstevel 		fru_ptr->i2c_info->blink_reg = blink_reg;
306403831d35Sstevel 		fru_ptr->i2c_info->blink_bit = blink_bit;
306503831d35Sstevel 		last_ptr = fru_ptr;
306603831d35Sstevel 		fru_ptr++;
306703831d35Sstevel 		last_ptr->next = fru_ptr;
306803831d35Sstevel 	}
306903831d35Sstevel 	last_ptr->next = (fru_info_t *)NULL;
307003831d35Sstevel 	/*
307103831d35Sstevel 	 * PDU
307203831d35Sstevel 	 */
307303831d35Sstevel 	mct_system_info.fru_info_list[PDU] = (fru_info_t *)
307403831d35Sstevel 	    kmem_zalloc(sizeof (fru_info_t) *
307519397407SSherry Moore 	    (mct_system_info.max_units[PDU] + pad), KM_SLEEP);
307603831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[PDU];
307703831d35Sstevel 	for (unit = 1; unit <= mct_system_info.max_units[PDU]; ++unit) {
307803831d35Sstevel 		fru_ptr->fru_type = PDU;
307903831d35Sstevel 		/* SCB15 */
308003831d35Sstevel 		/*
308103831d35Sstevel 		 * get the FRU event code (t), then use it to get the
308203831d35Sstevel 		 * FRU bit-offsets for LED and SYSCFG registers
308303831d35Sstevel 		 */
308403831d35Sstevel 		t = FRU_UNIT_TO_EVCODE(PDU, unit);
308503831d35Sstevel 		led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
308603831d35Sstevel 		bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
308703831d35Sstevel 		if (IS_SCB_P15) {
308803831d35Sstevel 			blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
308903831d35Sstevel 			i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
309003831d35Sstevel 			blink_reg = SCSB_REG_ADDR(i);
309103831d35Sstevel 		} else {
309203831d35Sstevel 			blink_bit = 0;
309303831d35Sstevel 			blink_reg = 0;
309403831d35Sstevel 		}
309503831d35Sstevel 		/*
309603831d35Sstevel 		 * get the registers addresses and shadow register index for
309703831d35Sstevel 		 * the SYSCFG register
309803831d35Sstevel 		 */
309903831d35Sstevel 		i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
310003831d35Sstevel 		syscfg = SCSB_REG_ADDR(i);
310103831d35Sstevel 		index = SCSB_REG_INDEX(syscfg);
310203831d35Sstevel 		i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
310303831d35Sstevel 		led_reg = SCSB_REG_ADDR(i);
310403831d35Sstevel 		/*
310503831d35Sstevel 		 * check and set presence status
310603831d35Sstevel 		 */
310703831d35Sstevel 		if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
310803831d35Sstevel 			fru_ptr->fru_status = FRU_PRESENT;
310903831d35Sstevel 			fru_ptr->fru_version = (fru_version_t)0;
311003831d35Sstevel 		} else {
311103831d35Sstevel 			fru_ptr->fru_status = FRU_NOT_PRESENT;
311203831d35Sstevel 			fru_ptr->fru_version = (fru_version_t)0;
311303831d35Sstevel 		}
311403831d35Sstevel 		fru_ptr->fru_unit = (scsb_unum_t)unit;
311503831d35Sstevel 		fru_ptr->fru_id = fru_id_table[event_to_index(t)];
311603831d35Sstevel 		fru_ptr->type_list = (fru_options_t *)NULL;
311703831d35Sstevel 		fru_ptr->i2c_info = (fru_i2c_info_t *)
311803831d35Sstevel 		    kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
311903831d35Sstevel 		fru_ptr->i2c_info->syscfg_reg = syscfg;
312003831d35Sstevel 		fru_ptr->i2c_info->syscfg_bit = bit_num;
312103831d35Sstevel 		fru_ptr->i2c_info->ledata_reg = led_reg;
312203831d35Sstevel 		fru_ptr->i2c_info->ledata_bit = led_bit;
312303831d35Sstevel 		fru_ptr->i2c_info->blink_reg = blink_reg;
312403831d35Sstevel 		fru_ptr->i2c_info->blink_bit = blink_bit;
312503831d35Sstevel 		last_ptr = fru_ptr;
312603831d35Sstevel 		fru_ptr++;
312703831d35Sstevel 		last_ptr->next = fru_ptr;
312803831d35Sstevel 	}
312903831d35Sstevel 	last_ptr->next = (fru_info_t *)NULL;
313003831d35Sstevel 	/*
313103831d35Sstevel 	 * Power Supplies
313203831d35Sstevel 	 */
313303831d35Sstevel 	mct_system_info.fru_info_list[PS] = (fru_info_t *)
313403831d35Sstevel 	    kmem_zalloc(sizeof (fru_info_t) *
313519397407SSherry Moore 	    (mct_system_info.max_units[PS] + pad), KM_SLEEP);
313603831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[PS];
313703831d35Sstevel 	for (unit = 1; unit <= mct_system_info.max_units[PS]; ++unit) {
313803831d35Sstevel 		/*
313903831d35Sstevel 		 * get the FRU event code (t), then use it to get the
314003831d35Sstevel 		 * FRU bit-offsets for LED and SYSCFG registers
314103831d35Sstevel 		 */
314203831d35Sstevel 		t = FRU_UNIT_TO_EVCODE(PS, unit);
314303831d35Sstevel 		led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
314403831d35Sstevel 		bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
314503831d35Sstevel 		if (IS_SCB_P15) {
314603831d35Sstevel 			blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
314703831d35Sstevel 			i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
314803831d35Sstevel 			blink_reg = SCSB_REG_ADDR(i);
314903831d35Sstevel 		} else {
315003831d35Sstevel 			blink_bit = 0;
315103831d35Sstevel 			blink_reg = 0;
315203831d35Sstevel 		}
315303831d35Sstevel 		/*
315403831d35Sstevel 		 * get the registers addresses and shadow register index for
315503831d35Sstevel 		 * the SYSCFG register
315603831d35Sstevel 		 */
315703831d35Sstevel 		i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
315803831d35Sstevel 		syscfg = SCSB_REG_ADDR(i);
315903831d35Sstevel 		index = SCSB_REG_INDEX(syscfg);
316003831d35Sstevel 		i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
316103831d35Sstevel 		led_reg = SCSB_REG_ADDR(i);
316203831d35Sstevel 		/*
316303831d35Sstevel 		 * check and set presence status
316403831d35Sstevel 		 */
316503831d35Sstevel 		if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
316603831d35Sstevel 			fru_ptr->fru_status = FRU_PRESENT;
316703831d35Sstevel 		} else {
316803831d35Sstevel 			fru_ptr->fru_status = FRU_NOT_PRESENT;
316903831d35Sstevel 		}
317003831d35Sstevel 		fru_ptr->fru_type = PS;
317103831d35Sstevel 		fru_ptr->fru_unit = (scsb_unum_t)unit;
317203831d35Sstevel 		fru_ptr->fru_id = fru_id_table[event_to_index(t)];
317303831d35Sstevel 		fru_ptr->fru_version = (fru_version_t)0;
317403831d35Sstevel 		fru_ptr->type_list = (fru_options_t *)NULL;
317503831d35Sstevel 		fru_ptr->i2c_info = (fru_i2c_info_t *)
317603831d35Sstevel 		    kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
317703831d35Sstevel 		fru_ptr->i2c_info->syscfg_reg = syscfg;
317803831d35Sstevel 		fru_ptr->i2c_info->syscfg_bit = bit_num;
317903831d35Sstevel 		fru_ptr->i2c_info->ledata_reg = led_reg;
318003831d35Sstevel 		fru_ptr->i2c_info->ledata_bit = led_bit;
318103831d35Sstevel 		fru_ptr->i2c_info->blink_reg = blink_reg;
318203831d35Sstevel 		fru_ptr->i2c_info->blink_bit = blink_bit;
318303831d35Sstevel 		last_ptr = fru_ptr;
318403831d35Sstevel 		fru_ptr++;
318503831d35Sstevel 		last_ptr->next = fru_ptr;
318603831d35Sstevel 	}
318703831d35Sstevel 	last_ptr->next = (fru_info_t *)NULL;
318803831d35Sstevel 	/*
318903831d35Sstevel 	 * SCSI Disks and removable media
319003831d35Sstevel 	 */
319103831d35Sstevel 	mct_system_info.fru_info_list[DISK] = (fru_info_t *)
319203831d35Sstevel 	    kmem_zalloc(sizeof (fru_info_t) *
319319397407SSherry Moore 	    (mct_system_info.max_units[DISK] + pad), KM_SLEEP);
319403831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[DISK];
319503831d35Sstevel 	for (unit = 1; unit <= mct_system_info.max_units[DISK]; ++unit) {
319603831d35Sstevel 		/* SCB15 */
319703831d35Sstevel 		/*
319803831d35Sstevel 		 * get the FRU event code (t), then use it to get the
319903831d35Sstevel 		 * FRU bit-offsets for LED and SYSCFG registers
320003831d35Sstevel 		 */
320103831d35Sstevel 		t = FRU_UNIT_TO_EVCODE(DISK, unit);
320203831d35Sstevel 		led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
320303831d35Sstevel 		bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
320403831d35Sstevel 		if (IS_SCB_P15) {
320503831d35Sstevel 			blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
320603831d35Sstevel 			i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
320703831d35Sstevel 			blink_reg = SCSB_REG_ADDR(i);
320803831d35Sstevel 		} else {
320903831d35Sstevel 			blink_bit = 0;
321003831d35Sstevel 			blink_reg = 0;
321103831d35Sstevel 		}
321203831d35Sstevel 		/*
321303831d35Sstevel 		 * get the registers addresses and shadow register index for
321403831d35Sstevel 		 * the SYSCFG register
321503831d35Sstevel 		 */
321603831d35Sstevel 		i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
321703831d35Sstevel 		syscfg = SCSB_REG_ADDR(i);
321803831d35Sstevel 		index = SCSB_REG_INDEX(syscfg);
321903831d35Sstevel 		i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
322003831d35Sstevel 		led_reg = SCSB_REG_ADDR(i);
322103831d35Sstevel 		/*
322203831d35Sstevel 		 * check and set presence status
322303831d35Sstevel 		 */
322403831d35Sstevel 		if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
322503831d35Sstevel 			fru_ptr->fru_status = FRU_PRESENT;
322603831d35Sstevel 			fru_ptr->fru_version = (fru_version_t)0;
322703831d35Sstevel 		} else
322803831d35Sstevel 			fru_ptr->fru_status = FRU_NOT_PRESENT;
322903831d35Sstevel 		fru_ptr->fru_type = DISK;
323003831d35Sstevel 		fru_ptr->fru_unit = (scsb_unum_t)unit;
323103831d35Sstevel 		fru_ptr->fru_id = fru_id_table[event_to_index(t)];
323203831d35Sstevel 		fru_ptr->type_list = (fru_options_t *)NULL;
323303831d35Sstevel 		fru_ptr->i2c_info = (fru_i2c_info_t *)
323403831d35Sstevel 		    kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
323503831d35Sstevel 		fru_ptr->i2c_info->syscfg_reg = syscfg;
323603831d35Sstevel 		fru_ptr->i2c_info->syscfg_bit = bit_num;
323703831d35Sstevel 		fru_ptr->i2c_info->ledata_reg = led_reg;
323803831d35Sstevel 		fru_ptr->i2c_info->ledata_bit = led_bit;
323903831d35Sstevel 		fru_ptr->i2c_info->blink_reg = blink_reg;
324003831d35Sstevel 		fru_ptr->i2c_info->blink_bit = blink_bit;
324103831d35Sstevel 		last_ptr = fru_ptr;
324203831d35Sstevel 		fru_ptr++;
324303831d35Sstevel 		last_ptr->next = fru_ptr;
324403831d35Sstevel 	}
324503831d35Sstevel 	last_ptr->next = (fru_info_t *)NULL;
324603831d35Sstevel 	/*
324703831d35Sstevel 	 * Fan Trays
324803831d35Sstevel 	 */
324903831d35Sstevel 	mct_system_info.fru_info_list[FAN] = (fru_info_t *)
325003831d35Sstevel 	    kmem_zalloc(sizeof (fru_info_t) *
325119397407SSherry Moore 	    (mct_system_info.max_units[FAN] + pad), KM_SLEEP);
325203831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[FAN];
325303831d35Sstevel 	for (unit = 1; unit <= mct_system_info.max_units[FAN]; ++unit) {
325403831d35Sstevel 		int		bit_num;
325503831d35Sstevel 		/* SCB15 */
325603831d35Sstevel 		/*
325703831d35Sstevel 		 * get the FRU event code (t), then use it to get the
325803831d35Sstevel 		 * FRU bit-offsets for LED and SYSCFG registers
325903831d35Sstevel 		 */
326003831d35Sstevel 		t = FRU_UNIT_TO_EVCODE(FAN, unit);
326103831d35Sstevel 		led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
326203831d35Sstevel 		bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
326303831d35Sstevel 		if (IS_SCB_P15) {
326403831d35Sstevel 			blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
326503831d35Sstevel 			i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
326603831d35Sstevel 			blink_reg = SCSB_REG_ADDR(i);
326703831d35Sstevel 		} else {
326803831d35Sstevel 			blink_bit = 0;
326903831d35Sstevel 			blink_reg = 0;
327003831d35Sstevel 		}
327103831d35Sstevel 		/*
327203831d35Sstevel 		 * get the registers addresses and shadow register index for
327303831d35Sstevel 		 * the SYSCFG register
327403831d35Sstevel 		 */
327503831d35Sstevel 		i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
327603831d35Sstevel 		syscfg = SCSB_REG_ADDR(i);
327703831d35Sstevel 		index = SCSB_REG_INDEX(syscfg);
327803831d35Sstevel 		i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
327903831d35Sstevel 		led_reg = SCSB_REG_ADDR(i);
328003831d35Sstevel 		/*
328103831d35Sstevel 		 * check and set presence status
328203831d35Sstevel 		 */
328303831d35Sstevel 		if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
328403831d35Sstevel 			fru_ptr->fru_status = FRU_PRESENT;
328503831d35Sstevel 		} else {
328603831d35Sstevel 			fru_ptr->fru_status = FRU_NOT_PRESENT;
328703831d35Sstevel 		}
328803831d35Sstevel 		fru_ptr->fru_type = FAN;
328903831d35Sstevel 		fru_ptr->fru_unit = (scsb_unum_t)unit;
329003831d35Sstevel 		fru_ptr->fru_id = fru_id_table[event_to_index(t)];
329103831d35Sstevel 		fru_ptr->fru_version = (fru_version_t)0;
329203831d35Sstevel 		fru_ptr->type_list = (fru_options_t *)NULL;
329303831d35Sstevel 		fru_ptr->i2c_info = (fru_i2c_info_t *)
329403831d35Sstevel 		    kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
329503831d35Sstevel 		fru_ptr->i2c_info->syscfg_reg = syscfg;
329603831d35Sstevel 		fru_ptr->i2c_info->syscfg_bit = bit_num;
329703831d35Sstevel 		fru_ptr->i2c_info->ledata_reg = led_reg;
329803831d35Sstevel 		fru_ptr->i2c_info->ledata_bit = led_bit;
329903831d35Sstevel 		fru_ptr->i2c_info->blink_reg = blink_reg;
330003831d35Sstevel 		fru_ptr->i2c_info->blink_bit = blink_bit;
330103831d35Sstevel 		last_ptr = fru_ptr;
330203831d35Sstevel 		fru_ptr++;
330303831d35Sstevel 		last_ptr->next = fru_ptr;
330403831d35Sstevel 	}
330503831d35Sstevel 	last_ptr->next = (fru_info_t *)NULL;
330603831d35Sstevel 	/*
330703831d35Sstevel 	 * Alarm Cards
330803831d35Sstevel 	 */
330903831d35Sstevel 	mct_system_info.fru_info_list[ALARM] = (fru_info_t *)
331003831d35Sstevel 	    kmem_zalloc(sizeof (fru_info_t) *
331119397407SSherry Moore 	    (mct_system_info.max_units[ALARM] + pad), KM_SLEEP);
331203831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[ALARM];
331303831d35Sstevel 	for (unit = 1; unit <= mct_system_info.max_units[ALARM]; ++unit) {
331403831d35Sstevel 		int		bit_num;
331503831d35Sstevel 
331603831d35Sstevel 		/*
331703831d35Sstevel 		 * get the FRU event code (t), then use it to get the
331803831d35Sstevel 		 * FRU bit-offsets for SYSCFG register
331903831d35Sstevel 		 */
332003831d35Sstevel 		t = FRU_UNIT_TO_EVCODE(ALARM, unit);
332103831d35Sstevel 		bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
332203831d35Sstevel 		/*
332303831d35Sstevel 		 * get the registers addresses and shadow register index for
332403831d35Sstevel 		 * the SYSCFG register
332503831d35Sstevel 		 */
332603831d35Sstevel 		i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
332703831d35Sstevel 		syscfg = SCSB_REG_ADDR(i);
332803831d35Sstevel 		index = SCSB_REG_INDEX(syscfg);
332903831d35Sstevel 		/*
333003831d35Sstevel 		 * check and set presence status
333103831d35Sstevel 		 */
333203831d35Sstevel 		if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
333303831d35Sstevel 			fru_ptr->fru_status = FRU_PRESENT;
333403831d35Sstevel 			if (acslot_ptr != NULL && acslot_ptr->fru_status ==
333503831d35Sstevel 			    FRU_PRESENT) {
333603831d35Sstevel 				acslot_ptr->fru_type = (scsb_utype_t)OC_AC;
333703831d35Sstevel 				/*
333803831d35Sstevel 				 * acslot_ptr->fru_id =
333903831d35Sstevel 				 *	fru_id_table[event_to_index(t)];
334003831d35Sstevel 				 */
334103831d35Sstevel 			}
334203831d35Sstevel 		} else {
334303831d35Sstevel 			fru_ptr->fru_status = FRU_NOT_PRESENT;
334403831d35Sstevel 		}
334503831d35Sstevel 
334603831d35Sstevel 		fru_ptr->fru_type = ALARM;
334703831d35Sstevel 		fru_ptr->fru_unit = (scsb_unum_t)unit;
334803831d35Sstevel 		fru_ptr->fru_id = fru_id_table[event_to_index(t)];
334903831d35Sstevel 		fru_ptr->fru_version = (fru_version_t)0;
335003831d35Sstevel 		fru_ptr->type_list = (fru_options_t *)NULL;
335103831d35Sstevel 		fru_ptr->i2c_info = (fru_i2c_info_t *)
335203831d35Sstevel 		    kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
335303831d35Sstevel 		fru_ptr->i2c_info->syscfg_reg = syscfg;
335403831d35Sstevel 		fru_ptr->i2c_info->syscfg_bit = bit_num;
335503831d35Sstevel 		fru_ptr->i2c_info->ledata_reg = 0;
335603831d35Sstevel 		fru_ptr->i2c_info->ledata_bit = 0;
335703831d35Sstevel 		fru_ptr->i2c_info->blink_reg = 0;
335803831d35Sstevel 		fru_ptr->i2c_info->blink_bit = 0;
335903831d35Sstevel 		last_ptr = fru_ptr;
336003831d35Sstevel 		fru_ptr++;
336103831d35Sstevel 		last_ptr->next = fru_ptr;
336203831d35Sstevel 	}
336303831d35Sstevel 	last_ptr->next = (fru_info_t *)NULL;
336403831d35Sstevel 	/*
336503831d35Sstevel 	 * SCB
336603831d35Sstevel 	 */
336703831d35Sstevel 	mct_system_info.fru_info_list[SCB] = (fru_info_t *)
336803831d35Sstevel 	    kmem_zalloc(sizeof (fru_info_t) *
336919397407SSherry Moore 	    (mct_system_info.max_units[SCB] + pad), KM_SLEEP);
337003831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[SCB];
337103831d35Sstevel 	unit = 1;
337203831d35Sstevel 	/* SCB15 */
337303831d35Sstevel 	/*
337403831d35Sstevel 	 * get the FRU event code (t), then use it to get the
337503831d35Sstevel 	 * FRU bit-offset for LED register
337603831d35Sstevel 	 */
337703831d35Sstevel 	t = FRU_UNIT_TO_EVCODE(SCB, unit);
337803831d35Sstevel 	led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
337903831d35Sstevel 	i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
338003831d35Sstevel 	led_reg = SCSB_REG_ADDR(i);
338103831d35Sstevel 	if (IS_SCB_P15) {
338203831d35Sstevel 		blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
338303831d35Sstevel 		i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
338403831d35Sstevel 		blink_reg = SCSB_REG_ADDR(i);
338503831d35Sstevel 	} else {
338603831d35Sstevel 		blink_bit = 0;
338703831d35Sstevel 		blink_reg = 0;
338803831d35Sstevel 	}
338903831d35Sstevel 	i = SYS_REG_INDEX(SCTRL_SCBID0, SCTRL_SCBID_BASE);
339003831d35Sstevel 	index = SCSB_REG_ADDR(i);
339103831d35Sstevel 	/*
339203831d35Sstevel 	 * check and set presence status
339303831d35Sstevel 	 */
339403831d35Sstevel 	if (scsb->scsb_state & SCSB_SCB_PRESENT) {
339503831d35Sstevel 		fru_ptr->fru_status = FRU_PRESENT;
339603831d35Sstevel 	} else {
339703831d35Sstevel 		fru_ptr->fru_status = FRU_NOT_PRESENT;
339803831d35Sstevel 	}
339903831d35Sstevel 	fru_ptr->fru_type = SCB;
340003831d35Sstevel 	fru_ptr->fru_unit = (scsb_unum_t)unit;
340103831d35Sstevel 	fru_ptr->fru_id = fru_id_table[event_to_index(t)];
340203831d35Sstevel 	/* get PROM_VERSION from shadow registers */
340303831d35Sstevel 	if (scsb_rdwr_register(scsb, I2C_WR_RD, index, 1, &t_uchar, 1))
340403831d35Sstevel 		fru_ptr->fru_version = (fru_version_t)0;
340503831d35Sstevel 	else
340603831d35Sstevel 		fru_ptr->fru_version = (fru_version_t)t_uchar;
340703831d35Sstevel 	fru_ptr->type_list = (fru_options_t *)NULL;
340803831d35Sstevel 	fru_ptr->i2c_info = (fru_i2c_info_t *)
340903831d35Sstevel 	    kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
341003831d35Sstevel 	fru_ptr->i2c_info->syscfg_reg = 0;
341103831d35Sstevel 	fru_ptr->i2c_info->syscfg_bit = 0;
341203831d35Sstevel 	fru_ptr->i2c_info->ledata_reg = led_reg;
341303831d35Sstevel 	fru_ptr->i2c_info->ledata_bit = led_bit;
341403831d35Sstevel 	fru_ptr->i2c_info->blink_reg = blink_reg;
341503831d35Sstevel 	fru_ptr->i2c_info->blink_bit = blink_bit;
341603831d35Sstevel 	fru_ptr->next = (fru_info_t *)NULL;
341703831d35Sstevel 	/*
341803831d35Sstevel 	 * SSB
341903831d35Sstevel 	 */
342003831d35Sstevel 	mct_system_info.fru_info_list[SSB] = (fru_info_t *)
342103831d35Sstevel 	    kmem_zalloc(sizeof (fru_info_t) *
342219397407SSherry Moore 	    (mct_system_info.max_units[SSB] + pad), KM_SLEEP);
342303831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[SSB];
342403831d35Sstevel 	unit = 1;
342503831d35Sstevel 	/* SCB15 */
342603831d35Sstevel 	/*
342703831d35Sstevel 	 * get the FRU event code (t), then use it to get the
342803831d35Sstevel 	 * FRU bit-offset for SYSCFG register
342903831d35Sstevel 	 */
343003831d35Sstevel 	t = FRU_UNIT_TO_EVCODE(SSB, unit);
343103831d35Sstevel 	bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
343203831d35Sstevel 	/*
343303831d35Sstevel 	 * get the registers addresses and shadow register index for
343403831d35Sstevel 	 * the SYSCFG register
343503831d35Sstevel 	 */
343603831d35Sstevel 	i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
343703831d35Sstevel 	syscfg = SCSB_REG_ADDR(i);
343803831d35Sstevel 	index = SCSB_REG_INDEX(syscfg);
343903831d35Sstevel 	/*
344003831d35Sstevel 	 * check and set presence status
344103831d35Sstevel 	 */
344203831d35Sstevel 	if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
344303831d35Sstevel 		fru_ptr->fru_status = FRU_PRESENT;
344403831d35Sstevel 	} else {
344503831d35Sstevel 		fru_ptr->fru_status = FRU_NOT_PRESENT;
344603831d35Sstevel 	}
344703831d35Sstevel 	fru_ptr->fru_type = SSB;
344803831d35Sstevel 	fru_ptr->fru_unit = (scsb_unum_t)unit;
344903831d35Sstevel 	fru_ptr->fru_id = fru_id_table[event_to_index(t)];
345003831d35Sstevel 	fru_ptr->fru_version = (fru_version_t)0;
345103831d35Sstevel 	fru_ptr->type_list = (fru_options_t *)NULL;
345203831d35Sstevel 	fru_ptr->i2c_info = (fru_i2c_info_t *)
345303831d35Sstevel 	    kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
345403831d35Sstevel 	fru_ptr->i2c_info->syscfg_reg = syscfg;
345503831d35Sstevel 	fru_ptr->i2c_info->syscfg_bit = bit_num;
345603831d35Sstevel 	fru_ptr->i2c_info->ledata_reg = 0;
345703831d35Sstevel 	fru_ptr->i2c_info->ledata_bit = 0;
345803831d35Sstevel 	fru_ptr->i2c_info->blink_reg = 0;
345903831d35Sstevel 	fru_ptr->i2c_info->blink_bit = 0;
346003831d35Sstevel 	fru_ptr->next = (fru_info_t *)NULL;
346103831d35Sstevel 	/*
346203831d35Sstevel 	 * CFTM
346303831d35Sstevel 	 */
346403831d35Sstevel 	mct_system_info.fru_info_list[CFTM] = (fru_info_t *)
346503831d35Sstevel 	    kmem_zalloc(sizeof (fru_info_t) *
346619397407SSherry Moore 	    (mct_system_info.max_units[CFTM] + pad), KM_SLEEP);
346703831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[CFTM];
346803831d35Sstevel 	unit = 1;
346903831d35Sstevel 	/* SCB15 */
347003831d35Sstevel 	/*
347103831d35Sstevel 	 * get the FRU event code (t), then use it to get the
347203831d35Sstevel 	 * FRU bit-offsets for LED and SYSCFG registers
347303831d35Sstevel 	 */
347403831d35Sstevel 	t = FRU_UNIT_TO_EVCODE(CFTM, unit);
347503831d35Sstevel 	led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
347603831d35Sstevel 	bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
347703831d35Sstevel 	if (IS_SCB_P15) {
347803831d35Sstevel 		blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
347903831d35Sstevel 		i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
348003831d35Sstevel 		blink_reg = SCSB_REG_ADDR(i);
348103831d35Sstevel 	} else {
348203831d35Sstevel 		blink_bit = 0;
348303831d35Sstevel 		blink_reg = 0;
348403831d35Sstevel 	}
348503831d35Sstevel 	/*
348603831d35Sstevel 	 * get the registers addresses and shadow register index for
348703831d35Sstevel 	 * the SYSCFG register
348803831d35Sstevel 	 */
348903831d35Sstevel 	i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
349003831d35Sstevel 	syscfg = SCSB_REG_ADDR(i);
349103831d35Sstevel 	index = SCSB_REG_INDEX(syscfg);
349203831d35Sstevel 	i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
349303831d35Sstevel 	led_reg = SCSB_REG_ADDR(i);
349403831d35Sstevel 	/*
349503831d35Sstevel 	 * check and set presence status
349603831d35Sstevel 	 */
349703831d35Sstevel 	if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
349803831d35Sstevel 		fru_ptr->fru_status = FRU_PRESENT;
349903831d35Sstevel 		if (ctcslot_ptr != NULL && ctcslot_ptr->fru_status ==
350003831d35Sstevel 		    FRU_PRESENT) {
350103831d35Sstevel 			ctcslot_ptr->fru_type = (scsb_utype_t)OC_CTC;
350203831d35Sstevel 			scsb->scsb_hsc_state |= SCSB_HSC_CTC_PRES;
350303831d35Sstevel 		}
350403831d35Sstevel 	} else {
350503831d35Sstevel 		fru_ptr->fru_status = FRU_NOT_PRESENT;
350603831d35Sstevel 	}
350703831d35Sstevel 	fru_ptr->fru_type = CFTM;
350803831d35Sstevel 	fru_ptr->fru_unit = (scsb_unum_t)1;
350903831d35Sstevel 	fru_ptr->fru_id = fru_id_table[event_to_index(t)];
351003831d35Sstevel 	fru_ptr->fru_version = (fru_version_t)0;
351103831d35Sstevel 	fru_ptr->type_list = (fru_options_t *)NULL;
351203831d35Sstevel 	fru_ptr->i2c_info = (fru_i2c_info_t *)
351303831d35Sstevel 	    kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
351403831d35Sstevel 	fru_ptr->i2c_info->syscfg_reg = syscfg;
351503831d35Sstevel 	fru_ptr->i2c_info->syscfg_bit = bit_num;
351603831d35Sstevel 	fru_ptr->i2c_info->ledata_reg = led_reg;
351703831d35Sstevel 	fru_ptr->i2c_info->ledata_bit = led_bit;
351803831d35Sstevel 	fru_ptr->i2c_info->blink_reg = blink_reg;
351903831d35Sstevel 	fru_ptr->i2c_info->blink_bit = blink_bit;
352003831d35Sstevel 	fru_ptr->next = (fru_info_t *)NULL;
352103831d35Sstevel 	/*
352203831d35Sstevel 	 * CRTM
352303831d35Sstevel 	 */
352403831d35Sstevel 	mct_system_info.fru_info_list[CRTM] = (fru_info_t *)
352503831d35Sstevel 	    kmem_zalloc(sizeof (fru_info_t) *
352603831d35Sstevel 	    (mct_system_info.max_units[CRTM] + pad),
352703831d35Sstevel 	    KM_SLEEP);
352803831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[CRTM];
352903831d35Sstevel 	unit = 1;
353003831d35Sstevel 	/* SCB15 */
353103831d35Sstevel 	/*
353203831d35Sstevel 	 * get the FRU event code (t), then use it to get the
353303831d35Sstevel 	 * FRU bit-offsets for LED and SYSCFG registers
353403831d35Sstevel 	 */
353503831d35Sstevel 	t = FRU_UNIT_TO_EVCODE(CRTM, unit);
353603831d35Sstevel 	bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
353703831d35Sstevel 	/*
353803831d35Sstevel 	 * get the registers addresses and shadow register index for
353903831d35Sstevel 	 * the SYSCFG register
354003831d35Sstevel 	 */
354103831d35Sstevel 	i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
354203831d35Sstevel 	syscfg = SCSB_REG_ADDR(i);
354303831d35Sstevel 	index = SCSB_REG_INDEX(syscfg);
354403831d35Sstevel 	/*
354503831d35Sstevel 	 * check and set presence status
354603831d35Sstevel 	 */
354703831d35Sstevel 	if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
354803831d35Sstevel 		fru_ptr->fru_status = FRU_PRESENT;
354903831d35Sstevel 	} else {
355003831d35Sstevel 		fru_ptr->fru_status = FRU_NOT_PRESENT;
355103831d35Sstevel 	}
355203831d35Sstevel 	fru_ptr->fru_type = CRTM;
355303831d35Sstevel 	fru_ptr->fru_unit = (scsb_unum_t)unit;
355403831d35Sstevel 	fru_ptr->fru_id = fru_id_table[event_to_index(t)];
355503831d35Sstevel 	fru_ptr->fru_version = (fru_version_t)0;
355603831d35Sstevel 	fru_ptr->type_list = (fru_options_t *)NULL;
355703831d35Sstevel 	fru_ptr->i2c_info = (fru_i2c_info_t *)
355803831d35Sstevel 	    kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
355903831d35Sstevel 	fru_ptr->i2c_info->syscfg_reg = syscfg;
356003831d35Sstevel 	fru_ptr->i2c_info->syscfg_bit = bit_num;
356103831d35Sstevel 	fru_ptr->i2c_info->ledata_reg = 0;
356203831d35Sstevel 	fru_ptr->i2c_info->ledata_bit = 0;
356303831d35Sstevel 	fru_ptr->i2c_info->blink_reg = 0;
356403831d35Sstevel 	fru_ptr->i2c_info->blink_bit = 0;
356503831d35Sstevel 	fru_ptr->next = (fru_info_t *)NULL;
356603831d35Sstevel 	/*
356703831d35Sstevel 	 * PRTM
356803831d35Sstevel 	 */
356903831d35Sstevel 	mct_system_info.fru_info_list[PRTM] = (fru_info_t *)
357003831d35Sstevel 	    kmem_zalloc(sizeof (fru_info_t) *
357119397407SSherry Moore 	    (mct_system_info.max_units[PRTM] + pad), KM_SLEEP);
357203831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[PRTM];
357303831d35Sstevel 	unit = 1;
357403831d35Sstevel 	/*
357503831d35Sstevel 	 * SCB15
357603831d35Sstevel 	 * get the FRU event code (t), then use it to get the
357703831d35Sstevel 	 * FRU bit-offsets for LED and SYSCFG registers
357803831d35Sstevel 	 */
357903831d35Sstevel 	t = FRU_UNIT_TO_EVCODE(PRTM, unit);
358003831d35Sstevel 	bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
358103831d35Sstevel 	/*
358203831d35Sstevel 	 * get the registers addresses and shadow register index for
358303831d35Sstevel 	 * the SYSCFG register
358403831d35Sstevel 	 */
358503831d35Sstevel 	i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
358603831d35Sstevel 	syscfg = SCSB_REG_ADDR(i);
358703831d35Sstevel 	index = SCSB_REG_INDEX(syscfg);
358803831d35Sstevel 	/*
358903831d35Sstevel 	 * check and set presence status
359003831d35Sstevel 	 */
359103831d35Sstevel 	if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
359203831d35Sstevel 		fru_ptr->fru_status = FRU_PRESENT;
359303831d35Sstevel 	} else {
359403831d35Sstevel 		fru_ptr->fru_status = FRU_NOT_PRESENT;
359503831d35Sstevel 	}
359603831d35Sstevel 	fru_ptr->fru_type = PRTM;
359703831d35Sstevel 	fru_ptr->fru_unit = (scsb_unum_t)unit;
359803831d35Sstevel 	fru_ptr->fru_id = fru_id_table[event_to_index(t)];
359903831d35Sstevel 	fru_ptr->fru_version = (fru_version_t)0;
360003831d35Sstevel 	fru_ptr->type_list = (fru_options_t *)NULL;
360103831d35Sstevel 	fru_ptr->i2c_info = (fru_i2c_info_t *)
360203831d35Sstevel 	    kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
360303831d35Sstevel 	fru_ptr->i2c_info->syscfg_reg = syscfg;
360403831d35Sstevel 	fru_ptr->i2c_info->syscfg_bit = bit_num;
360503831d35Sstevel 	fru_ptr->i2c_info->ledata_reg = 0;
360603831d35Sstevel 	fru_ptr->i2c_info->ledata_bit = 0;
360703831d35Sstevel 	fru_ptr->i2c_info->blink_reg = 0;
360803831d35Sstevel 	fru_ptr->i2c_info->blink_bit = 0;
360903831d35Sstevel 	fru_ptr->next = (fru_info_t *)NULL;
361003831d35Sstevel 
361103831d35Sstevel 	scsb->scsb_state |= SCSB_TOPOLOGY;
361203831d35Sstevel #ifdef DEBUG
361303831d35Sstevel 	mct_topology_dump(scsb, 0);
361403831d35Sstevel #endif
361503831d35Sstevel }
361603831d35Sstevel 
361703831d35Sstevel /*ARGSUSED*/
361803831d35Sstevel static void
361903831d35Sstevel scsb_free_topology(scsb_state_t *scsb)
362003831d35Sstevel {
362103831d35Sstevel 	int		i;
362203831d35Sstevel 	fru_info_t	*fru_ptr;
362303831d35Sstevel 
362403831d35Sstevel 	if (scsb_debug & 0x00100005)
362503831d35Sstevel 		cmn_err(CE_NOTE, "scsb_free_topology:");
362603831d35Sstevel 	for (i = 0; i < SCSB_UNIT_TYPES; ++i) {
362703831d35Sstevel 		fru_ptr = mct_system_info.fru_info_list[i];
362803831d35Sstevel 		while (fru_ptr != NULL) {
362903831d35Sstevel 			if (fru_ptr->i2c_info != (fru_i2c_info_t *)NULL)
363003831d35Sstevel 				kmem_free(fru_ptr->i2c_info,
363103831d35Sstevel 				    sizeof (fru_i2c_info_t));
363203831d35Sstevel 			fru_ptr = fru_ptr->next;
363303831d35Sstevel 		}
363403831d35Sstevel 		if ((fru_ptr = mct_system_info.fru_info_list[i]) !=
363503831d35Sstevel 		    (fru_info_t *)NULL) {
363603831d35Sstevel 			kmem_free(fru_ptr, sizeof (fru_info_t) *
363703831d35Sstevel 			    mct_system_info.max_units[i]);
363803831d35Sstevel 			mct_system_info.fru_info_list[i] = (fru_info_t *)NULL;
363903831d35Sstevel 		}
364003831d35Sstevel 	}
364103831d35Sstevel }
364203831d35Sstevel 
364303831d35Sstevel #ifdef DEBUG
364403831d35Sstevel static void
364503831d35Sstevel mct_topology_dump(scsb_state_t *scsb, int force)
364603831d35Sstevel {
364703831d35Sstevel 	int		i;
364803831d35Sstevel 	fru_info_t	*fru_ptr;
364903831d35Sstevel 
365003831d35Sstevel 	if (!force && !(scsb_debug & 0x00200000))
365103831d35Sstevel 		return;
365203831d35Sstevel 	if (force && !(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)))
365303831d35Sstevel 		return;
365403831d35Sstevel 	if (!(scsb->scsb_state & SCSB_TOPOLOGY)) {
365503831d35Sstevel 		cmn_err(CE_NOTE, "mct_topology_dump: Topology not set!");
365603831d35Sstevel 		return;
365703831d35Sstevel 	}
365803831d35Sstevel 	for (i = 0; i < SCSB_UNIT_TYPES; ++i) {
365903831d35Sstevel 		fru_ptr = mct_system_info.fru_info_list[i];
366003831d35Sstevel 		switch ((scsb_utype_t)i) {
366103831d35Sstevel 		case SLOT:
366203831d35Sstevel 			cmn_err(CE_NOTE, "MCT: Number of Slots: %d",
366303831d35Sstevel 			    mct_system_info.max_units[SLOT]);
366403831d35Sstevel 			break;
366503831d35Sstevel 		case ALARM:
366603831d35Sstevel 			cmn_err(CE_NOTE, "MCT: MAX Number of Alarm Cards: %d",
366703831d35Sstevel 			    mct_system_info.max_units[ALARM]);
366803831d35Sstevel 			break;
366903831d35Sstevel 		case DISK:
367003831d35Sstevel 			cmn_err(CE_NOTE, "MCT: MAX Number of SCSI Devices: %d",
367103831d35Sstevel 			    mct_system_info.max_units[DISK]);
367203831d35Sstevel 			break;
367303831d35Sstevel 		case FAN:
367403831d35Sstevel 			cmn_err(CE_NOTE, "MCT: MAX Number of Fan Trays: %d",
367503831d35Sstevel 			    mct_system_info.max_units[FAN]);
367603831d35Sstevel 			break;
367703831d35Sstevel 		case PDU:
367803831d35Sstevel 			cmn_err(CE_NOTE, "MCT: MAX Number of PDUs: %d",
367903831d35Sstevel 			    mct_system_info.max_units[PDU]);
368003831d35Sstevel 			break;
368103831d35Sstevel 		case PS:
368203831d35Sstevel 			cmn_err(CE_NOTE,
368303831d35Sstevel 			    "MCT: MAX Number of Power Supplies: %d",
368403831d35Sstevel 			    mct_system_info.max_units[PS]);
368503831d35Sstevel 			break;
368603831d35Sstevel 		case SCB:
368703831d35Sstevel 			cmn_err(CE_NOTE, "MCT: MAX Number of SCBs: %d",
368803831d35Sstevel 			    mct_system_info.max_units[SCB]);
368903831d35Sstevel 			break;
369003831d35Sstevel 		case SSB:
369103831d35Sstevel 			cmn_err(CE_NOTE, "MCT: MAX Number of SSBs: %d",
369203831d35Sstevel 			    mct_system_info.max_units[SSB]);
369303831d35Sstevel 			break;
369403831d35Sstevel 		}
369503831d35Sstevel 		while (fru_ptr != NULL) {
369603831d35Sstevel 			if (fru_ptr->fru_status & FRU_PRESENT) {
369703831d35Sstevel 				cmn_err(CE_NOTE,
369803831d35Sstevel 				    "MCT:   type=%d, unit=%d, id=0x%x, "
369903831d35Sstevel 				    "version=0x%x",
370003831d35Sstevel 				    fru_ptr->fru_type,
370103831d35Sstevel 				    fru_ptr->fru_unit,
370203831d35Sstevel 				    fru_ptr->fru_id,
370303831d35Sstevel 				    fru_ptr->fru_version);
370403831d35Sstevel 			}
370503831d35Sstevel 			fru_ptr = fru_ptr->next;
370603831d35Sstevel 		}
370703831d35Sstevel 	}
370803831d35Sstevel }
370903831d35Sstevel 
371003831d35Sstevel /*
371103831d35Sstevel  * Sends an event when the system controller board I2C errors
371203831d35Sstevel  * exceed the threshold.
371303831d35Sstevel  */
371403831d35Sstevel static void
371503831d35Sstevel scsb_failing_event(scsb_state_t *scsb)
371603831d35Sstevel {
371703831d35Sstevel 	uint32_t scsb_event_code = SCTRL_EVENT_SCB;
371803831d35Sstevel 
371903831d35Sstevel 	add_event_code(scsb, scsb_event_code);
372003831d35Sstevel 	(void) scsb_queue_ops(scsb, QPUT_INT32, 1, &scsb_event_code,
372103831d35Sstevel 	"scsb_intr");
372203831d35Sstevel }
372303831d35Sstevel #endif
372403831d35Sstevel 
372503831d35Sstevel int
372603831d35Sstevel scsb_read_bhealthy(scsb_state_t *scsb)
372703831d35Sstevel {
372803831d35Sstevel 	int		error;
372903831d35Sstevel 	uchar_t		reg;
373003831d35Sstevel 	int		index;
373103831d35Sstevel 
373203831d35Sstevel 	if (scsb_debug & 0x8001) {
373303831d35Sstevel 		cmn_err(CE_NOTE, "scsb_read_bhealthy()");
373403831d35Sstevel 	}
373503831d35Sstevel 	reg = SCSB_REG_ADDR(SCTRL_BHLTHY_BASE);
373603831d35Sstevel 	index = SCSB_REG_INDEX(reg);
373703831d35Sstevel 	error = scsb_rdwr_register(scsb, I2C_WR_RD, reg,
373803831d35Sstevel 	    SCTRL_BHLTHY_NUMREGS, &scsb->scsb_data_reg[index], 1);
373903831d35Sstevel 	return (error);
374003831d35Sstevel }
374103831d35Sstevel 
374203831d35Sstevel /*
374303831d35Sstevel  * Returns the health status of a slot
374403831d35Sstevel  */
374503831d35Sstevel int
374603831d35Sstevel scsb_read_slot_health(scsb_state_t *scsb, int pslotnum)
374703831d35Sstevel {
374803831d35Sstevel 	int slotnum = tonga_psl_to_ssl(scsb, pslotnum);
374903831d35Sstevel 	return (scsb_fru_op(scsb, SLOT, slotnum,
375003831d35Sstevel 	    SCTRL_BHLTHY_BASE, SCSB_FRU_OP_GET_BITVAL));
375103831d35Sstevel }
375203831d35Sstevel 
375303831d35Sstevel /*
375403831d35Sstevel  * DIAGNOSTIC and DEBUG only.
375503831d35Sstevel  * Called from ioctl command (SCSBIOC_BHEALTHY_GET)
375603831d35Sstevel  */
375703831d35Sstevel int
375803831d35Sstevel scsb_bhealthy_slot(scsb_state_t *scsb, scsb_uinfo_t *suip)
375903831d35Sstevel {
376003831d35Sstevel 	int		error = 0;
376103831d35Sstevel 	int		base, code, unit_number;
376203831d35Sstevel 	uchar_t		reg;
376303831d35Sstevel 	int		index;
376403831d35Sstevel 
376503831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN)
376603831d35Sstevel 		return (EAGAIN);
376703831d35Sstevel 
376803831d35Sstevel 	/* operation valid for slots only */
376903831d35Sstevel 	if (suip == NULL || suip->unit_type != SLOT) {
377003831d35Sstevel 		return (EINVAL);
377103831d35Sstevel 	}
377203831d35Sstevel 
377303831d35Sstevel 	if (scsb_debug & 0x8001)
377403831d35Sstevel 		cmn_err(CE_NOTE, "scsb_bhealthy_slot: slot %d",
377503831d35Sstevel 		    suip->unit_number);
377603831d35Sstevel 	if (suip->unit_number > mct_system_info.max_units[SLOT]) {
377703831d35Sstevel 		return (EINVAL);
377803831d35Sstevel 	}
377903831d35Sstevel 	/*
378003831d35Sstevel 	 * Map 1.0 Tonga Slot Number, if necessary
378103831d35Sstevel 	 */
378203831d35Sstevel 	tonga_slotnum_check(scsb, suip);
378303831d35Sstevel 	base = SCTRL_BHLTHY_BASE;
378403831d35Sstevel 	code = FRU_UNIT_TO_EVCODE(suip->unit_type, suip->unit_number);
378503831d35Sstevel 	unit_number = FRU_OFFSET(code, base);
378603831d35Sstevel 	index = FRU_REG_INDEX(code, base);
378703831d35Sstevel 	reg = SCSB_REG_ADDR(index);
378803831d35Sstevel 	index = SCSB_REG_INDEX(reg);		/* shadow index */
378903831d35Sstevel 
379003831d35Sstevel 	if (scsb->scsb_state & SCSB_P10_PROM) {
379103831d35Sstevel 		error = scsb_read_bhealthy(scsb);
379203831d35Sstevel 	}
379303831d35Sstevel 	/* else shadow regs are updated by interrupt handler */
379403831d35Sstevel 	if (error == 0) {
379503831d35Sstevel 		if (scsb->scsb_data_reg[index] & (1 << unit_number))
379603831d35Sstevel 			suip->unit_state = ON;
379703831d35Sstevel 		else
379803831d35Sstevel 			suip->unit_state = OFF;
379903831d35Sstevel 	}
380003831d35Sstevel 	return (error);
380103831d35Sstevel }
380203831d35Sstevel 
380303831d35Sstevel /*
380403831d35Sstevel  * Called from HSC and ioctl command (SCSBIOC_RESET_UNIT)
380503831d35Sstevel  * to reset one specified slot
380603831d35Sstevel  */
380703831d35Sstevel int
380803831d35Sstevel scsb_reset_unit(scsb_state_t *scsb, scsb_uinfo_t *suip)
380903831d35Sstevel {
381003831d35Sstevel 	int		error;
381103831d35Sstevel 	int		unit_number;
381203831d35Sstevel 	uchar_t		reg;
381303831d35Sstevel 	int		index, slotnum, reset_state;
381403831d35Sstevel 
381503831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN)
381603831d35Sstevel 		return (EAGAIN);
381703831d35Sstevel 	if (scsb_debug & 0x8001) {
381803831d35Sstevel 		cmn_err(CE_NOTE, "scsb_reset_slot(%d): slot %d, state %d\n",
381903831d35Sstevel 		    scsb->scsb_instance, suip->unit_number,
382003831d35Sstevel 		    suip->unit_state);
382103831d35Sstevel 	}
382203831d35Sstevel 	if (suip->unit_type != ALARM && !(scsb->scsb_state &
382303831d35Sstevel 	    (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) {
382403831d35Sstevel 		return (EINVAL);
382503831d35Sstevel 	}
382603831d35Sstevel 	if (suip->unit_state != ON && suip->unit_state != OFF) {
382703831d35Sstevel 		return (EINVAL);
382803831d35Sstevel 	}
382903831d35Sstevel 	error = 0;
383003831d35Sstevel 	switch (suip->unit_type) {
383103831d35Sstevel 	case ALARM:
383203831d35Sstevel 	{
383303831d35Sstevel 		int	i, code;
383403831d35Sstevel 		if (suip->unit_number != 1)
383503831d35Sstevel 			return (EINVAL);
383603831d35Sstevel 		code = FRU_UNIT_TO_EVCODE(suip->unit_type, suip->unit_number);
383703831d35Sstevel 		unit_number = FRU_OFFSET(code, SCTRL_RESET_BASE);
383803831d35Sstevel 		i = ALARM_RESET_REG_INDEX(code, SCTRL_RESET_BASE);
383903831d35Sstevel 		reg = SCSB_REG_ADDR(i);
384003831d35Sstevel 		break;
384103831d35Sstevel 	}
384203831d35Sstevel 	case SLOT:
384303831d35Sstevel 		slotnum = suip->unit_number;
384403831d35Sstevel 		reset_state = (suip->unit_state == ON) ? SCSB_RESET_SLOT :
384503831d35Sstevel 		    SCSB_UNRESET_SLOT;
384603831d35Sstevel 		if (scsb->scsb_state & SCSB_IS_TONGA) {
384703831d35Sstevel 			if (slotnum > TG_MAX_SLOTS ||
384803831d35Sstevel 			    slotnum == SC_TG_CPU_SLOT) {
384903831d35Sstevel 				return (EINVAL);
385003831d35Sstevel 			}
385103831d35Sstevel 		} else {
385203831d35Sstevel 			if (slotnum > MC_MAX_SLOTS ||
385303831d35Sstevel 			    slotnum == SC_MC_CPU_SLOT ||
385403831d35Sstevel 			    (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
385503831d35Sstevel 			    slotnum == SC_MC_CTC_SLOT)) {
385603831d35Sstevel 				return (EINVAL);
385703831d35Sstevel 			}
385803831d35Sstevel 		}
385903831d35Sstevel 		return (scsb_reset_slot(scsb, slotnum, reset_state));
386003831d35Sstevel 	default:
386103831d35Sstevel 		return (EINVAL);
386203831d35Sstevel 	}
386303831d35Sstevel 	index = SCSB_REG_INDEX(reg);
386403831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
386503831d35Sstevel 	if (suip->unit_state == ON)
386603831d35Sstevel 		scsb->scsb_data_reg[index] |= (1 << unit_number);
386703831d35Sstevel 	else /* OFF */
386803831d35Sstevel 		scsb->scsb_data_reg[index] &= ~(1 << unit_number);
386903831d35Sstevel 	if ((error = scsb_rdwr_register(scsb, I2C_WR, reg, 1,
387003831d35Sstevel 	    &scsb->scsb_data_reg[index], 0)) != 0) {
387103831d35Sstevel 		if (scsb_debug & 0x8002)
387203831d35Sstevel 			cmn_err(CE_WARN,
387303831d35Sstevel 			    "scsb_leds: write failure to 0x%x", reg);
387403831d35Sstevel 		return (error);
387503831d35Sstevel 	}
387603831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
387703831d35Sstevel 	return (error);
387803831d35Sstevel }
387903831d35Sstevel 
388003831d35Sstevel /*
388103831d35Sstevel  * Diagnostic and DEBUG
388203831d35Sstevel  * This is a helper function for the helper ioctl to pretend that
388303831d35Sstevel  * scsb h/w is doing its job!!!
388403831d35Sstevel  */
388503831d35Sstevel int
388603831d35Sstevel scsb_slot_occupancy(scsb_state_t *scsb, scsb_uinfo_t *suip)
388703831d35Sstevel {
388803831d35Sstevel 	int		error;
388903831d35Sstevel 	int		saved_unit_number;
389003831d35Sstevel 
389103831d35Sstevel 	if (!(scsb->scsb_state & (SCSB_DEBUG_MODE | SCSB_DIAGS_MODE)))
389203831d35Sstevel 		return (EACCES);
389303831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN) {
389403831d35Sstevel 		return (EAGAIN);
389503831d35Sstevel 	}
389603831d35Sstevel 	error = 0;
389703831d35Sstevel 	switch (suip->unit_type) {
389803831d35Sstevel 	case ALARM:
389903831d35Sstevel 		if (suip->unit_number !=
390003831d35Sstevel 		    (mct_system_info.fru_info_list[ALARM])->fru_unit) {
390103831d35Sstevel 			return (EINVAL);
390203831d35Sstevel 		}
390303831d35Sstevel 		break;
390403831d35Sstevel 
390503831d35Sstevel 	case SLOT:
390603831d35Sstevel 		/*
390703831d35Sstevel 		 * All slots are acceptable, except slots 11 & 12.
390803831d35Sstevel 		 */
390903831d35Sstevel 		if (suip->unit_number < 1 || suip->unit_number >
391003831d35Sstevel 		    mct_system_info.max_units[ALARM]) {
391103831d35Sstevel 			error = EINVAL;
391203831d35Sstevel 			break;
391303831d35Sstevel 		}
391403831d35Sstevel 		/* Map 1.0 Tonga Slot Numbers if necessary */
391503831d35Sstevel 		saved_unit_number = suip->unit_number;
391603831d35Sstevel 		tonga_slotnum_check(scsb, suip);
391703831d35Sstevel 		break;
391803831d35Sstevel 
391903831d35Sstevel 	default:
392003831d35Sstevel 		error = EINVAL;
392103831d35Sstevel 		break;
392203831d35Sstevel 	}
392303831d35Sstevel 
392403831d35Sstevel 	if (error)
392503831d35Sstevel 		return (error);
392603831d35Sstevel 	if (suip->unit_state == ON) {
392703831d35Sstevel 		if (hsc_slot_occupancy(saved_unit_number, B_TRUE, 0, B_TRUE)
392803831d35Sstevel 		    != 0)
392903831d35Sstevel 			error = EFAULT;
393003831d35Sstevel 	} else {
393103831d35Sstevel 		if (hsc_slot_occupancy(saved_unit_number, B_FALSE, 0, B_FALSE)
393203831d35Sstevel 		    != 0)
393303831d35Sstevel 			error = EFAULT;
393403831d35Sstevel 	}
393503831d35Sstevel 
393603831d35Sstevel 	return (error);
393703831d35Sstevel }
393803831d35Sstevel 
393903831d35Sstevel static int
394003831d35Sstevel scsb_clear_intptrs(scsb_state_t *scsb)
394103831d35Sstevel {
394203831d35Sstevel 	int		i, error;
394303831d35Sstevel 	uchar_t		wbuf[SCTRL_MAX_GROUP_NUMREGS];
394403831d35Sstevel 	error = 0;
394503831d35Sstevel 	for (i = 1; i <= SCTRL_INTR_NUMREGS; ++i) {
394603831d35Sstevel 		wbuf[i] = 0xff;
394703831d35Sstevel 	}
394803831d35Sstevel 	if (error = scsb_rdwr_register(scsb, I2C_WR,
394903831d35Sstevel 	    SCSB_REG_ADDR(SCTRL_INTSRC_BASE),
395003831d35Sstevel 	    SCTRL_INTR_NUMREGS, wbuf, 1)) {
395103831d35Sstevel 		if (scsb_debug & 0x0402)
395203831d35Sstevel 			cmn_err(CE_NOTE, "scsb_clear_intptrs(): "
395303831d35Sstevel 			    "write to 0x%x failed",
395403831d35Sstevel 			    SCSB_REG_ADDR(SCTRL_INTSRC_BASE));
395503831d35Sstevel 	}
395603831d35Sstevel 	return (error);
395703831d35Sstevel }
395803831d35Sstevel 
395903831d35Sstevel static int
396003831d35Sstevel scsb_setall_intmasks(scsb_state_t *scsb)
396103831d35Sstevel {
396203831d35Sstevel 	int		error;
396303831d35Sstevel 	uchar_t		reg, wdata, rmask;
396403831d35Sstevel 	int		i;
396503831d35Sstevel 
396603831d35Sstevel 	/*
396703831d35Sstevel 	 * write loop for Interrupt Mask registers
396803831d35Sstevel 	 */
396903831d35Sstevel 	if (scsb_debug & 0x0401)
397003831d35Sstevel 		cmn_err(CE_NOTE, "setall_intmasks()");
397103831d35Sstevel 	error = 0;
397203831d35Sstevel 	rmask = 0;
397303831d35Sstevel 	wdata = 0xff;
397403831d35Sstevel 	reg = SCSB_REG_ADDR(SCTRL_INTMASK_BASE);
397503831d35Sstevel 	for (i = 0; i < SCTRL_MASK_NUMREGS; ++i, ++reg) {
397603831d35Sstevel 		if (error = scsb_write_mask(scsb, reg, rmask, wdata, 0)) {
397703831d35Sstevel 			if (scsb_debug & 0x0402)
397803831d35Sstevel 				cmn_err(CE_NOTE, "scsb_setall_intmasks: "
397903831d35Sstevel 				    "write to 0x%x failed: %d", reg, error);
398003831d35Sstevel 			error = EIO;
398103831d35Sstevel 			break;
398203831d35Sstevel 		}
398303831d35Sstevel 	}
398403831d35Sstevel 	return (error);
398503831d35Sstevel }
398603831d35Sstevel 
398703831d35Sstevel 
398803831d35Sstevel /*
398903831d35Sstevel  * Clear Interrupt masks based on the FRUs that could be installed
399003831d35Sstevel  * for this particular topology, determined by the MidPlane ID
399103831d35Sstevel  * from SCTRL_SYSCFG registers
399203831d35Sstevel  *	case SCTRL_MPID_HALF:
399303831d35Sstevel  *		1 CPU, 1 AlarmCard, 1 SCB/SSB, 2 PS, 3 FAN, 3 SCSI, 8 Slots
399403831d35Sstevel  *	case SCTRL_MPID_QUARTER:
399503831d35Sstevel  *		1 CPU, 1 AlarmCard, 1 SCB/SSB, 1 PS, 2 FAN, 1 SCSI, 4 Slots
399603831d35Sstevel  *	case SCTRL_MPID_QUARTER_NODSK:
399703831d35Sstevel  *		1 CPU, 1 AlarmCard, 1 SCB/SSB, 1 PS, 2 FAN, 0 SCSI, 4 Slots
399803831d35Sstevel  */
399903831d35Sstevel static int
400003831d35Sstevel scsb_clear_intmasks(scsb_state_t *scsb)
400103831d35Sstevel {
400203831d35Sstevel 	int		error;
400303831d35Sstevel 	uchar_t		msk_reg, reg, wdata, rmask;
400403831d35Sstevel 	uchar_t		mask_data[SCTRL_MAX_GROUP_NUMREGS];
400503831d35Sstevel 	int		tmp, idx, code, unit, offset, mbid;
400603831d35Sstevel 	scsb_utype_t    fru_type;
400703831d35Sstevel 	fru_info_t	*fru_ptr;
400803831d35Sstevel 
400903831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN &&
401003831d35Sstevel 	    !(scsb->scsb_state & SCSB_IN_INTR)) {
401103831d35Sstevel 		return (EAGAIN);
401203831d35Sstevel 	}
401303831d35Sstevel 	error = 0;
401403831d35Sstevel 	for (tmp = 0; tmp < SCTRL_MASK_NUMREGS; ++tmp)
401503831d35Sstevel 		mask_data[tmp] = 0;
401603831d35Sstevel 	msk_reg = SCSB_REG_ADDR(SCTRL_INTMASK_BASE);
401703831d35Sstevel 	mbid    = SCSB_REG_INDEX(msk_reg); /* the Mask Base Index Delta */
401803831d35Sstevel 	if (scsb_debug & 0x0400) {
401903831d35Sstevel 		cmn_err(CE_NOTE, "clear_intmasks: msk_reg=0x%x; mbid=%d",
402003831d35Sstevel 		    msk_reg, mbid);
402103831d35Sstevel 	}
402203831d35Sstevel 	for (fru_type = 0; fru_type < SCSB_UNIT_TYPES; ++fru_type) {
402303831d35Sstevel 		if (fru_type == SCB)
402403831d35Sstevel 			continue;	/* handle below, 2 reg offsets */
402503831d35Sstevel 		fru_ptr = mct_system_info.fru_info_list[fru_type];
402603831d35Sstevel 		for (; fru_ptr != NULL; fru_ptr = fru_ptr->next) {
402703831d35Sstevel 			unit = fru_ptr->fru_unit;
402803831d35Sstevel 			code   = FRU_UNIT_TO_EVCODE(fru_type, unit);
402903831d35Sstevel 			offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
403003831d35Sstevel 			reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE);
403103831d35Sstevel 			idx    = SCSB_REG_INDEX(reg);
403203831d35Sstevel 			tmp = idx - mbid;
403303831d35Sstevel 			mask_data[tmp] |= (1 << offset);
403403831d35Sstevel 			if (scsb_debug & 0x0400)
403503831d35Sstevel 				cmn_err(CE_NOTE,
403603831d35Sstevel 				"clear_intmasks:%d:%d: PRES mask[%d]:0x%x",
403703831d35Sstevel 				    fru_type, unit, tmp, mask_data[tmp]);
403803831d35Sstevel 			if ((fru_type == SLOT) && (IS_SCB_P15)) {
403903831d35Sstevel 				/*
404003831d35Sstevel 				 * Unmask the corresponding Slot HLTHY mask
404103831d35Sstevel 				 * Use Slot bit and register offsets,
404203831d35Sstevel 				 *  but with SCTRL_INTMASK_HLTHY_BASE
404303831d35Sstevel 				 */
404403831d35Sstevel 				reg = FRU_REG_ADDR(code,
404503831d35Sstevel 				    SCTRL_INTMASK_HLTHY_BASE);
404603831d35Sstevel 				idx = SCSB_REG_INDEX(reg);
404703831d35Sstevel 				tmp = idx - mbid;
404803831d35Sstevel 				mask_data[tmp] |= (1 << offset);
404903831d35Sstevel 				if (scsb_debug & 0x0400) {
405003831d35Sstevel 					cmn_err(CE_NOTE,
405103831d35Sstevel 				"clear_intmasks:Slot:%d: HLTHY mask[%d]:0x%x"
405203831d35Sstevel 				"; reg=0x%x, idx=%d, mbid=%d",
405303831d35Sstevel 					    unit, tmp, mask_data[tmp],
405403831d35Sstevel 					    reg, idx, mbid);
405503831d35Sstevel 				}
405603831d35Sstevel 			}
405703831d35Sstevel 		}
405803831d35Sstevel 	}
405903831d35Sstevel 	/*
406003831d35Sstevel 	 * Now unmask these non-fru interrupt events
406103831d35Sstevel 	 *	SCTRL_EVENT_PWRDWN	(almost normal)
406203831d35Sstevel 	 *	SCTRL_EVENT_REPLACE	(not used)
406303831d35Sstevel 	 *	SCTRL_EVENT_ALARM_INT	(not working in P0.6/P1.0)
406403831d35Sstevel 	 *	SCTRL_EVENT_SCB		(SCB 1.5 ONLY; plus SCB_INT_OFFSET)
406503831d35Sstevel 	 */
406603831d35Sstevel 	code   = SCTRL_EVENT_PWRDWN;
406703831d35Sstevel 	offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
406803831d35Sstevel 	reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE);
406903831d35Sstevel 	idx    = SCSB_REG_INDEX(reg);
407003831d35Sstevel 	tmp = idx - mbid;
407103831d35Sstevel 	mask_data[tmp] |= (1 << offset);
407203831d35Sstevel 	if (IS_SCB_P15) {
407303831d35Sstevel 		code   = SCTRL_EVENT_SCB;
407403831d35Sstevel 		offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
407503831d35Sstevel 		reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE) + SCB_INT_OFFSET;
407603831d35Sstevel 		idx    = SCSB_REG_INDEX(reg);
407703831d35Sstevel 		tmp = idx - mbid;
407803831d35Sstevel 		mask_data[tmp] |= (1 << offset);
407903831d35Sstevel 		code   = SCTRL_EVENT_ALARM_INT;
408003831d35Sstevel 		offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
408103831d35Sstevel 		reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE);
408203831d35Sstevel 		idx    = SCSB_REG_INDEX(reg);
408303831d35Sstevel 		tmp = idx - mbid;
408403831d35Sstevel 		mask_data[tmp] |= (1 << offset);
408503831d35Sstevel 	}
408603831d35Sstevel 	for (tmp = 0; tmp < SCTRL_MASK_NUMREGS; ++tmp) {
408703831d35Sstevel 		rmask = 0;
408803831d35Sstevel 		wdata = mask_data[tmp];
408903831d35Sstevel 		if (scsb_debug & 0x0400)
409003831d35Sstevel 			cmn_err(CE_NOTE, "clear_intmasks:0x%x: ~(0x%x),0x%x",
409103831d35Sstevel 			    msk_reg, (~wdata) & 0xff, wdata);
409203831d35Sstevel 		mutex_enter(&scsb->scsb_mutex);
409303831d35Sstevel 		if (error = scsb_write_mask(scsb, msk_reg, rmask,
409403831d35Sstevel 		    (~wdata) & 0xff, wdata)) {
409503831d35Sstevel 			mutex_exit(&scsb->scsb_mutex);
409603831d35Sstevel 			if (scsb_debug & 0x0402)
409703831d35Sstevel 				cmn_err(CE_NOTE, "scsb_clear_intmasks: "
409803831d35Sstevel 				    "write to 0x%x failed: %d",
409903831d35Sstevel 				    msk_reg, error);
410003831d35Sstevel 			error = EIO;
410103831d35Sstevel 			break;
410203831d35Sstevel 		}
410303831d35Sstevel 		mutex_exit(&scsb->scsb_mutex);
410403831d35Sstevel 		++msk_reg;
410503831d35Sstevel 	}
410603831d35Sstevel 	return (error);
410703831d35Sstevel }
410803831d35Sstevel 
410903831d35Sstevel static int
411003831d35Sstevel scsb_get_status(scsb_state_t *scsb, scsb_status_t *smp)
411103831d35Sstevel {
411203831d35Sstevel 	register int 	i;
411303831d35Sstevel 
411403831d35Sstevel 	if (smp == NULL) {
411503831d35Sstevel 		return (EFAULT);
411603831d35Sstevel 	}
411703831d35Sstevel 	if (scsb_debug & 0x40000000 &&
411803831d35Sstevel 	    (scsb->scsb_state & SCSB_DEBUG_MODE ||
411903831d35Sstevel 	    scsb->scsb_state & SCSB_DIAGS_MODE)) {
412003831d35Sstevel 		if (scsb->scsb_state & SCSB_FROZEN) {
412103831d35Sstevel 			return (EAGAIN);
412203831d35Sstevel 		}
412303831d35Sstevel 		mutex_enter(&scsb->scsb_mutex);
412403831d35Sstevel 		if (scsb_debug & 0x80000000) {
412503831d35Sstevel 			if ((i = scsb_readall_regs(scsb)) != 0 &&
412603831d35Sstevel 			    scsb->scsb_state & SCSB_DEBUG_MODE)
412703831d35Sstevel 				cmn_err(CE_WARN, "scsb_get_status: "
412803831d35Sstevel 				    "scsb_readall_regs() FAILED");
412903831d35Sstevel 		} else {
413003831d35Sstevel 			if ((i = scsb_check_config_status(scsb)) == 0) {
413103831d35Sstevel 				i = scsb_set_scfg_pres_leds(scsb, NULL);
413203831d35Sstevel 			}
413303831d35Sstevel 		}
413403831d35Sstevel 		mutex_exit(&scsb->scsb_mutex);
413503831d35Sstevel 		if (i) {
413603831d35Sstevel 			cmn_err(CE_WARN,
413703831d35Sstevel 			    "scsb_get_status: FAILED Presence LEDs update");
413803831d35Sstevel 			return (EIO);
413903831d35Sstevel 		}
414003831d35Sstevel 	}
414103831d35Sstevel 	for (i = 0; i < SCSB_DATA_REGISTERS; ++i)
414203831d35Sstevel 		smp->scsb_reg[i] = scsb->scsb_data_reg[i];
414303831d35Sstevel 	return (0);
414403831d35Sstevel }
414503831d35Sstevel 
414603831d35Sstevel /*
414703831d35Sstevel  * scsb_freeze_check:
414803831d35Sstevel  *	Turn all the leds off on the system monitor card, without changing
414903831d35Sstevel  *	the state of what we have for scsb. This routine is called only when
415003831d35Sstevel  *	replacing system monitor card, so the state of the card leds could be
415103831d35Sstevel  *	restored, using scsb_restore().
415203831d35Sstevel  *	Also, set state to SCSB_FROZEN which denies access to scsb while in
415303831d35Sstevel  *	freeze mode.
415403831d35Sstevel  */
415503831d35Sstevel static char  *BAD_BOARD_MSG =
415603831d35Sstevel 	"SCSB: Should NOT remove SCB(%d) while cPCI Slot %d is "
415703831d35Sstevel 	"in RESET with a possible bad board.";
415803831d35Sstevel static int	slots_in_reset[SCTRL_MAX_GROUP_NUMREGS];
415903831d35Sstevel 
416003831d35Sstevel static void
416103831d35Sstevel scsb_freeze_check(scsb_state_t *scsb)
416203831d35Sstevel {
416303831d35Sstevel 	register int	i;
416403831d35Sstevel 	int		offset;
416503831d35Sstevel 	int		unit, slotnum;
416603831d35Sstevel 	int		index;
416703831d35Sstevel 	fru_info_t	*fru_ptr;
416803831d35Sstevel 	uint32_t	code;
416903831d35Sstevel 	uchar_t		reg;
417003831d35Sstevel 
417103831d35Sstevel 	if (scsb_debug & 0x20001)
417203831d35Sstevel 		cmn_err(CE_NOTE, "scsb_freeze_check(%d):", scsb->scsb_instance);
417303831d35Sstevel 
417403831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN) {
417503831d35Sstevel 		return;
417603831d35Sstevel 	}
417703831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
417803831d35Sstevel 	for (i = 0; i < SCTRL_MAX_GROUP_NUMREGS; ++i)
417903831d35Sstevel 		slots_in_reset[i] = 0;
418003831d35Sstevel 	/*
418103831d35Sstevel 	 * We allow the SCB to be removed only if none of
418203831d35Sstevel 	 * the cPCI resets are asserted for occupied slots.
418303831d35Sstevel 	 * There shouldn't be a bad board plugged in the system
418403831d35Sstevel 	 * while swapping the SCB.
418503831d35Sstevel 	 */
418603831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[SLOT];
418703831d35Sstevel 	for (unit = 1; unit <= mct_system_info.max_units[SLOT]; ++unit) {
418803831d35Sstevel 		if (IS_SCB_P15) {
418903831d35Sstevel 			slotnum = tonga_psl_to_ssl(scsb, unit);
419003831d35Sstevel 		} else {
419103831d35Sstevel 			slotnum = unit;
419203831d35Sstevel 		}
419303831d35Sstevel 		code = FRU_UNIT_TO_EVCODE(SLOT, slotnum);
419403831d35Sstevel 		offset = FRU_OFFSET(code, SCTRL_RESET_BASE);
419503831d35Sstevel 		reg = FRU_REG_ADDR(code, SCTRL_RESET_BASE);
419603831d35Sstevel 		index = SCSB_REG_INDEX(reg);
419703831d35Sstevel 		if (scsb->scsb_data_reg[index] & (1 << offset)) {
419803831d35Sstevel 			if (fru_ptr[unit - 1].fru_status == FRU_PRESENT) {
419903831d35Sstevel 				slots_in_reset[unit - 1] = unit;
420003831d35Sstevel 				cmn_err(CE_NOTE, BAD_BOARD_MSG,
420103831d35Sstevel 				    scsb->scsb_instance, unit);
420203831d35Sstevel 			}
420303831d35Sstevel 		}
420403831d35Sstevel 	}
420503831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
420603831d35Sstevel }
420703831d35Sstevel 
420803831d35Sstevel static void
420903831d35Sstevel scsb_freeze(scsb_state_t *scsb)
421003831d35Sstevel {
421103831d35Sstevel 	uint32_t	code;
421203831d35Sstevel 	if (scsb_debug & 0x00020002) {
421303831d35Sstevel 		cmn_err(CE_WARN, "scsb_freeze: SCB%d possibly removed",
421403831d35Sstevel 		    scsb->scsb_instance);
421503831d35Sstevel 	}
421603831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN)
421703831d35Sstevel 		return;
421803831d35Sstevel 	scsb->scsb_state |= SCSB_FROZEN;
421903831d35Sstevel 	scsb->scsb_state &= ~SCSB_SCB_PRESENT;
4220*07d06da5SSurya Prakki 	(void) scsb_hsc_freeze(scsb->scsb_dev);
422103831d35Sstevel 	/*
422203831d35Sstevel 	 * Send the EVENT_SCB since there is evidence that the
422303831d35Sstevel 	 * System Controller Board has been removed.
422403831d35Sstevel 	 */
422503831d35Sstevel 	code = SCTRL_EVENT_SCB;
422603831d35Sstevel 	if (!(scsb->scsb_state & SCSB_IN_INTR))
422703831d35Sstevel 		scsb_event_code = code;
422803831d35Sstevel 	check_fru_info(scsb, code);
422903831d35Sstevel 	add_event_code(scsb, code);
423003831d35Sstevel 	(void) scsb_queue_ops(scsb, QPUT_INT32, 1, &code, "scsb_freeze");
423103831d35Sstevel }
423203831d35Sstevel 
423303831d35Sstevel /*
423403831d35Sstevel  * scsb_restore will only be called from the interrupt handler context on
423503831d35Sstevel  * INIT_SCB interrupt for newly inserted SCB.
423603831d35Sstevel  * Called with mutex held.
423703831d35Sstevel  */
423803831d35Sstevel static void
423903831d35Sstevel scsb_restore(scsb_state_t *scsb)
424003831d35Sstevel {
424103831d35Sstevel 	if (scsb_debug & 0x20001)
424203831d35Sstevel 		cmn_err(CE_NOTE, "scsb_restore(%d):", scsb->scsb_instance);
424303831d35Sstevel 
424403831d35Sstevel 	if (initialize_scb(scsb) != DDI_SUCCESS) {
424503831d35Sstevel 		if (scsb_debug & 0x00020002) {
424603831d35Sstevel 			cmn_err(CE_WARN, "scsb_restore: INIT Failed");
424703831d35Sstevel 		return;
424803831d35Sstevel 		}
424903831d35Sstevel 	}
425003831d35Sstevel 	/* 9. Clear all Interrupts */
425103831d35Sstevel 	if (scsb_clear_intmasks(scsb)) {
425203831d35Sstevel 		cmn_err(CE_WARN,
425303831d35Sstevel 		    "scsb%d: I2C TRANSFER Failed", scsb->scsb_instance);
425403831d35Sstevel 		if (scsb_debug & 0x00020002) {
425503831d35Sstevel 			cmn_err(CE_WARN, "scsb_restore: clear_intmasks Failed");
425603831d35Sstevel 		}
425703831d35Sstevel 		return;
425803831d35Sstevel 	}
425903831d35Sstevel 
426003831d35Sstevel 	/* 10. */
426103831d35Sstevel 	/* Check if Alarm Card present at boot and set flags */
426203831d35Sstevel 	if (scsb_fru_op(scsb, ALARM, 1, SCTRL_SYSCFG_BASE,
426303831d35Sstevel 	    SCSB_FRU_OP_GET_BITVAL))
426403831d35Sstevel 		scsb->scsb_hsc_state |= SCSB_ALARM_CARD_PRES;
426503831d35Sstevel 	else
426603831d35Sstevel 		scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_PRES;
426703831d35Sstevel 
426803831d35Sstevel 	scsb->scsb_state &= ~SCSB_FROZEN;
426903831d35Sstevel 	(void) scsb_hsc_restore(scsb->scsb_dev);
427003831d35Sstevel }
427103831d35Sstevel 
427203831d35Sstevel /*
427303831d35Sstevel  * Given an Event Code,
427403831d35Sstevel  * Return:
427503831d35Sstevel  *	FRU type    in LSByte
427603831d35Sstevel  *	unit number in MSByte
427703831d35Sstevel  */
427803831d35Sstevel uint16_t
427903831d35Sstevel event_to_type(uint32_t evcode)
428003831d35Sstevel {
428103831d35Sstevel 	int		i, li, unit;
428203831d35Sstevel 	uint32_t	ec;
428303831d35Sstevel 	uint16_t	ret;
428403831d35Sstevel 	for (i = li = 0; i < SCSB_UNIT_TYPES; ++i) {
428503831d35Sstevel 		if (evcode == type_to_code1[i]) {
428603831d35Sstevel 			ret = (uint16_t)(0x0100 | i);
428703831d35Sstevel 			return (ret);
428803831d35Sstevel 		}
428903831d35Sstevel 		if (evcode < type_to_code1[i]) {
429003831d35Sstevel 			unit = 1;
429103831d35Sstevel 			ec = type_to_code1[li];
429203831d35Sstevel 			while (ec < evcode)
429303831d35Sstevel 				ec = ec << 1, ++unit;
429403831d35Sstevel 			ret = (unit << 8) | li;
429503831d35Sstevel 			return (ret);
429603831d35Sstevel 		}
429703831d35Sstevel 		li = i;
429803831d35Sstevel 	}
429903831d35Sstevel 	return ((uint16_t)0xffff);
430003831d35Sstevel }
430103831d35Sstevel 
430203831d35Sstevel /*
430303831d35Sstevel  * scsb interrupt handler for (MC) PSM_INT vector
430403831d35Sstevel  * P0.6: HW shipped to beta customers
430503831d35Sstevel  *	1. did not have Slot Occupant Presense support
430603831d35Sstevel  *	2. I2C interrupt-map properties not yet tested, using polling daemon
430703831d35Sstevel  *	3. Polling detects each event reliably twice.
430803831d35Sstevel  *	   clr_bits# are used to keep track of events to be ignored 2nd time
430903831d35Sstevel  *
431003831d35Sstevel  * retval flags allow all events to be checked, and still returning the
431103831d35Sstevel  * correct DDI value.
431203831d35Sstevel  *
431303831d35Sstevel  */
431403831d35Sstevel #define	SCSB_INTR_CLAIMED	1
431503831d35Sstevel #define	SCSB_INTR_UNCLAIMED	2
431603831d35Sstevel #define	SCSB_INTR_EVENT		4
431703831d35Sstevel 
431803831d35Sstevel /*
431903831d35Sstevel  * Does preprocessing of the interrupt. The only thing this
432003831d35Sstevel  * needs to do is to ask scsb to release the interrupt line.
432103831d35Sstevel  * and then schedule delayed actual processing using timeout()
432203831d35Sstevel  */
432303831d35Sstevel uint_t
432403831d35Sstevel scsb_intr_preprocess(caddr_t arg)
432503831d35Sstevel {
432603831d35Sstevel 	scsb_state_t	*scsb = (scsb_state_t *)arg;
432703831d35Sstevel 
432803831d35Sstevel 	scb_pre_s = gethrtime();
432903831d35Sstevel 
433003831d35Sstevel 	/*
433103831d35Sstevel 	 * If SCSB_IN_INTR is already set in scsb_state,
433203831d35Sstevel 	 * it means we are being interrupted by someone else. This can
433303831d35Sstevel 	 * happen only if the interrupt does not belong to scsb, and some
433403831d35Sstevel 	 * other device, e.g. a FAN or PS is interrupting. So, we
433503831d35Sstevel 	 * cancel the previous timeout().
433603831d35Sstevel 	 */
433703831d35Sstevel 
433803831d35Sstevel 	if (scsb->scsb_state & SCSB_IN_INTR) {
4339*07d06da5SSurya Prakki 		(void) untimeout(scsb_intr_tid);
4340*07d06da5SSurya Prakki 		(void) scsb_invoke_intr_chain();
4341*07d06da5SSurya Prakki 		(void) scsb_toggle_psmint(scsb, 1);
434203831d35Sstevel 		scsb->scsb_state &= ~SCSB_IN_INTR;
434303831d35Sstevel 		goto intr_end;
434403831d35Sstevel 	}
434503831d35Sstevel 	scsb->scsb_state |= SCSB_IN_INTR;
434603831d35Sstevel 
434703831d35Sstevel 	/*
434803831d35Sstevel 	 * Stop scsb from interrupting first.
434903831d35Sstevel 	 */
435003831d35Sstevel 	if (scsb_quiesce_psmint(scsb) != DDI_SUCCESS) {
435103831d35Sstevel 		goto intr_end;
435203831d35Sstevel 	}
435303831d35Sstevel 
435403831d35Sstevel 	/*
435503831d35Sstevel 	 * Schedule a timeout to actually process the
435603831d35Sstevel 	 * interrupt.
435703831d35Sstevel 	 */
435803831d35Sstevel 	scsb_intr_tid = timeout((void (*)(void *))scsb_intr, arg,
435903831d35Sstevel 	    drv_usectohz(1000));
436003831d35Sstevel 
436103831d35Sstevel intr_end:
436203831d35Sstevel 
436303831d35Sstevel 	scb_pre_e = gethrtime();
436403831d35Sstevel 	return (DDI_INTR_CLAIMED);
436503831d35Sstevel }
436603831d35Sstevel 
436703831d35Sstevel static void scsb_healthy_intr(scsb_state_t *scsb, int pslotnum);
436803831d35Sstevel void
436903831d35Sstevel scsb_intr(caddr_t arg)
437003831d35Sstevel {
437103831d35Sstevel 	scsb_state_t	*scsb = (scsb_state_t *)arg;
437203831d35Sstevel 	int		i, idx, offset, unit, numregs, error;
437303831d35Sstevel 	int		intr_idx, index, offset_base, retval, slotnum, val;
437403831d35Sstevel 	uint32_t	code;
437503831d35Sstevel 	uchar_t		intr_reg, tmp_reg, intr_addr, clr_bits = 0;
437603831d35Sstevel 	uchar_t		ac_slot = B_FALSE;
437703831d35Sstevel 	uchar_t		*int_masks;
437803831d35Sstevel 	uchar_t		cstatus_regs[SCTRL_MAX_GROUP_NUMREGS];
437903831d35Sstevel 	scsb_utype_t	fru_type;
438003831d35Sstevel 	fru_info_t	*fru_ptr;
438103831d35Sstevel 	int		ac_present;
438203831d35Sstevel 
438303831d35Sstevel 	/*
438403831d35Sstevel 	 * Avoid mayhem, make sure we have only one timeout thread running.
438503831d35Sstevel 	 */
438603831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
438703831d35Sstevel 	while (scsb_in_postintr)
438803831d35Sstevel 		cv_wait(&scsb->scsb_cv, &scsb->scsb_mutex);
438903831d35Sstevel 	scsb_in_postintr = 1;
439003831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
439103831d35Sstevel 
439203831d35Sstevel 	scb_post_s = gethrtime();
439303831d35Sstevel 	if (scsb_debug & 0x00002000)
439403831d35Sstevel 		cmn_err(CE_NOTE, "scsb_intr(%d)", scsb->scsb_instance);
439503831d35Sstevel 	retval = 0;
439603831d35Sstevel 	tmp_reg = 0;
439703831d35Sstevel 	/*
439803831d35Sstevel 	 * XXX: Problem, when we want to support swapping between SCB
439903831d35Sstevel 	 * versions, then we need to check the SCB PROM ID (CF) register here
440003831d35Sstevel 	 * before assuming the same SCB version was re-inserted.
440103831d35Sstevel 	 * We will have to duplicate some of the scb_initialization()
440203831d35Sstevel 	 * code to set the scsb_state PROM ID bits and to set up the
440303831d35Sstevel 	 * register table pointers.
440403831d35Sstevel 	 *
440503831d35Sstevel 	 * Only if NOT SSB_PRESENT, check the SCB PROM ID
440603831d35Sstevel 	 */
440703831d35Sstevel 	if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
440803831d35Sstevel 		if (scb_check_version(scsb) != DDI_SUCCESS) {
440903831d35Sstevel #ifdef DEBUG
441003831d35Sstevel 			if (scsb->scsb_state & SCSB_SSB_PRESENT &&
441103831d35Sstevel 			    scsb->scsb_i2c_errcnt > scsb_err_threshold)
441203831d35Sstevel 				scsb_failing_event(scsb);
441303831d35Sstevel #endif
441403831d35Sstevel 			goto intr_error;
441503831d35Sstevel 		}
441603831d35Sstevel 	}
441703831d35Sstevel 	if (IS_SCB_P15) {
441803831d35Sstevel 		int_masks = scb_15_int_masks;
441903831d35Sstevel 	} else {
442003831d35Sstevel 		int_masks = scb_10_int_masks;
442103831d35Sstevel 	}
442203831d35Sstevel 	/*
442303831d35Sstevel 	 * Now check the INTSRC registers for set bits.
442403831d35Sstevel 	 * Do a quick check by OR'ing INTSRC registers together as we copy
442503831d35Sstevel 	 * them from the transfer buffer. For P1.0 or earlier we had already
442603831d35Sstevel 	 * read the interrupt source registers and wrote them back to stop
442703831d35Sstevel 	 * interrupt. So we need to do this step only for P1.5 or later.
442803831d35Sstevel 	 * We already read INTSRC6 to take care of SCB insertion case, so
442903831d35Sstevel 	 * do not read INTSRC6 again.
443003831d35Sstevel 	 */
443103831d35Sstevel 
443203831d35Sstevel 	if (IS_SCB_P15) {
443303831d35Sstevel 		intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
443403831d35Sstevel 		/* read the interrupt register from scsb */
443503831d35Sstevel 		if (scsb_rdwr_register(scsb, I2C_WR_RD, intr_addr,
443603831d35Sstevel 		    SCTRL_INTR_NUMREGS - 1, scb_intr_regs, 1)) {
443703831d35Sstevel 			cmn_err(CE_WARN, "scsb_intr: "
443803831d35Sstevel 			    " Failed read of interrupt registers.");
443903831d35Sstevel #ifdef DEBUG
444003831d35Sstevel 			if (scsb->scsb_state & SCSB_SSB_PRESENT &&
444103831d35Sstevel 			    scsb->scsb_i2c_errcnt > scsb_err_threshold)
444203831d35Sstevel 				scsb_failing_event(scsb);
444303831d35Sstevel #endif
444403831d35Sstevel 			goto intr_error;
444503831d35Sstevel 		}
444603831d35Sstevel 	}
444703831d35Sstevel 
444803831d35Sstevel 	/*
444903831d35Sstevel 	 * We have seen that an interrupt source bit can be set
445003831d35Sstevel 	 * even though the corresponding interrupt mask bit
445103831d35Sstevel 	 * has been set to mask the interrupt. So we must
445203831d35Sstevel 	 * clear all bits set in the interrupt source register.
445303831d35Sstevel 	 */
445403831d35Sstevel 	for (i = 0; i < SCTRL_INTR_NUMREGS; ++i) {
445503831d35Sstevel 		retval |= scb_intr_regs[i];		/* Quick INTSRC check */
445603831d35Sstevel #ifdef DEBUG
445703831d35Sstevel 		if (scsb_debug & 0x08000000) {
445803831d35Sstevel 			if (tmp_reg || scb_intr_regs[i]) {
445903831d35Sstevel 				cmn_err(CE_NOTE, "scsb_intr: INTSRC%d=0x%x",
446003831d35Sstevel 				    i + 1, scb_intr_regs[i]);
446103831d35Sstevel 				++tmp_reg;
446203831d35Sstevel 			}
446303831d35Sstevel 		}
446403831d35Sstevel #endif
446503831d35Sstevel 	}
446603831d35Sstevel 	/*
446703831d35Sstevel 	 * Any bits from quick check? If this is not our interrupt,
446803831d35Sstevel 	 * something is wrong. FAN/PS interrupts are supposed to be
446903831d35Sstevel 	 * blocked, but we can not be sure. So, go ahead and call the
447003831d35Sstevel 	 * emergency interrupt handlers for FAN/PS devices and mask
447103831d35Sstevel 	 * their interrupts, if they aren't already masked.
447203831d35Sstevel 	 */
447303831d35Sstevel 	if (retval == 0) {
447403831d35Sstevel 		goto intr_error;
447503831d35Sstevel 	}
447603831d35Sstevel 
447703831d35Sstevel 	retval = 0;
447803831d35Sstevel 
447903831d35Sstevel 	/*
448003831d35Sstevel 	 * If SCB 1.5 or 2.0, check for the INIT_SCB Interrupt
448103831d35Sstevel 	 * to support Hot SCB Insertion.
448203831d35Sstevel 	 * The check was moved here during debugging of the SCB hot insertion.
448303831d35Sstevel 	 * Theoretically, this code could be moved back to the check for
448403831d35Sstevel 	 * SCTRL_EVENT_SCB in the processing loop below.
448503831d35Sstevel 	 */
448603831d35Sstevel 	if (IS_SCB_P15) {
448703831d35Sstevel 		int	iid;
448803831d35Sstevel 		iid = SCSB_REG_INDEX(intr_addr);
448903831d35Sstevel 		offset = FRU_OFFSET(SCTRL_EVENT_SCB, SCTRL_INTPTR_BASE);
449003831d35Sstevel 		tmp_reg = SCSB_REG_ADDR(SCTRL_INTSRC_SCB_P15);
449103831d35Sstevel 		intr_idx = SCSB_REG_INDEX(tmp_reg) - iid;
449203831d35Sstevel 		clr_bits = 1 << offset;
449303831d35Sstevel 		if (scb_intr_regs[intr_idx] & clr_bits) {
449403831d35Sstevel 			/*
449503831d35Sstevel 			 * Must be newly inserted SCB
449603831d35Sstevel 			 * Time to re-initialize.
449703831d35Sstevel 			 */
449803831d35Sstevel 			if (scsb_debug & 0x00023000) {
449903831d35Sstevel 				cmn_err(CE_NOTE,
450003831d35Sstevel 				    "scsb_intr(%d): INIT_SCB INT",
450103831d35Sstevel 				    scsb->scsb_instance);
450203831d35Sstevel 			}
450303831d35Sstevel 			scsb_restore(scsb);
450403831d35Sstevel 			retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
450503831d35Sstevel 			/*
450603831d35Sstevel 			 * The INTSRC bit will be cleared by the
450703831d35Sstevel 			 * scsb_restore() function.
450803831d35Sstevel 			 * Also, leave the bit set in scb_intr_regs[] so we can
450903831d35Sstevel 			 * report the event code as we check for other
451003831d35Sstevel 			 * interrupt source bits.
451103831d35Sstevel 			 *
451203831d35Sstevel 			 * scsb_write_mask(scsb, tmp_reg, 0, clr_bits, 0);
451303831d35Sstevel 			 * scb_intr_regs[intr_idx] &= ~clr_bits;
451403831d35Sstevel 			 */
451503831d35Sstevel 		}
451603831d35Sstevel 		/*
451703831d35Sstevel 		 * In case this is a power down interrupt, check the validity
451803831d35Sstevel 		 * of the request to make sure it's not an I2C noise
451903831d35Sstevel 		 */
452003831d35Sstevel 		offset = FRU_OFFSET(SCTRL_EVENT_PWRDWN,
452103831d35Sstevel 		    SCTRL_INTPTR_BASE);
452203831d35Sstevel 		clr_bits = 1 << offset;
452303831d35Sstevel 		intr_reg = scb_intr_regs[intr_idx];
452403831d35Sstevel 		if (intr_reg & clr_bits) {
452503831d35Sstevel 			/*
452603831d35Sstevel 			 * A shutdown request has been detected. Poll
452703831d35Sstevel 			 * the corresponding register ? more times to
452803831d35Sstevel 			 * make sure it's a genuine shutdown request.
452903831d35Sstevel 			 */
453003831d35Sstevel 			for (i = 0; i < scsb_shutdown_count; i++) {
453103831d35Sstevel 				drv_usecwait(1000);
453203831d35Sstevel 				if (scsb_rdwr_register(scsb, I2C_WR_RD, tmp_reg,
453303831d35Sstevel 				    1, &intr_reg, 1)) {
453403831d35Sstevel 					cmn_err(CE_WARN, "Failed to read "
453503831d35Sstevel 					    " interrupt register");
453603831d35Sstevel 					goto intr_error;
453703831d35Sstevel 				}
453803831d35Sstevel 				if (scsb_debug & 0x08000000) {
453903831d35Sstevel 					cmn_err(CE_NOTE, "scsb_intr: "
454003831d35Sstevel 					    " INTSRC6[%d]=0x%x", i,
454103831d35Sstevel 					    intr_reg);
454203831d35Sstevel 				}
454303831d35Sstevel 				if (!(intr_reg & clr_bits)) {
454403831d35Sstevel 					scb_intr_regs[intr_idx] &= ~clr_bits;
454503831d35Sstevel 					break;
454603831d35Sstevel 				}
454703831d35Sstevel 			}
454803831d35Sstevel 		}
454903831d35Sstevel 	}
455003831d35Sstevel 	/*
455103831d35Sstevel 	 * if retval == 0, then we didn't call scsb_restore,
455203831d35Sstevel 	 * so we update the shadow copy of SYSCFG registers
455303831d35Sstevel 	 * We *MUST* read the syscfg registers before any attempt
455403831d35Sstevel 	 * to clear the interrupt source registers is made.
455503831d35Sstevel 	 */
455603831d35Sstevel 	if (retval == 0 && scsb_check_config_status(scsb)) {
455703831d35Sstevel 		cmn_err(CE_WARN,
455803831d35Sstevel 		    "scsb_intr: Failed read of config/status registers");
455903831d35Sstevel 		if (scsb->scsb_state & SCSB_P06_NOINT_KLUGE) {
456003831d35Sstevel 			if (!scsb_debug) {
456103831d35Sstevel 				goto intr_error;
456203831d35Sstevel 			}
456303831d35Sstevel 		}
456403831d35Sstevel #ifdef DEBUG
456503831d35Sstevel 		if (scsb->scsb_state & SCSB_SSB_PRESENT &&
456603831d35Sstevel 		    scsb->scsb_i2c_errcnt > scsb_err_threshold) {
456703831d35Sstevel 			scsb_failing_event(scsb);
456803831d35Sstevel 		}
456903831d35Sstevel #endif
457003831d35Sstevel 		/*
457103831d35Sstevel 		 * Allow to go on so we clear the INTSRC bits
457203831d35Sstevel 		 */
457303831d35Sstevel 	}
457403831d35Sstevel 
457503831d35Sstevel 	/*
457603831d35Sstevel 	 * Read the board healthy registers here, if any of the healthy
457703831d35Sstevel 	 * interrupts are set.
457803831d35Sstevel 	 */
457903831d35Sstevel 	if (IS_SCB_P15) {
458003831d35Sstevel 		intr_idx = intr_reg = 0;
458103831d35Sstevel 		intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
458203831d35Sstevel 		index = SCSB_REG_INDEX(intr_addr);
458303831d35Sstevel 		for (i = 0; i < SCTRL_BHLTHY_NUMREGS; ++i, ++intr_idx) {
458403831d35Sstevel 			scsb->scsb_data_reg[index++] =
458503831d35Sstevel 			    scb_intr_regs[intr_idx] & int_masks[intr_idx];
458603831d35Sstevel 			intr_reg |= scb_intr_regs[i];
458703831d35Sstevel 		}
458803831d35Sstevel 
458903831d35Sstevel 		if (intr_reg &&	scsb_read_bhealthy(scsb) != 0) {
459003831d35Sstevel 			cmn_err(CE_WARN, "%s#%d: Error Reading Healthy# "
459103831d35Sstevel 			    " Registers", ddi_driver_name(scsb->scsb_dev),
459203831d35Sstevel 			    ddi_get_instance(scsb->scsb_dev));
459303831d35Sstevel #ifdef DEBUG
459403831d35Sstevel 			if (scsb->scsb_state & SCSB_SSB_PRESENT &&
459503831d35Sstevel 			    scsb->scsb_i2c_errcnt > scsb_err_threshold) {
459603831d35Sstevel 				scsb_failing_event(scsb);
459703831d35Sstevel 			}
459803831d35Sstevel #endif
459903831d35Sstevel 			goto intr_error;
460003831d35Sstevel 		}
460103831d35Sstevel 	}
460203831d35Sstevel 
460303831d35Sstevel 	/*
460403831d35Sstevel 	 * We clear the interrupt source registers now itself so that
460503831d35Sstevel 	 * future interrupts can be latched quickly, instead of after
460603831d35Sstevel 	 * finishing processing of all interrupt conditions. The global
460703831d35Sstevel 	 * interrupt mask however remain disabled.
460803831d35Sstevel 	 */
460903831d35Sstevel 	if (IS_SCB_P15) {
461003831d35Sstevel 		if (scsb_rdwr_register(scsb, I2C_WR, intr_addr,
461103831d35Sstevel 		    SCTRL_INTR_NUMREGS, scb_intr_regs, 1)) {
461203831d35Sstevel 			cmn_err(CE_WARN, "scsb_intr: Failed write to interrupt"
461303831d35Sstevel 			    " registers.");
461403831d35Sstevel #ifdef DEBUG
461503831d35Sstevel 			if (scsb->scsb_state & SCSB_SSB_PRESENT &&
461603831d35Sstevel 			    scsb->scsb_i2c_errcnt > scsb_err_threshold) {
461703831d35Sstevel 				scsb_failing_event(scsb);
461803831d35Sstevel 			}
461903831d35Sstevel #endif
462003831d35Sstevel 			goto intr_error;
462103831d35Sstevel 		}
462203831d35Sstevel 	}
462303831d35Sstevel 
462403831d35Sstevel 	/*
462503831d35Sstevel 	 * At this point, all interrupt source registers are read.
462603831d35Sstevel 	 * We only handle interrups which are not masked
462703831d35Sstevel 	 */
462803831d35Sstevel 	for (i = 0; i < SCTRL_INTR_NUMREGS; ++i) {
462903831d35Sstevel 		scb_intr_regs[i] &= int_masks[i];
463003831d35Sstevel 	}
463103831d35Sstevel 
463203831d35Sstevel 	/*
463303831d35Sstevel 	 * We are here means that there was some bit set in the interrupt
463403831d35Sstevel 	 * source register. So we must claim the interrupt no matter
463503831d35Sstevel 	 * whatever error we may encounter in the course of processing.
463603831d35Sstevel 	 */
463703831d35Sstevel 	retval |= SCSB_INTR_CLAIMED;
463803831d35Sstevel 
463903831d35Sstevel 	/* store config status data */
464003831d35Sstevel 	tmp_reg = SCSB_REG_ADDR(SCTRL_SYSCFG_BASE);
464103831d35Sstevel 	index = SCSB_REG_INDEX(tmp_reg);
464203831d35Sstevel 	for (i = 0; i < SCTRL_CFG_NUMREGS; ++i)
464303831d35Sstevel 		cstatus_regs[i] = scsb->scsb_data_reg[index + i];
464403831d35Sstevel 	/*
464503831d35Sstevel 	 * Clear the event code,
464603831d35Sstevel 	 * then check to see what kind(s) of events we were interrupted for.
464703831d35Sstevel 	 * Check all SCTRL_INTSRC registers
464803831d35Sstevel 	 */
464903831d35Sstevel 	scsb_event_code = 0;
465003831d35Sstevel 	clr_bits = 0;
465103831d35Sstevel 	intr_idx = 0;
465203831d35Sstevel 	numregs = SCTRL_INTR_NUMREGS;
465303831d35Sstevel 	index = SCSB_REG_INDEX(intr_addr);
465403831d35Sstevel 	/*
465503831d35Sstevel 	 * If SCB 1.5, adjust some variables to skip the SCTRL_BHLTHY_REGS
465603831d35Sstevel 	 * which will be handled last in this function.
465703831d35Sstevel 	 */
465803831d35Sstevel 	if (IS_SCB_P15) {
465903831d35Sstevel 		i = SCTRL_BHLTHY_NUMREGS;
466003831d35Sstevel 		intr_idx += i;
466103831d35Sstevel 		intr_addr += i;
466203831d35Sstevel 		index += i;
466303831d35Sstevel 	}
466403831d35Sstevel 	/*
466503831d35Sstevel 	 * For the rest of the INTSRC registers, we walk through the
466603831d35Sstevel 	 * scb_fru_offset[] table, matching register offsets with our offset
466703831d35Sstevel 	 * counter.  Then we check for the scb_fru_offset[] bit in intr_reg.
466803831d35Sstevel 	 * The scb_fru_offset[] index is now the SCTRL_EVENT code.
466903831d35Sstevel 	 * The code is then compared to type_to_code1[] entries to find the
467003831d35Sstevel 	 * fru_type.  The fru_type will help us recognize when to do
467103831d35Sstevel 	 * SLOT Hot Swap processing.
467203831d35Sstevel 	 *
467303831d35Sstevel 	 * offset_base:		the appropriate scb_fru_offset[] base index
467403831d35Sstevel 	 *			for the INTPTR_BASE register group
467503831d35Sstevel 	 * offset:		bit offset found in INTSRC register
467603831d35Sstevel 	 * intr_idx:		index to temporary INTSRC register copies
467703831d35Sstevel 	 * intr:		modified copy of current INTR register
467803831d35Sstevel 	 * intr_addr:		SCB register address of current INTR register
467903831d35Sstevel 	 * index:		index to current INTR shadow register
468003831d35Sstevel 	 * idx:			bit-number of current INTR event bit
468103831d35Sstevel 	 * uc:			uchar_t from scb_fru_offset[] table,
468203831d35Sstevel 	 *			containing register and FRU offsets.
468303831d35Sstevel 	 * j:			used to walk fru_offset[] table, which is also
468403831d35Sstevel 	 *			the bit-number of the current event code
468503831d35Sstevel 	 * code:		manufactured event code for current INT event
468603831d35Sstevel 	 */
468703831d35Sstevel 	offset_base = FRU_OFFSET_BASE(SCTRL_INTPTR_BASE);
468803831d35Sstevel 	for (offset = 0; intr_idx < numregs;
468903831d35Sstevel 	    ++offset, ++intr_idx, ++intr_addr, ++index) {
469003831d35Sstevel 		scsb->scsb_data_reg[index] = scb_intr_regs[intr_idx];
469103831d35Sstevel 		intr_reg = scb_intr_regs[intr_idx];
469203831d35Sstevel 		while (intr_reg) {	/* for each INTSRC bit that's set */
469303831d35Sstevel 			int		j;
469403831d35Sstevel 			uint16_t	ui;
469503831d35Sstevel 			uchar_t		uc;
469603831d35Sstevel 			idx = event_to_index((uint32_t)intr_reg); /* offset */
469703831d35Sstevel 			code = (1 << idx);		/* back to bit mask */
469803831d35Sstevel 			clr_bits |= code;
469903831d35Sstevel 			intr_reg = intr_reg & ~code;	/* clear this one   */
470003831d35Sstevel 			for (j = 0; j < MCT_MAX_FRUS; ++j) {
470103831d35Sstevel 				/*
470203831d35Sstevel 				 * Get register offset from table and check
470303831d35Sstevel 				 * for a match with our loop offset counter.
470403831d35Sstevel 				 * Then check for intr_reg bit-offset match
470503831d35Sstevel 				 * with bit-offset from table entry.
470603831d35Sstevel 				 */
470703831d35Sstevel 				uc = scb_fru_offset[offset_base + j];
470803831d35Sstevel 				if (offset != ((uc >> 4) & 0xf)) {
470903831d35Sstevel 					if (IS_SCB_P10)
471003831d35Sstevel 						continue;
471103831d35Sstevel 					if (j != FRU_INDEX(SCTRL_EVENT_SCB))
471203831d35Sstevel 						continue;
471303831d35Sstevel 					if (offset != ((uc >> 4) & 0xf)
471403831d35Sstevel 					    + SCB_INT_OFFSET)
471503831d35Sstevel 						continue;
471603831d35Sstevel 				}
471703831d35Sstevel 				if (idx == (uc & 0xf))
471803831d35Sstevel 					break;
471903831d35Sstevel 			}
472003831d35Sstevel 			if (uc == 0xff) {
472103831d35Sstevel 				/*
472203831d35Sstevel 				 * bit idx not recognized, check another.
472303831d35Sstevel 				 */
472403831d35Sstevel 				continue;
472503831d35Sstevel 			}
472603831d35Sstevel 			/*
472703831d35Sstevel 			 * We found the fru_offset[] entry, now use the index
472803831d35Sstevel 			 * to get the event code.
472903831d35Sstevel 			 */
473003831d35Sstevel 			code = (uint32_t)(1 << j);
473103831d35Sstevel 			if (scsb_debug & 0x00002000) {
473203831d35Sstevel 				cmn_err(CE_NOTE, "scsb_intr: code=0x%x", code);
473303831d35Sstevel 			}
473403831d35Sstevel 			/*
473503831d35Sstevel 			 * Now check for the NON-FRU type events.
473603831d35Sstevel 			 */
473703831d35Sstevel 			if (code ==  SCTRL_EVENT_PWRDWN) {
473803831d35Sstevel 				if (scsb_debug & 0x1002) {
473903831d35Sstevel 					cmn_err(CE_NOTE,
474003831d35Sstevel 					    "scsb_intr(%d): power down req."
474103831d35Sstevel 					    " INT.", scsb->scsb_instance);
474203831d35Sstevel 				}
474303831d35Sstevel 				scsb_event_code |= code;
474403831d35Sstevel 				if (scsb->scsb_state & SCSB_OPEN &&
474503831d35Sstevel 				    scsb->scsb_rq != (queue_t *)NULL) {
474603831d35Sstevel 					/*
474703831d35Sstevel 					 * inform applications using poll(2)
474803831d35Sstevel 					 * about this event, and provide the
474903831d35Sstevel 					 * event code to EnvMon scsb policy
475003831d35Sstevel 					 */
475103831d35Sstevel 					if (!(scsb_debug & 0x00040000))
475203831d35Sstevel 					(void) scsb_queue_put(scsb->scsb_rq, 1,
475303831d35Sstevel 					    &scsb_event_code, "scsb_intr");
475403831d35Sstevel 					goto intr_error;
475503831d35Sstevel 				}
475603831d35Sstevel 				continue;
475703831d35Sstevel 			} else if (code == SCTRL_EVENT_REPLACE) {
475803831d35Sstevel 				if (scsb_debug & 0x1002) {
475903831d35Sstevel 					cmn_err(CE_NOTE,
476003831d35Sstevel 					    "scsb_intr(%d): replacement "
476103831d35Sstevel 					    "req. INT.",
476203831d35Sstevel 					    scsb->scsb_instance);
476303831d35Sstevel 				}
476403831d35Sstevel 				scsb_freeze_check(scsb);
476503831d35Sstevel 				scsb_freeze(scsb);
476603831d35Sstevel 				scsb_event_code |= code;
476703831d35Sstevel 				retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
476803831d35Sstevel 				continue;
476903831d35Sstevel 			} else if (code == SCTRL_EVENT_SCB) {
477003831d35Sstevel 				int	tmp;
477103831d35Sstevel 				/*
477203831d35Sstevel 				 * Must be newly inserted SCB
477303831d35Sstevel 				 * Time to re-initialize.
477403831d35Sstevel 				 */
477503831d35Sstevel 				if (scsb_debug & 0x1002) {
477603831d35Sstevel 					cmn_err(CE_NOTE,
477703831d35Sstevel 					    "scsb_intr(%d): INIT SCB INTR",
477803831d35Sstevel 					    scsb->scsb_instance);
477903831d35Sstevel 				}
478003831d35Sstevel 				/*
478103831d35Sstevel 				 * SCB initialization already handled, but we
478203831d35Sstevel 				 * set the event code bit here in order to
478303831d35Sstevel 				 * report the event to interested utilities.
478403831d35Sstevel 				 *
478503831d35Sstevel 				 * scsb_restore(scsb);
478603831d35Sstevel 				 * The INTSRC bit is already cleared,
478703831d35Sstevel 				 * so we won't do it again.
478803831d35Sstevel 				 */
478903831d35Sstevel 				tmp = FRU_OFFSET(SCTRL_EVENT_SCB,
479003831d35Sstevel 				    SCTRL_INTPTR_BASE);
479103831d35Sstevel 				clr_bits &= ~(1 << tmp);
479203831d35Sstevel 				scsb_event_code |= code;
479303831d35Sstevel 				retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
479403831d35Sstevel 				continue;
479503831d35Sstevel 			} else if (code == SCTRL_EVENT_ALARM_INT) {
479603831d35Sstevel 				/*
479703831d35Sstevel 				 * P0.6/P1.0: SCTRL_INTR_ALARM_INT is always
479803831d35Sstevel 				 * set and cannot be cleared, so ignore it.
479903831d35Sstevel 				 */
480003831d35Sstevel 				if (!IS_SCB_P15) {
480103831d35Sstevel 					continue;
480203831d35Sstevel 				}
480303831d35Sstevel 				if (scsb_debug & 0x1002) {
480403831d35Sstevel 					cmn_err(CE_NOTE,
480503831d35Sstevel 					    "scsb_intr(%d): Alarm INT.",
480603831d35Sstevel 					    scsb->scsb_instance);
480703831d35Sstevel 				}
480803831d35Sstevel 				scsb_event_code |= code;
480903831d35Sstevel 				retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
481003831d35Sstevel 				/*
481103831d35Sstevel 				 * XXX:
481203831d35Sstevel 				 * Must service the Alarm INT by clearing INT
481303831d35Sstevel 				 * condition on Alarm Card,
481403831d35Sstevel 				 * then clear the SCTRL_INTR_ALARM_INT bit here.
481503831d35Sstevel 				 * Waiting for specs and test environment.
481603831d35Sstevel 				 */
481703831d35Sstevel 				continue;
481803831d35Sstevel 			} else if ((ui = event_to_type(code)) == 0xffff) {
481903831d35Sstevel 				/*
482003831d35Sstevel 				 * FRU type not found
482103831d35Sstevel 				 */
482203831d35Sstevel 				break;
482303831d35Sstevel 			}
482403831d35Sstevel 			/*
482503831d35Sstevel 			 * Check for special processing
482603831d35Sstevel 			 * now that we found the FRU type.
482703831d35Sstevel 			 */
482803831d35Sstevel 			fru_type = (scsb_utype_t)(ui & 0xff);
482903831d35Sstevel 			unit = (ui >> 8) & 0xff;
483003831d35Sstevel 			if (scsb_debug & 0x00002000) {
483103831d35Sstevel 				cmn_err(CE_NOTE, "scsb_intr: "
483203831d35Sstevel 				    "FRU type/unit/code %d/%d/0x%x",
483303831d35Sstevel 				    fru_type, unit, code);
483403831d35Sstevel 			}
483503831d35Sstevel 			switch (fru_type) {
483603831d35Sstevel 			case PDU:
483703831d35Sstevel 				break;
483803831d35Sstevel 			case PS:
483903831d35Sstevel 				break;
484003831d35Sstevel 			case DISK:
484103831d35Sstevel 				break;
484203831d35Sstevel 			case FAN:
484303831d35Sstevel 				break;
484403831d35Sstevel 			case SSB:
484503831d35Sstevel 				/*
484603831d35Sstevel 				 * in check_fru_info() below, we see if the
484703831d35Sstevel 				 * SSB has been removed, then check for
484803831d35Sstevel 				 * occupied slots in reset to see if we should
484903831d35Sstevel 				 * WARN agains SCB removal
485003831d35Sstevel 				 */
485103831d35Sstevel 				break;
485203831d35Sstevel 			case CFTM:
485303831d35Sstevel 				break;
485403831d35Sstevel 			case CRTM:
485503831d35Sstevel 				break;
485603831d35Sstevel 			case PRTM:
485703831d35Sstevel 				break;
485803831d35Sstevel 			case SLOT:
485903831d35Sstevel 				slotnum = tonga_ssl_to_psl(scsb, unit);
486003831d35Sstevel 				if (scsb_debug & 0x00002000) {
486103831d35Sstevel 					cmn_err(CE_NOTE, "scsb_intr: "
486203831d35Sstevel 					    "unit/slot %d/%d",
486303831d35Sstevel 					    unit, slotnum);
486403831d35Sstevel 				}
486503831d35Sstevel 
486603831d35Sstevel 				/*
486703831d35Sstevel 				 * If the slot number is not valid, continue.
486803831d35Sstevel 				 */
486903831d35Sstevel 				if (scsb->scsb_state & SCSB_IS_TONGA) {
487003831d35Sstevel 					if (slotnum > TG_MAX_SLOTS ||
487103831d35Sstevel 					    slotnum == SC_TG_CPU_SLOT) {
487203831d35Sstevel 						continue;
487303831d35Sstevel 					}
487403831d35Sstevel 					/*
487503831d35Sstevel 					 * For a tonga, we need to return
487603831d35Sstevel 					 * the code corresponding to the
487703831d35Sstevel 					 * actual physical slot
487803831d35Sstevel 					 */
487903831d35Sstevel 					code = FRU_UNIT_TO_EVCODE(SLOT,
488003831d35Sstevel 					    slotnum);
488103831d35Sstevel 				} else {
488203831d35Sstevel 					if (slotnum > MC_MAX_SLOTS ||
488303831d35Sstevel 					    slotnum == SC_MC_CPU_SLOT ||
488403831d35Sstevel 					    (scsb->scsb_hsc_state &
488503831d35Sstevel 					    SCSB_HSC_CTC_PRES &&
488603831d35Sstevel 					    slotnum == SC_MC_CTC_SLOT)) {
488703831d35Sstevel 						continue;
488803831d35Sstevel 					}
488903831d35Sstevel 				}
489003831d35Sstevel 			/* FALLTHROUGH */
489103831d35Sstevel 			case ALARM:
489203831d35Sstevel 		/*
489303831d35Sstevel 		 * INDENT CHEATING, 2 indentations
489403831d35Sstevel 		 */
489503831d35Sstevel 		ac_present = 0;
489603831d35Sstevel 		/*
489703831d35Sstevel 		 * If it is an Alarm Card Interrupt, we just do some sanity
489803831d35Sstevel 		 * checks and then wait for the slot interrupt to take
489903831d35Sstevel 		 * connect or disconnect action.
490003831d35Sstevel 		 * XXX - Is there a gaurantee that ALARM int will occur first ?
490103831d35Sstevel 		 */
490203831d35Sstevel 		if (fru_type == ALARM) {
490303831d35Sstevel 			DEBUG2("AC Intr %d(%d)\n", scsb->ac_slotnum, idx+1);
490403831d35Sstevel 			val = scsb_fru_op(scsb, SLOT,
490503831d35Sstevel 			    tonga_ssl_to_psl(scsb, scsb->ac_slotnum),
490603831d35Sstevel 			    SCTRL_SYSCFG_BASE, SCSB_FRU_OP_GET_BITVAL);
490703831d35Sstevel 			ac_present = scsb_fru_op(scsb, ALARM, 1,
490803831d35Sstevel 			    SCTRL_SYSCFG_BASE,
490903831d35Sstevel 			    SCSB_FRU_OP_GET_BITVAL);
491003831d35Sstevel 			/*
491103831d35Sstevel 			 * It is observed that slot presence and Alarm
491203831d35Sstevel 			 * presence bits do not go ON at the same time.
491303831d35Sstevel 			 * Hence we wait till both events happen.
491403831d35Sstevel 			 */
491503831d35Sstevel #ifdef DEBUG
491603831d35Sstevel 			if ((((val) && (!ac_present)) ||
491703831d35Sstevel 			    ((!val) && (ac_present))) &&
491803831d35Sstevel 			    (scsb->scsb_hsc_state &
491903831d35Sstevel 			    SCSB_AC_SLOT_INTR_DONE))
492003831d35Sstevel 
492103831d35Sstevel 				cmn_err(CE_WARN, "?Alarm and Slot presence "
492203831d35Sstevel 				    "state bits do not match! (%x,%x)",
492303831d35Sstevel 				    val, ac_present);
492403831d35Sstevel #endif
492503831d35Sstevel 			if (scsb->scsb_hsc_state & SCSB_AC_SLOT_INTR_DONE)
492603831d35Sstevel 				scsb->scsb_hsc_state &= ~SCSB_AC_SLOT_INTR_DONE;
492703831d35Sstevel 			else
492803831d35Sstevel 				scsb->scsb_hsc_state |= SCSB_AC_SLOT_INTR_DONE;
492903831d35Sstevel 			break;	/* we break and wait for slot interrupt. */
493003831d35Sstevel 		}
493103831d35Sstevel 
493203831d35Sstevel 		/*
493303831d35Sstevel 		 * cPCI slot interrupt event
493403831d35Sstevel 		 */
493503831d35Sstevel 		if (scsb->scsb_state & SCSB_IS_TONGA) {
493603831d35Sstevel 			if (slotnum > TG_MAX_SLOTS ||
493703831d35Sstevel 			    slotnum == SC_TG_CPU_SLOT) {
493803831d35Sstevel 				continue;
493903831d35Sstevel 			}
494003831d35Sstevel 		} else {
494103831d35Sstevel 			if (slotnum > MC_MAX_SLOTS ||
494203831d35Sstevel 			    slotnum == SC_MC_CPU_SLOT ||
494303831d35Sstevel 			    (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
494403831d35Sstevel 			    slotnum == SC_MC_CTC_SLOT)) {
494503831d35Sstevel 				continue;
494603831d35Sstevel 			}
494703831d35Sstevel 		}
494803831d35Sstevel 		if (scsb_is_alarm_card_slot(scsb, slotnum) == B_TRUE) {
494903831d35Sstevel 			DEBUG2("AC slot Intr %d(%d)\n", slotnum, idx+1);
495003831d35Sstevel 			ac_slot = B_TRUE;
495103831d35Sstevel 		}
495203831d35Sstevel 		val = scsb_fru_op(scsb, SLOT, unit, SCTRL_SYSCFG_BASE,
495303831d35Sstevel 		    SCSB_FRU_OP_GET_BITVAL);
495403831d35Sstevel 		if (ac_slot == B_TRUE) {
495503831d35Sstevel 			ac_present = scsb_fru_op(scsb, ALARM, 1,
495603831d35Sstevel 			    SCTRL_SYSCFG_BASE,
495703831d35Sstevel 			    SCSB_FRU_OP_GET_BITVAL);
495803831d35Sstevel #ifdef DEBUG
495903831d35Sstevel 			if ((((val) && (!ac_present)) ||
496003831d35Sstevel 			    ((!val) && (ac_present))) &&
496103831d35Sstevel 			    (scsb->scsb_hsc_state &
496203831d35Sstevel 			    SCSB_AC_SLOT_INTR_DONE)) {
496303831d35Sstevel 
496403831d35Sstevel 				cmn_err(CE_WARN, "?Alarm and Slot presence "
496503831d35Sstevel 				    "state bits do not match! (%x,%x)",
496603831d35Sstevel 				    val, ac_present);
496703831d35Sstevel 			}
496803831d35Sstevel #endif
496903831d35Sstevel 			if (scsb->scsb_hsc_state & SCSB_AC_SLOT_INTR_DONE)
497003831d35Sstevel 				scsb->scsb_hsc_state &= ~SCSB_AC_SLOT_INTR_DONE;
497103831d35Sstevel 			else
497203831d35Sstevel 				scsb->scsb_hsc_state |= SCSB_AC_SLOT_INTR_DONE;
497303831d35Sstevel 		}
497403831d35Sstevel 		if (val) {
497503831d35Sstevel 			if (ac_present) {
497603831d35Sstevel 				DEBUG1("AC insertion on slot %d!\n", slotnum);
497703831d35Sstevel 				if (scsb_debug & 0x00010000) {
497803831d35Sstevel 					cmn_err(CE_NOTE, "scsb_intr: "
497903831d35Sstevel 					"AC_PRES slot %d", slotnum);
498003831d35Sstevel 				}
498103831d35Sstevel 				scsb->scsb_hsc_state |= SCSB_ALARM_CARD_PRES;
498203831d35Sstevel 			}
498303831d35Sstevel #ifndef	lint
498403831d35Sstevel 			else
498503831d35Sstevel 				DEBUG1("IO Insertion on slot %d!\n", slotnum);
498603831d35Sstevel #endif
498703831d35Sstevel 			/*
498803831d35Sstevel 			 * Special case : check MPID type.
498903831d35Sstevel 			 * If MC midplane type,
499003831d35Sstevel 			 * check to make sure the Alarm Card present
499103831d35Sstevel 			 * bit is ON. If not, this is a regular IO card.
499203831d35Sstevel 			 */
499303831d35Sstevel 			(void) scsb_connect_slot(scsb, slotnum, B_FALSE);
499403831d35Sstevel 		} else {
499503831d35Sstevel 			if ((ac_slot == B_TRUE) &&
499603831d35Sstevel 			    (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES)) {
499703831d35Sstevel 
499803831d35Sstevel 				DEBUG1("AC Removal on slot %d!\n", slotnum);
499903831d35Sstevel #ifdef DEBUG
500003831d35Sstevel 				if (scsb_debug & 0x00010000) {
500103831d35Sstevel 					cmn_err(CE_NOTE, "scsb_intr: "
500203831d35Sstevel 					    "!AC_PRES slot %d",
500303831d35Sstevel 					    slotnum);
500403831d35Sstevel 				}
500503831d35Sstevel #endif /* DEBUG */
500603831d35Sstevel 				scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_PRES;
500703831d35Sstevel 			}
500803831d35Sstevel #ifndef	lint
500903831d35Sstevel 			else
501003831d35Sstevel 				DEBUG1("IO Removal on slot %d!\n", slotnum);
501103831d35Sstevel #endif
501203831d35Sstevel 			(void) scsb_disconnect_slot(scsb, B_FALSE, slotnum);
501303831d35Sstevel 		}
501403831d35Sstevel 		/*
501503831d35Sstevel 		 * END INDENT CHEATING, 2 indentations
501603831d35Sstevel 		 */
501703831d35Sstevel 
501803831d35Sstevel 				break;
501903831d35Sstevel 			default:
502003831d35Sstevel 				/*
502103831d35Sstevel 				 * ERROR: Did not find cause of INTSRC bit
502203831d35Sstevel 				 */
502303831d35Sstevel 				if (scsb_debug & 0x00000002) {
502403831d35Sstevel 					cmn_err(CE_WARN,
502503831d35Sstevel 					    "scsb_intr: FRU type %d"
502603831d35Sstevel 					    " not recognized", fru_type);
502703831d35Sstevel 				}
502803831d35Sstevel 				continue;
502903831d35Sstevel 			}
503003831d35Sstevel 			scsb_event_code |= code;
503103831d35Sstevel 			retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
503203831d35Sstevel 			if (fru_type == SLOT)
503303831d35Sstevel 				continue;
503403831d35Sstevel 			error = 0;
503503831d35Sstevel 			fru_ptr = mct_system_info.fru_info_list[fru_type];
503603831d35Sstevel 			for (; fru_ptr != NULL; fru_ptr = fru_ptr->next) {
503703831d35Sstevel 				if (unit != fru_ptr->fru_unit)
503803831d35Sstevel 					continue;
503903831d35Sstevel 				if (fru_ptr->i2c_info == NULL ||
504003831d35Sstevel 				    (tmp_reg = fru_ptr->i2c_info->
504103831d35Sstevel 				    ledata_reg) == 0)
504203831d35Sstevel 					continue;
504303831d35Sstevel 				error = scsb_set_scfg_pres_leds(scsb, fru_ptr);
504403831d35Sstevel 				if (error) {
504503831d35Sstevel 					cmn_err(CE_WARN, "scsb_intr(): "
504603831d35Sstevel 					    "I2C write error to 0x%x",
504703831d35Sstevel 					    tmp_reg);
504803831d35Sstevel 					if (!(scsb->scsb_state &
504903831d35Sstevel 					    SCSB_DEBUG_MODE)) {
505003831d35Sstevel 						goto intr_error;
505103831d35Sstevel 					}
505203831d35Sstevel 				}
505303831d35Sstevel 				break;
505403831d35Sstevel 			}
505503831d35Sstevel 		}
505603831d35Sstevel 		if (clr_bits) {
505703831d35Sstevel 			clr_bits = 0;
505803831d35Sstevel 		}
505903831d35Sstevel 	}
506003831d35Sstevel 	/*
506103831d35Sstevel 	 * Check for SCB 1.5 interrupt for SLOT HEALTHY changes
506203831d35Sstevel 	 */
506303831d35Sstevel 	clr_bits = 0;
506403831d35Sstevel 	intr_idx = 0;
506503831d35Sstevel 	numregs = SCTRL_INTR_NUMREGS;
506603831d35Sstevel 	intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
506703831d35Sstevel 	index = SCSB_REG_INDEX(intr_addr);
506803831d35Sstevel 	if (IS_SCB_P15) {
506903831d35Sstevel 		for (i = 0; i < SCTRL_BHLTHY_NUMREGS;
507003831d35Sstevel 		    ++i, ++intr_idx, ++intr_addr) {
507103831d35Sstevel 			scsb->scsb_data_reg[index++] = scb_intr_regs[intr_idx];
507203831d35Sstevel 			intr_reg = scb_intr_regs[i];
507303831d35Sstevel 			while (intr_reg) {
507403831d35Sstevel 				idx = event_to_index((uint32_t)intr_reg);
507503831d35Sstevel 				code = (1 << idx);
507603831d35Sstevel 				clr_bits |= code;
507703831d35Sstevel 				intr_reg = intr_reg & ~code;
507803831d35Sstevel 				/* idx + 1 because bit 0 is for Slot 1 */
507903831d35Sstevel 				slotnum = tonga_ssl_to_psl(scsb, idx + 1);
508003831d35Sstevel 				if (scsb->scsb_state & SCSB_IS_TONGA) {
508103831d35Sstevel 					if (slotnum > TG_MAX_SLOTS ||
508203831d35Sstevel 					    slotnum == SC_TG_CPU_SLOT) {
508303831d35Sstevel 						continue;
508403831d35Sstevel 					}
508503831d35Sstevel 				} else {
508603831d35Sstevel 					if (slotnum > MC_MAX_SLOTS ||
508703831d35Sstevel 					    slotnum == SC_MC_CPU_SLOT ||
508803831d35Sstevel 					    (scsb->scsb_hsc_state &
508903831d35Sstevel 					    SCSB_HSC_CTC_PRES &&
509003831d35Sstevel 					    slotnum == SC_MC_CTC_SLOT)) {
509103831d35Sstevel 						continue;
509203831d35Sstevel 					}
509303831d35Sstevel 				}
509403831d35Sstevel 				scsb_healthy_intr(scsb, slotnum);
509503831d35Sstevel 			}
509603831d35Sstevel 			if (clr_bits) {
509703831d35Sstevel 				clr_bits = 0;
509803831d35Sstevel 			}
509903831d35Sstevel 		}
510003831d35Sstevel 	}
510103831d35Sstevel 	code = scsb_event_code;
510203831d35Sstevel 	if (retval & SCSB_INTR_EVENT &&
510303831d35Sstevel 	    !(scsb->scsb_state & SCSB_P06_NOINT_KLUGE)) {
510403831d35Sstevel 		check_fru_info(scsb, code);
510503831d35Sstevel 		add_event_code(scsb, code);
510603831d35Sstevel 		(void) scsb_queue_ops(scsb, QPUT_INT32, 1, &scsb_event_code,
510703831d35Sstevel 		"scsb_intr");
510803831d35Sstevel 	}
510903831d35Sstevel intr_error:
511003831d35Sstevel 	scb_post_e = gethrtime();
511103831d35Sstevel 
511203831d35Sstevel 	if (scsb_debug & 0x8000000)
511303831d35Sstevel 		cmn_err(CE_NOTE, "Summary of times in nsec: pre_time %llu, \
511403831d35Sstevel 			post_time %llu", scb_pre_e - scb_pre_s,
511503831d35Sstevel 		    scb_post_e - scb_post_s);
511603831d35Sstevel 
511703831d35Sstevel 
511803831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
511903831d35Sstevel 	scsb_in_postintr = 0;
512003831d35Sstevel 	cv_broadcast(&scsb->scsb_cv);
512103831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
512203831d35Sstevel 
512303831d35Sstevel 	/*
512403831d35Sstevel 	 * Re-enable interrupt now.
512503831d35Sstevel 	 */
5126*07d06da5SSurya Prakki 	(void) scsb_toggle_psmint(scsb, 1);
512703831d35Sstevel 	scsb->scsb_state &= ~SCSB_IN_INTR;
512803831d35Sstevel }
512903831d35Sstevel 
513003831d35Sstevel static int
513103831d35Sstevel scsb_polled_int(scsb_state_t *scsb, int cmd, uint32_t *set)
513203831d35Sstevel {
513303831d35Sstevel 	if (scsb_debug & 0x4000)
513403831d35Sstevel 		cmn_err(CE_NOTE, "scsb_polled_int(scsb,0x%x)", cmd);
513503831d35Sstevel 	*set = 0;
513603831d35Sstevel 	if (cmd == SCSBIOC_SHUTDOWN_POLL) {
513703831d35Sstevel 		return (EINVAL);
513803831d35Sstevel 	}
513903831d35Sstevel 	if (cmd != SCSBIOC_INTEVENT_POLL) {
514003831d35Sstevel 		return (EINVAL);
514103831d35Sstevel 	}
514203831d35Sstevel 	if (scsb->scsb_state & SCSB_P06_NOINT_KLUGE) {
514303831d35Sstevel 		/*
514403831d35Sstevel 		 * scsb_intr() may modify scsb_event_code
514503831d35Sstevel 		 */
514603831d35Sstevel 		scsb_event_code = SCTRL_EVENT_NONE;
514703831d35Sstevel 		(void) scsb_intr((caddr_t)scsb);
514803831d35Sstevel 		*set = scsb_event_code;
514903831d35Sstevel 		scsb_event_code = 0;
515003831d35Sstevel 	} else {
515103831d35Sstevel 		/*
515203831d35Sstevel 		 * SCSB_P06_INTR_ON, we know there was an event
515303831d35Sstevel 		 * and we're retrieving the event code from the event FIFO.
515403831d35Sstevel 		 */
515503831d35Sstevel 		*set = get_event_code();
515603831d35Sstevel 	}
515703831d35Sstevel 	if (scsb_debug & 0x01004000) {
515803831d35Sstevel 		cmn_err(CE_NOTE, "scsb_polled_int: event_code = 0x%x", *set);
515903831d35Sstevel 	}
516003831d35Sstevel 	return (0);
516103831d35Sstevel }
516203831d35Sstevel 
516303831d35Sstevel static int
516403831d35Sstevel scsb_leds_switch(scsb_state_t *scsb, scsb_ustate_t op)
516503831d35Sstevel {
516603831d35Sstevel 	register int 	i;
516703831d35Sstevel 	int		index;
516803831d35Sstevel 	uchar_t		reg, idata, rwbuf[SCTRL_MAX_GROUP_NUMREGS];
516903831d35Sstevel 
517003831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN &&
517103831d35Sstevel 	    !(scsb->scsb_state & SCSB_IN_INTR)) {
517203831d35Sstevel 		return (EAGAIN);
517303831d35Sstevel 	}
517403831d35Sstevel 	if (scsb_debug & 0x0101) {
517503831d35Sstevel 		cmn_err(CE_NOTE, "scsb_leds_switch(%s):",
517603831d35Sstevel 		    op == ON ? "ON" : "OFF");
517703831d35Sstevel 	}
517803831d35Sstevel 	/* Step 1: turn ON/OFF all NOK LEDs. */
517903831d35Sstevel 	if (scsb_debug & 0x0100) {
518003831d35Sstevel 		cmn_err(CE_NOTE, "scsb%d: turning all NOK LEDs %s",
518103831d35Sstevel 		    scsb->scsb_instance,
518203831d35Sstevel 		    op == ON ? "ON" : "OFF");
518303831d35Sstevel 	}
518403831d35Sstevel 	if (op == ON)
518503831d35Sstevel 		idata = 0xff;
518603831d35Sstevel 	else	/* off */
518703831d35Sstevel 		idata = 0x00;
518803831d35Sstevel 	reg = SCSB_REG_ADDR(SCTRL_LED_NOK_BASE);
518903831d35Sstevel 	index = SCSB_REG_INDEX(reg);
519003831d35Sstevel 	for (i = 0; i < SCTRL_LED_NOK_NUMREGS;  ++i) {
519103831d35Sstevel 		rwbuf[i] = idata;
519203831d35Sstevel 		scsb->scsb_data_reg[index + i] = idata;
519303831d35Sstevel 	}
519403831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
519503831d35Sstevel 	i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_LED_NOK_NUMREGS,
519603831d35Sstevel 	    rwbuf, 1);
519703831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
519803831d35Sstevel 	if (i) {
519903831d35Sstevel 		if (scsb_debug & 0x0102)
520003831d35Sstevel 			cmn_err(CE_WARN, "scsb_leds_switch(): "
520103831d35Sstevel 			    "Failed to turn %s NOK LEDs",
520203831d35Sstevel 			    op == ON ? "ON" : "OFF");
520303831d35Sstevel 	}
520403831d35Sstevel 	/* Step 2: turn ON/OFF all OK LEDs. */
520503831d35Sstevel 	if (scsb_debug & 0x0100) {
520603831d35Sstevel 		cmn_err(CE_NOTE, "scsb%d: turning all OK LEDs %s",
520703831d35Sstevel 		    scsb->scsb_instance,
520803831d35Sstevel 		    op == ON ? "ON" : "OFF");
520903831d35Sstevel 	}
521003831d35Sstevel 	reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE);
521103831d35Sstevel 	index = SCSB_REG_INDEX(reg);
521203831d35Sstevel 	for (i = 0; i < SCTRL_LED_OK_NUMREGS;  ++i) {
521303831d35Sstevel 		rwbuf[i] = idata;
521403831d35Sstevel 		scsb->scsb_data_reg[index + i] = idata;
521503831d35Sstevel 	}
521603831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
521703831d35Sstevel 	i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_LED_OK_NUMREGS,
521803831d35Sstevel 	    rwbuf, 1);
521903831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
522003831d35Sstevel 	if (i) {
522103831d35Sstevel 		if (scsb_debug & 0x0102)
522203831d35Sstevel 			cmn_err(CE_WARN, "scsb_leds_switch(): "
522303831d35Sstevel 			    "Failed to turn %s NOK LEDs",
522403831d35Sstevel 			    op == ON ? "ON" : "OFF");
522503831d35Sstevel 	}
522603831d35Sstevel 	/* Step 3: turn OFF all BLINK LEDs. */
522703831d35Sstevel 	if (op == OFF) {
522803831d35Sstevel 		reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE);
522903831d35Sstevel 		index = SCSB_REG_INDEX(reg);
523003831d35Sstevel 		for (i = 0; i < SCTRL_BLINK_NUMREGS;  ++i) {
523103831d35Sstevel 			rwbuf[i] = idata;
523203831d35Sstevel 			scsb->scsb_data_reg[index + i] = idata;
523303831d35Sstevel 		}
523403831d35Sstevel 		mutex_enter(&scsb->scsb_mutex);
523503831d35Sstevel 		i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_BLINK_NUMREGS,
523603831d35Sstevel 		    rwbuf, 1);
523703831d35Sstevel 		mutex_exit(&scsb->scsb_mutex);
523803831d35Sstevel 		if (i) {
523903831d35Sstevel 			if (scsb_debug & 0x0102)
524003831d35Sstevel 				cmn_err(CE_WARN, "scsb_leds_switch(): "
524103831d35Sstevel 				    "Failed to turn %s BLINK BITs",
524203831d35Sstevel 				    op == ON ? "ON" : "OFF");
524303831d35Sstevel 		}
524403831d35Sstevel 	}
524503831d35Sstevel 	return (0);
524603831d35Sstevel }
524703831d35Sstevel 
524803831d35Sstevel static int
524903831d35Sstevel scsb_readall_regs(scsb_state_t *scsb)
525003831d35Sstevel {
525103831d35Sstevel 	int		error;
525203831d35Sstevel 	int		index;
525303831d35Sstevel 	uchar_t		reg;
525403831d35Sstevel 
525503831d35Sstevel 	if (!(scsb_debug & 0x40000000))
525603831d35Sstevel 		return (0);
525703831d35Sstevel 	if (scsb_debug & 0x0005) {
525803831d35Sstevel 		cmn_err(CE_NOTE, "scsb_readall_regs:");
525903831d35Sstevel 	}
526003831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN) {
526103831d35Sstevel 		return (EAGAIN);
526203831d35Sstevel 	}
526303831d35Sstevel 	reg = SCSB_REG_ADDR_START;	/* 1st register in set */
526403831d35Sstevel 	index = SCSB_REG_INDEX(reg);
526503831d35Sstevel 	error = scsb_rdwr_register(scsb, I2C_WR_RD, reg, SCSB_DATA_REGISTERS,
526603831d35Sstevel 	    &scsb->scsb_data_reg[index], 1);
526703831d35Sstevel 	return (error);
526803831d35Sstevel }
526903831d35Sstevel 
527003831d35Sstevel 
527103831d35Sstevel /*
527203831d35Sstevel  * read 1-byte register, mask with read bits (rmask),
527303831d35Sstevel  * turn ON bits in on_mask, turn OFF bits in off_mask
527403831d35Sstevel  * write the byte back to register
527503831d35Sstevel  * NOTE: MUST be called with mutex held
527603831d35Sstevel  */
527703831d35Sstevel static int
527803831d35Sstevel scsb_write_mask(scsb_state_t *scsb,
527903831d35Sstevel 		uchar_t reg,
528003831d35Sstevel 		uchar_t rmask,
528103831d35Sstevel 		uchar_t on_mask,
528203831d35Sstevel 		uchar_t off_mask)
528303831d35Sstevel {
528403831d35Sstevel 	i2c_transfer_t	*i2cxferp;
528503831d35Sstevel 	int		index, error = 0;
528603831d35Sstevel 	uchar_t		reg_data;
528703831d35Sstevel 
528803831d35Sstevel 	if (scsb_debug & 0x0800) {
528903831d35Sstevel 		cmn_err(CE_NOTE, "scsb_write_mask(,%x,,%x,%x):",
529003831d35Sstevel 		    reg, on_mask, off_mask);
529103831d35Sstevel 	}
529203831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN &&
529303831d35Sstevel 	    !(scsb->scsb_state & SCSB_IN_INTR)) {
529403831d35Sstevel 		return (EAGAIN);
529503831d35Sstevel 	}
529603831d35Sstevel 	/* select the register address and read the register */
529703831d35Sstevel 	i2cxferp = (i2c_transfer_t *)scsb->scsb_i2ctp;
529803831d35Sstevel 	i2cxferp->i2c_flags = I2C_WR_RD;
529903831d35Sstevel 	i2cxferp->i2c_wlen = 1;
530003831d35Sstevel 	i2cxferp->i2c_rlen = 1;
530103831d35Sstevel 	i2cxferp->i2c_wbuf[0] = reg;
530203831d35Sstevel 	i2cxferp->i2c_rbuf[0] = 0;
530303831d35Sstevel 	scsb->scsb_kstat_flag = B_TRUE;	/* we did a i2c transaction */
530403831d35Sstevel 	if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
530503831d35Sstevel 		error = EIO;
530603831d35Sstevel 		goto wm_error;
530703831d35Sstevel 	}
530803831d35Sstevel 	scsb->scsb_i2c_errcnt = 0;
530903831d35Sstevel 	if (scsb_debug & 0x0800)
531003831d35Sstevel 		cmn_err(CE_NOTE, "scsb_write_mask() read 0x%x",
531103831d35Sstevel 		    i2cxferp->i2c_rbuf[0]);
531203831d35Sstevel 	reg_data = i2cxferp->i2c_rbuf[0];
531303831d35Sstevel 	if (rmask)
531403831d35Sstevel 		reg_data &= rmask;
531503831d35Sstevel 	if (off_mask)
531603831d35Sstevel 		reg_data &= ~off_mask;
531703831d35Sstevel 	if (on_mask)
531803831d35Sstevel 		reg_data |= on_mask;
531903831d35Sstevel 	i2cxferp->i2c_flags = I2C_WR;
532003831d35Sstevel 	i2cxferp->i2c_wlen = 2;
532103831d35Sstevel 	i2cxferp->i2c_wbuf[0] = reg;
532203831d35Sstevel 	i2cxferp->i2c_wbuf[1] = reg_data;
532303831d35Sstevel 	if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
532403831d35Sstevel 		error = EIO;
532503831d35Sstevel 		goto wm_error;
532603831d35Sstevel 	}
532703831d35Sstevel 	/* keep shadow registers updated */
532803831d35Sstevel 	index = SCSB_REG_INDEX(reg);
532903831d35Sstevel 	scsb->scsb_data_reg[index] = reg_data;
533003831d35Sstevel 	if (scsb_debug & 0x0800)
533103831d35Sstevel 		cmn_err(CE_NOTE, "scsb_write_mask() wrote 0x%x", reg_data);
533203831d35Sstevel 	scsb->scsb_i2c_errcnt = 0;
533303831d35Sstevel 	return (error);
533403831d35Sstevel wm_error:
533503831d35Sstevel 	scsb->scsb_i2c_errcnt++;
533603831d35Sstevel 	if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
533703831d35Sstevel 		scsb->scsb_err_flag = B_TRUE; /* latch error */
533803831d35Sstevel 	if (scsb->scsb_state & SCSB_SSB_PRESENT) {
533903831d35Sstevel 		if (scsb_debug & 0x0802)
534003831d35Sstevel 			cmn_err(CE_WARN,
534103831d35Sstevel 			    "scsb_write_mask(): reg %x %s error, data=%x",
534203831d35Sstevel 			    reg,
534303831d35Sstevel 			    i2cxferp->i2c_flags & I2C_WR ? "write" : "read",
534403831d35Sstevel 			    i2cxferp->i2c_flags & I2C_WR ?
534503831d35Sstevel 			    i2cxferp->i2c_wbuf[1] : i2cxferp->i2c_rbuf[0]);
534603831d35Sstevel 	} else {
534703831d35Sstevel 		if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
534803831d35Sstevel 			scsb_freeze(scsb);
534903831d35Sstevel 		return (EAGAIN);
535003831d35Sstevel 	}
535103831d35Sstevel 	return (error);
535203831d35Sstevel }
535303831d35Sstevel 
535403831d35Sstevel /*
535503831d35Sstevel  * read/write len consecutive single byte registers to/from rbuf
535603831d35Sstevel  * NOTE: should be called with mutex held
535703831d35Sstevel  */
535803831d35Sstevel static int
535903831d35Sstevel scsb_rdwr_register(scsb_state_t *scsb, int op, uchar_t reg, int len,
536003831d35Sstevel 				uchar_t *rwbuf, int i2c_alloc)
536103831d35Sstevel {
536203831d35Sstevel 	i2c_transfer_t	*i2cxferp;
536303831d35Sstevel 	int		i, rlen, wlen, index, error = 0;
536403831d35Sstevel 
536503831d35Sstevel 	if (scsb_debug & 0x0800) {
536603831d35Sstevel 		cmn_err(CE_NOTE, "scsb_rdwr_register(scsb,%s,%x,%x,buf):",
536703831d35Sstevel 		    (op == I2C_WR) ? "write" : "read",  reg, len);
536803831d35Sstevel 	}
536903831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN &&
537003831d35Sstevel 	    !(scsb->scsb_state & SCSB_IN_INTR)) {
537103831d35Sstevel 		return (EAGAIN);
537203831d35Sstevel 	}
537303831d35Sstevel 	if (i2c_alloc) {
537403831d35Sstevel 		i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle, I2C_NOSLEEP);
537503831d35Sstevel 		if (i2cxferp == NULL) {
537603831d35Sstevel 			if (scsb_debug & 0x0042)
537703831d35Sstevel 				cmn_err(CE_WARN, "scsb_rdwr_register: "
537803831d35Sstevel 				    "i2ctx allocation failure");
537903831d35Sstevel 			return (ENOMEM);
538003831d35Sstevel 		}
538103831d35Sstevel 	} else {
538203831d35Sstevel 		i2cxferp = scsb->scsb_i2ctp;
538303831d35Sstevel 	}
538403831d35Sstevel 	index = SCSB_REG_INDEX(reg);
538503831d35Sstevel 	switch (op) {
538603831d35Sstevel 	case I2C_WR:
538703831d35Sstevel 		wlen = len + 1;	/* add the address */
538803831d35Sstevel 		rlen = 0;
538903831d35Sstevel 		i2cxferp->i2c_wbuf[0] = reg;
539003831d35Sstevel 		for (i = 0; i < len; ++i) {
539103831d35Sstevel 			scsb->scsb_data_reg[index + i] =
539203831d35Sstevel 			    i2cxferp->i2c_wbuf[1 + i] = rwbuf[i];
539303831d35Sstevel 			if (scsb_debug & 0x0080)
539403831d35Sstevel 				cmn_err(CE_NOTE,
539503831d35Sstevel 				"scsb_rdwr_register: writing rwbuf[%d]=0x%x",
539603831d35Sstevel 				    i, rwbuf[i]);
539703831d35Sstevel 		}
539803831d35Sstevel 		break;
539903831d35Sstevel 	case I2C_WR_RD:
540003831d35Sstevel 		wlen = 1;	/* for the address */
540103831d35Sstevel 		rlen = len;
540203831d35Sstevel 		i2cxferp->i2c_wbuf[0] = reg;
540303831d35Sstevel 		break;
540403831d35Sstevel 	default:
540503831d35Sstevel 		if (i2c_alloc)
540603831d35Sstevel 			scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
540703831d35Sstevel 		return (EINVAL);
540803831d35Sstevel 	}
540903831d35Sstevel 	/* select the register address */
541003831d35Sstevel 	i2cxferp->i2c_flags = op;
541103831d35Sstevel 	i2cxferp->i2c_rlen = rlen;
541203831d35Sstevel 	i2cxferp->i2c_wlen = wlen;
541303831d35Sstevel 	i2cxferp->i2c_wbuf[0] = reg;
541403831d35Sstevel 	scsb->scsb_kstat_flag = B_TRUE;	/* we did a i2c transaction */
541503831d35Sstevel 	if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
541603831d35Sstevel 		error = EIO;
541703831d35Sstevel 	} else if (rlen) {
541803831d35Sstevel 		/* copy to rwbuf[] and keep shadow registers updated */
541903831d35Sstevel 		for (i = 0; i < len; ++i) {
542003831d35Sstevel 			scsb->scsb_data_reg[index + i] = rwbuf[i] =
542103831d35Sstevel 			    i2cxferp->i2c_rbuf[i];
542203831d35Sstevel 			if (scsb_debug & 0x0080)
542303831d35Sstevel 				cmn_err(CE_NOTE,
542403831d35Sstevel 				"scsb_rdwr_register: read rwbuf[%d]=0x%x",
542503831d35Sstevel 				    i, rwbuf[i]);
542603831d35Sstevel 		}
542703831d35Sstevel 	}
542803831d35Sstevel 	if (i2c_alloc)
542903831d35Sstevel 		scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
543003831d35Sstevel 	if (error) {
543103831d35Sstevel 		scsb->scsb_i2c_errcnt++;
543203831d35Sstevel 		if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
543303831d35Sstevel 			scsb->scsb_err_flag = B_TRUE; /* latch error */
543403831d35Sstevel 		if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
543503831d35Sstevel 			if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
543603831d35Sstevel 				scsb_freeze(scsb);
543703831d35Sstevel 			return (EAGAIN);
543803831d35Sstevel 		} else {
543903831d35Sstevel 			cmn_err(CE_WARN,
544003831d35Sstevel 			    "scsb_rdwr_register(): I2C read error from %x",
544103831d35Sstevel 			    reg);
544203831d35Sstevel 		}
544303831d35Sstevel 	} else {
544403831d35Sstevel 		scsb->scsb_i2c_errcnt = 0;
544503831d35Sstevel 	}
544603831d35Sstevel 
544703831d35Sstevel 	return (error);
544803831d35Sstevel }
544903831d35Sstevel 
545003831d35Sstevel /*
545103831d35Sstevel  * Called from scsb_intr()
545203831d35Sstevel  * First find the fru_info for this fru_id, and set fru_status for callback.
545303831d35Sstevel  * Then check for a registered call_back entry for this fru_id,
545403831d35Sstevel  * and if found, call it.
545503831d35Sstevel  * Recursize call until no EVENTS left in evcode.
545603831d35Sstevel  */
545703831d35Sstevel static	void
545803831d35Sstevel check_fru_info(scsb_state_t *scsb, int evcode)
545903831d35Sstevel {
546003831d35Sstevel 	struct scsb_cb_entry	*cbe_ptr;
546103831d35Sstevel 	fru_info_t		*fru_ptr;
546203831d35Sstevel 	fru_id_t		fru_id;
546303831d35Sstevel 	scsb_fru_status_t	fru_status;
546403831d35Sstevel 	int			i, new_evcode;
546503831d35Sstevel 
546603831d35Sstevel 	if (scsb_debug & 0x00100001)
546703831d35Sstevel 		cmn_err(CE_NOTE, "check_fru_info(scsb,0x%x)", evcode);
546803831d35Sstevel 	if (evcode == 0)
546903831d35Sstevel 		return;
547003831d35Sstevel 	i = event_to_index((uint32_t)evcode);
547103831d35Sstevel 	new_evcode = evcode & ~(1 << i);
547203831d35Sstevel 	if (i > MCT_MAX_FRUS) {
547303831d35Sstevel 		if (scsb_debug & 0x00100000)
547403831d35Sstevel 			cmn_err(CE_NOTE,
547503831d35Sstevel 			    "check_fru_info: index %d out of range", i);
547603831d35Sstevel 		check_fru_info(scsb, new_evcode);
547703831d35Sstevel 		return;
547803831d35Sstevel 	}
547903831d35Sstevel 	fru_id = fru_id_table[i];
548003831d35Sstevel 	fru_ptr = find_fru_info(fru_id);
548103831d35Sstevel 	if (fru_ptr == (fru_info_t *)NULL) {
548203831d35Sstevel 		check_fru_info(scsb, new_evcode);
548303831d35Sstevel 		return;
548403831d35Sstevel 	}
548503831d35Sstevel 	update_fru_info(scsb, fru_ptr);
548603831d35Sstevel 	if (fru_ptr->fru_status & FRU_PRESENT) {
548703831d35Sstevel 		fru_status = FRU_PRESENT;
548803831d35Sstevel 	} else {
548903831d35Sstevel 		fru_status = FRU_NOT_PRESENT;
549003831d35Sstevel 		if (fru_ptr->fru_type == SSB) {
549103831d35Sstevel 			/*
549203831d35Sstevel 			 * WARN against SCB removal if any
549303831d35Sstevel 			 * occupied slots are in reset
549403831d35Sstevel 			 */
549503831d35Sstevel 			scsb_freeze_check(scsb);
549603831d35Sstevel 		}
549703831d35Sstevel 	}
549803831d35Sstevel 	/*
549903831d35Sstevel 	 * check for an entry in the CallBack table
550003831d35Sstevel 	 */
550103831d35Sstevel 	for (cbe_ptr = scsb_cb_table; cbe_ptr != NULL;
550203831d35Sstevel 	    cbe_ptr = cbe_ptr->cb_next) {
550303831d35Sstevel 		if (cbe_ptr->cb_fru_id == fru_id &&
550403831d35Sstevel 		    cbe_ptr->cb_fru_ptr == fru_ptr) {
550503831d35Sstevel 			if (scsb_debug & 0x00800000)
550603831d35Sstevel 				cmn_err(CE_NOTE,
550703831d35Sstevel 				    "check_fru_info: callback for FRU_ID "
550803831d35Sstevel 				    "0x%x; device is %spresent",
550903831d35Sstevel 				    (int)fru_id,
551003831d35Sstevel 				    fru_status == FRU_PRESENT ?
551103831d35Sstevel 				    "" : "not ");
551203831d35Sstevel 			(*cbe_ptr->cb_func)(
551303831d35Sstevel 			    cbe_ptr->cb_softstate_ptr,
551403831d35Sstevel 			    cbe_ptr->cb_event,
551503831d35Sstevel 			    fru_status);
551603831d35Sstevel 			break;
551703831d35Sstevel 		}
551803831d35Sstevel 	}
551903831d35Sstevel 	check_fru_info(scsb, new_evcode);
552003831d35Sstevel }
552103831d35Sstevel 
552203831d35Sstevel /*
552303831d35Sstevel  * -----------------------------
552403831d35Sstevel  * scsb kstat support functions.
552503831d35Sstevel  * -----------------------------
552603831d35Sstevel  */
552703831d35Sstevel /*
552803831d35Sstevel  * Create and initialize the kstat data structures
552903831d35Sstevel  */
553003831d35Sstevel static int
553103831d35Sstevel scsb_alloc_kstats(scsb_state_t *scsb)
553203831d35Sstevel {
553303831d35Sstevel 	kstat_named_t   *kn;
553403831d35Sstevel 	/*
553503831d35Sstevel 	 * scsb_ks_leddata_t for "scsb_leddata"
553603831d35Sstevel 	 */
553703831d35Sstevel 	if (scsb_debug & 0x00080001)
553803831d35Sstevel 		cmn_err(CE_NOTE,
553903831d35Sstevel 		    "scsb_alloc_kstats: create scsb_leddata: %lu bytes",
554003831d35Sstevel 		    sizeof (scsb_ks_leddata_t));
554103831d35Sstevel 	if ((scsb->ks_leddata = kstat_create(scsb_name, scsb->scsb_instance,
554203831d35Sstevel 	    SCSB_KS_LEDDATA, "misc", KSTAT_TYPE_RAW,
554303831d35Sstevel 	    sizeof (scsb_ks_leddata_t), KSTAT_FLAG_PERSISTENT))
554403831d35Sstevel 	    == NULL) {
554503831d35Sstevel 		scsb->scsb_state |= SCSB_KSTATS;
554603831d35Sstevel 		scsb_free_kstats(scsb);
554703831d35Sstevel 		return (DDI_FAILURE);
554803831d35Sstevel 	}
554903831d35Sstevel 	scsb->ks_leddata->ks_update = update_ks_leddata;
555003831d35Sstevel 	scsb->ks_leddata->ks_private = (void *)scsb;
555103831d35Sstevel 	if (update_ks_leddata(scsb->ks_leddata, KSTAT_READ) != DDI_SUCCESS) {
555203831d35Sstevel 		scsb->scsb_state |= SCSB_KSTATS;
555303831d35Sstevel 		scsb_free_kstats(scsb);
555403831d35Sstevel 		return (DDI_FAILURE);
555503831d35Sstevel 	}
555603831d35Sstevel 	kstat_install(scsb->ks_leddata);
555703831d35Sstevel 	/*
555803831d35Sstevel 	 * scsb_ks_state_t for "scsb_state"
555903831d35Sstevel 	 */
556003831d35Sstevel 	if (scsb_debug & 0x00080000)
556103831d35Sstevel 		cmn_err(CE_NOTE,
556203831d35Sstevel 		    "scsb_alloc_kstats: create scsb_state: %lu bytes",
556303831d35Sstevel 		    sizeof (scsb_ks_state_t));
556403831d35Sstevel 	if ((scsb->ks_state = kstat_create(scsb_name, scsb->scsb_instance,
556503831d35Sstevel 	    SCSB_KS_STATE, "misc", KSTAT_TYPE_RAW,
556603831d35Sstevel 	    sizeof (scsb_ks_state_t), KSTAT_FLAG_PERSISTENT))
556703831d35Sstevel 	    == NULL) {
556803831d35Sstevel 		scsb->scsb_state |= SCSB_KSTATS;
556903831d35Sstevel 		scsb_free_kstats(scsb);
557003831d35Sstevel 		return (DDI_FAILURE);
557103831d35Sstevel 	}
557203831d35Sstevel 	scsb->ks_state->ks_update = update_ks_state;
557303831d35Sstevel 	scsb->ks_state->ks_private = (void *)scsb;
557403831d35Sstevel 	if (update_ks_state(scsb->ks_state, KSTAT_READ) != DDI_SUCCESS) {
557503831d35Sstevel 		scsb->scsb_state |= SCSB_KSTATS;
557603831d35Sstevel 		scsb_free_kstats(scsb);
557703831d35Sstevel 		return (DDI_FAILURE);
557803831d35Sstevel 	}
557903831d35Sstevel 	kstat_install(scsb->ks_state);
558003831d35Sstevel 	/*
558103831d35Sstevel 	 * mct_topology_t for "env_topology"
558203831d35Sstevel 	 */
558303831d35Sstevel 	if (scsb_debug & 0x00080000)
558403831d35Sstevel 		cmn_err(CE_NOTE,
558503831d35Sstevel 		    "scsb_alloc_kstats: create env_toploogy: %lu bytes",
558603831d35Sstevel 		    sizeof (mct_topology_t));
558703831d35Sstevel 	if ((scsb->ks_topology = kstat_create(scsb_name, scsb->scsb_instance,
558803831d35Sstevel 	    SCSB_KS_TOPOLOGY, "misc", KSTAT_TYPE_RAW,
558903831d35Sstevel 	    sizeof (mct_topology_t), KSTAT_FLAG_PERSISTENT))
559003831d35Sstevel 	    == NULL) {
559103831d35Sstevel 		scsb->scsb_state |= SCSB_KSTATS;
559203831d35Sstevel 		scsb_free_kstats(scsb);
559303831d35Sstevel 		return (DDI_FAILURE);
559403831d35Sstevel 	}
559503831d35Sstevel 	scsb->ks_topology->ks_update = update_ks_topology;
559603831d35Sstevel 	scsb->ks_topology->ks_private = (void *)scsb;
559703831d35Sstevel 	if (update_ks_topology(scsb->ks_topology, KSTAT_READ) != DDI_SUCCESS) {
559803831d35Sstevel 		scsb->scsb_state |= SCSB_KSTATS;
559903831d35Sstevel 		scsb_free_kstats(scsb);
560003831d35Sstevel 		return (DDI_FAILURE);
560103831d35Sstevel 	}
560203831d35Sstevel 	kstat_install(scsb->ks_topology);
560303831d35Sstevel 	/*
560403831d35Sstevel 	 * kstat_named_t * 2 for "scsb_evc_register"
560503831d35Sstevel 	 */
560603831d35Sstevel 	if (scsb_debug & 0x00080001)
560703831d35Sstevel 		cmn_err(CE_NOTE,
560803831d35Sstevel 		    "scsb_alloc_kstats: create scsb_evc_register: %lu bytes",
560903831d35Sstevel 		    sizeof (kstat_named_t) * 2);
561003831d35Sstevel 	if ((scsb->ks_evcreg = kstat_create(scsb_name, scsb->scsb_instance,
561103831d35Sstevel 	    SCSB_KS_EVC_REGISTER, "misc", KSTAT_TYPE_NAMED, 2,
561203831d35Sstevel 	    KSTAT_FLAG_PERSISTENT|KSTAT_FLAG_WRITABLE)) == NULL) {
561303831d35Sstevel 		scsb->scsb_state |= SCSB_KSTATS;
561403831d35Sstevel 		scsb_free_kstats(scsb);
561503831d35Sstevel 		return (DDI_FAILURE);
561603831d35Sstevel 	}
561703831d35Sstevel 	scsb->ks_evcreg->ks_update = update_ks_evcreg;
561803831d35Sstevel 	scsb->ks_evcreg->ks_private = (void *)scsb;
561903831d35Sstevel 	kn = KSTAT_NAMED_PTR(scsb->ks_evcreg);
562003831d35Sstevel 	kstat_named_init(&kn[0], "pid_register", KSTAT_DATA_INT64);
562103831d35Sstevel 	kstat_named_init(&kn[1], "pid_unregister", KSTAT_DATA_INT64);
562203831d35Sstevel 	kstat_install(scsb->ks_evcreg);
562303831d35Sstevel 	/*
562403831d35Sstevel 	 * Done, set the flag for scsb_detach() and other checks
562503831d35Sstevel 	 */
562603831d35Sstevel 	scsb->scsb_state |= SCSB_KSTATS;
562703831d35Sstevel 	return (DDI_SUCCESS);
562803831d35Sstevel }
562903831d35Sstevel 
563003831d35Sstevel static int
563103831d35Sstevel update_ks_leddata(kstat_t *ksp, int rw)
563203831d35Sstevel {
563303831d35Sstevel 	scsb_state_t		*scsb;
563403831d35Sstevel 	scsb_ks_leddata_t	*pks_leddata;
563503831d35Sstevel 	int			i, numregs, index, error = DDI_SUCCESS;
563603831d35Sstevel 	uchar_t			reg;
563703831d35Sstevel 
563803831d35Sstevel 	scsb = (scsb_state_t *)ksp->ks_private;
563903831d35Sstevel 	if (scsb_debug & 0x00080001)
564003831d35Sstevel 		cmn_err(CE_NOTE, "update_ks_leddata: KS_UPDATE%sset",
564103831d35Sstevel 		    scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
564203831d35Sstevel 	/*
564303831d35Sstevel 	 * Since this is satisfied from the shadow registers, let it succeed
564403831d35Sstevel 	 * even if the SCB is not present.  It would be nice to return the
564503831d35Sstevel 	 * shadow values with a warning.
564603831d35Sstevel 	 *
564703831d35Sstevel 	 * if (scsb->scsb_state & SCSB_FROZEN) {
564803831d35Sstevel 	 *	return (DDI_FAILURE);
564903831d35Sstevel 	 * }
565003831d35Sstevel 	 */
565103831d35Sstevel 	if (rw == KSTAT_WRITE) {
565203831d35Sstevel 		return (EACCES);
565303831d35Sstevel 	}
565403831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
565503831d35Sstevel 	while (scsb->scsb_state & SCSB_KS_UPDATE) {
565603831d35Sstevel 		if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
565703831d35Sstevel 			mutex_exit(&scsb->scsb_mutex);
565803831d35Sstevel 			return (EINTR);
565903831d35Sstevel 		}
566003831d35Sstevel 	}
566103831d35Sstevel 	scsb->scsb_state |= SCSB_KS_UPDATE;
566203831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
566303831d35Sstevel 	if (scsb_debug & 0x00080001)
566403831d35Sstevel 		cmn_err(CE_NOTE, "update_ks_leddata: updating data");
566503831d35Sstevel 	pks_leddata = (scsb_ks_leddata_t *)ksp->ks_data;
566603831d35Sstevel 	/*
566703831d35Sstevel 	 * Call tonga_slotnum_led_shift() for each register that
566803831d35Sstevel 	 * contains Slot 1-5 information, the first register at each base:
566903831d35Sstevel 	 * NOK_BASE, OK_BASE, BLINK_OK_BASE
567003831d35Sstevel 	 * XXX: breaking register table access rules by not using macros.
567103831d35Sstevel 	 */
567203831d35Sstevel 	/* NOK */
567303831d35Sstevel 	reg = SCSB_REG_ADDR(SCTRL_LED_NOK_BASE);
567403831d35Sstevel 	index = SCSB_REG_INDEX(reg);
567503831d35Sstevel 	numregs = SCTRL_LED_NOK_NUMREGS;
567603831d35Sstevel 	i = 0;
567703831d35Sstevel 	if (IS_SCB_P15)
567803831d35Sstevel 		reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]);
567903831d35Sstevel 	else
568003831d35Sstevel 		reg = scsb->scsb_data_reg[index];
568103831d35Sstevel 	pks_leddata->scb_led_regs[i] = reg;
568203831d35Sstevel 	for (++i, ++index; i < numregs; ++i, ++index)
568303831d35Sstevel 		pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index];
568403831d35Sstevel 	/* OK */
568503831d35Sstevel 	reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE);
568603831d35Sstevel 	index = SCSB_REG_INDEX(reg);
568703831d35Sstevel 	numregs += SCTRL_LED_OK_NUMREGS;
568803831d35Sstevel 	if (IS_SCB_P15)
568903831d35Sstevel 		reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]);
569003831d35Sstevel 	else
569103831d35Sstevel 		reg = scsb->scsb_data_reg[index];
569203831d35Sstevel 	pks_leddata->scb_led_regs[i] = reg;
569303831d35Sstevel 	for (++i, ++index; i < numregs; ++i, ++index)
569403831d35Sstevel 		pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index];
569503831d35Sstevel 	/* BLINK */
569603831d35Sstevel 	reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE);
569703831d35Sstevel 	index = SCSB_REG_INDEX(reg);
569803831d35Sstevel 	numregs += SCTRL_BLINK_NUMREGS;
569903831d35Sstevel 	if (IS_SCB_P15)
570003831d35Sstevel 		reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]);
570103831d35Sstevel 	else
570203831d35Sstevel 		reg = scsb->scsb_data_reg[index];
570303831d35Sstevel 	pks_leddata->scb_led_regs[i] = reg;
570403831d35Sstevel 	for (++i, ++index; i < numregs; ++i, ++index)
570503831d35Sstevel 		pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index];
570603831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
570703831d35Sstevel 	scsb->scsb_state &= ~SCSB_KS_UPDATE;
570803831d35Sstevel 	cv_signal(&scsb->scsb_cv);
570903831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
571003831d35Sstevel 	if (scsb_debug & 0x00080001)
571103831d35Sstevel 		cmn_err(CE_NOTE, "update_ks_leddata: returning");
571203831d35Sstevel 	return (error);
571303831d35Sstevel }
571403831d35Sstevel 
571503831d35Sstevel static int
571603831d35Sstevel update_ks_evcreg(kstat_t *ksp, int rw)
571703831d35Sstevel {
571803831d35Sstevel 	scsb_state_t		*scsb;
571903831d35Sstevel 	int			error = 0;
572003831d35Sstevel 	kstat_named_t		*kn = KSTAT_NAMED_PTR(ksp);
572103831d35Sstevel 	pid_t			pid;
572203831d35Sstevel 
572303831d35Sstevel 	scsb = (scsb_state_t *)ksp->ks_private;
572403831d35Sstevel 	if (scsb_debug & 0x00080001)
572503831d35Sstevel 		cmn_err(CE_NOTE, "update_ks_evcreg: %s(%d), KS_UPDATE%sset",
572603831d35Sstevel 		    rw == KSTAT_READ ? "read" : "write", rw,
572703831d35Sstevel 		    scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
572803831d35Sstevel 	/*
572903831d35Sstevel 	 * Let this registration succeed
573003831d35Sstevel 	 *
573103831d35Sstevel 	 * if (scsb->scsb_state & SCSB_FROZEN) {
573203831d35Sstevel 	 *	return (DDI_FAILURE);
573303831d35Sstevel 	 * }
573403831d35Sstevel 	 */
573503831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
573603831d35Sstevel 	while (scsb->scsb_state & SCSB_KS_UPDATE) {
573703831d35Sstevel 		if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
573803831d35Sstevel 			mutex_exit(&scsb->scsb_mutex);
573903831d35Sstevel 			return (EINTR);
574003831d35Sstevel 		}
574103831d35Sstevel 	}
574203831d35Sstevel 	scsb->scsb_state |= SCSB_KS_UPDATE;
574303831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
574403831d35Sstevel 	if (rw == KSTAT_READ) {
574503831d35Sstevel 		kn[0].value.i64 = (int64_t)0;
574603831d35Sstevel 		kn[1].value.i64 = (int64_t)0;
574703831d35Sstevel 	} else if (rw == KSTAT_WRITE) {
574803831d35Sstevel 		/*
574903831d35Sstevel 		 * kn[0] is "pid_register", kn[1] is "pid_unregister"
575003831d35Sstevel 		 */
575103831d35Sstevel 		if (kn[0].value.i64 != 0 && kn[1].value.i64 == 0) {
575203831d35Sstevel 			pid = (pid_t)kn[0].value.i64;
575303831d35Sstevel 			if (add_event_proc(scsb, pid)) {
575403831d35Sstevel 				if (scsb_debug & 0x02000002) {
575503831d35Sstevel 					cmn_err(CE_WARN,
575603831d35Sstevel 					    "update_ks_evcreg: "
575703831d35Sstevel 					    "process add failed for %d",
575803831d35Sstevel 					    pid);
575903831d35Sstevel 				}
576003831d35Sstevel 				error = EOVERFLOW;
576103831d35Sstevel 			}
576203831d35Sstevel 		} else if (kn[0].value.i64 == 0 && kn[1].value.i64 != 0) {
576303831d35Sstevel 			pid = (pid_t)kn[1].value.i64;
576403831d35Sstevel 			if (del_event_proc(scsb, pid)) {
576503831d35Sstevel 				if (scsb_debug & 0x02000000) {
576603831d35Sstevel 					cmn_err(CE_NOTE,
576703831d35Sstevel 					    "update_ks_evcreg: "
576803831d35Sstevel 					    "process delete failed for %d",
576903831d35Sstevel 					    pid);
577003831d35Sstevel 				}
577103831d35Sstevel 				error = EOVERFLOW;
577203831d35Sstevel 			}
577303831d35Sstevel 		} else if (kn[0].value.i64 == 0 && kn[1].value.i64 == 0) {
577403831d35Sstevel 			/*
577503831d35Sstevel 			 * rewind the pointers and counts, zero the table.
577603831d35Sstevel 			 */
577703831d35Sstevel 			rew_event_proc(scsb);
577803831d35Sstevel 		} else {
577903831d35Sstevel 			error = EINVAL;
578003831d35Sstevel 		}
578103831d35Sstevel 	} else {
578203831d35Sstevel 		error = EINVAL;
578303831d35Sstevel 	}
578403831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
578503831d35Sstevel 	scsb->scsb_state &= ~SCSB_KS_UPDATE;
578603831d35Sstevel 	cv_signal(&scsb->scsb_cv);
578703831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
578803831d35Sstevel 	return (error);
578903831d35Sstevel }
579003831d35Sstevel 
579103831d35Sstevel static int
579203831d35Sstevel update_ks_state(kstat_t *ksp, int rw)
579303831d35Sstevel {
579403831d35Sstevel 	scsb_state_t		*scsb;
579503831d35Sstevel 	scsb_ks_state_t		*pks_state;
579603831d35Sstevel 	int			error = DDI_SUCCESS;
579703831d35Sstevel 	uint32_t		current_evc;
579803831d35Sstevel 
579903831d35Sstevel 	scsb = (scsb_state_t *)ksp->ks_private;
580003831d35Sstevel 	if (scsb_debug & 0x00080001)
580103831d35Sstevel 		cmn_err(CE_NOTE, "update_ks_state: KS_UPDATE%sset",
580203831d35Sstevel 		    scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
580303831d35Sstevel 	/*
580403831d35Sstevel 	 * Let this succeed based on last known data
580503831d35Sstevel 	 *
580603831d35Sstevel 	 * if (scsb->scsb_state & SCSB_FROZEN) {
580703831d35Sstevel 	 *	return (DDI_FAILURE);
580803831d35Sstevel 	 * }
580903831d35Sstevel 	 */
581003831d35Sstevel 	if (rw == KSTAT_WRITE) {
581103831d35Sstevel 		return (EACCES);
581203831d35Sstevel 	}
581303831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
581403831d35Sstevel 	while (scsb->scsb_state & SCSB_KS_UPDATE) {
581503831d35Sstevel 		if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
581603831d35Sstevel 			mutex_exit(&scsb->scsb_mutex);
581703831d35Sstevel 			return (EINTR);
581803831d35Sstevel 		}
581903831d35Sstevel 	}
582003831d35Sstevel 	scsb->scsb_state |= SCSB_KS_UPDATE;
582103831d35Sstevel 	/*
582203831d35Sstevel 	 * If SSB not present and scsb not SCSB_FROZEN, check for SCB presence
582303831d35Sstevel 	 * by initiating an I2C read from the SCB.  If an error occurs,
582403831d35Sstevel 	 * scsb_freeze() will be called to update SCB info and scsb state.
582503831d35Sstevel 	 */
582603831d35Sstevel 	if (!(scsb->scsb_state & SCSB_SSB_PRESENT) &&
582703831d35Sstevel 	    !(scsb->scsb_state & SCSB_FROZEN)) {
582803831d35Sstevel 		uchar_t		data;
582903831d35Sstevel 		/* Read the SCB PROM ID */
583003831d35Sstevel 		if (data = scsb_rdwr_register(scsb, I2C_WR_RD,
583103831d35Sstevel 		    (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1))
583203831d35Sstevel 			if (scsb_debug & 0x00080002)
583303831d35Sstevel 				cmn_err(CE_NOTE, "update_ks_state: SCB/I2C "
583403831d35Sstevel 				    "failure %d", data);
583503831d35Sstevel 	}
583603831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
583703831d35Sstevel 	pks_state = (scsb_ks_state_t *)ksp->ks_data;
583803831d35Sstevel 	pks_state->scb_present = (scsb->scsb_state & SCSB_SCB_PRESENT) ? 1 : 0;
583903831d35Sstevel 	pks_state->ssb_present = (scsb->scsb_state & SCSB_SSB_PRESENT) ? 1 : 0;
584003831d35Sstevel 	pks_state->scsb_frozen = (scsb->scsb_state & SCSB_FROZEN) ? 1 : 0;
584103831d35Sstevel 	if (scsb->scsb_state & SCSB_DEBUG_MODE)
584203831d35Sstevel 		pks_state->scsb_mode = (uint8_t)ENVC_DEBUG_MODE;
584303831d35Sstevel 	else if (scsb->scsb_state & SCSB_DIAGS_MODE)
584403831d35Sstevel 		pks_state->scsb_mode = (uint8_t)ENVCTRL_DIAG_MODE;
584503831d35Sstevel 	else
584603831d35Sstevel 		pks_state->scsb_mode = (uint8_t)ENVCTRL_NORMAL_MODE;
584703831d35Sstevel 	/*
584803831d35Sstevel 	 * If scsb_attach() has not completed the kstat installs,
584903831d35Sstevel 	 * then there are no event processes to check for.
585003831d35Sstevel 	 */
585103831d35Sstevel 	if (scsb->scsb_state & SCSB_KSTATS) {
585203831d35Sstevel 		switch (check_event_procs(&current_evc)) {
585303831d35Sstevel 		case EVC_NO_EVENT_CODE:
585403831d35Sstevel 			pks_state->event_code = 0;
585503831d35Sstevel 			break;
585603831d35Sstevel 		case EVC_NEW_EVENT_CODE:
585703831d35Sstevel 		/* FALLTHROUGH */
585803831d35Sstevel 		case EVC_NO_CURR_PROC:
585903831d35Sstevel 			pks_state->event_code = current_evc;
586003831d35Sstevel 			break;
586103831d35Sstevel 		case EVC_OR_EVENT_CODE:
586203831d35Sstevel 			pks_state->event_code |= current_evc;
586303831d35Sstevel 			break;
586403831d35Sstevel 		case EVC_FAILURE:
586503831d35Sstevel 			pks_state->event_code = 0;
586603831d35Sstevel 			error = DDI_FAILURE;
586703831d35Sstevel 			break;
586803831d35Sstevel 		}
586903831d35Sstevel 	} else {
587003831d35Sstevel 		pks_state->event_code = 0;
587103831d35Sstevel 	}
587203831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
587303831d35Sstevel 	scsb->scsb_state &= ~SCSB_KS_UPDATE;
587403831d35Sstevel 	cv_signal(&scsb->scsb_cv);
587503831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
587603831d35Sstevel 	return (error);
587703831d35Sstevel }
587803831d35Sstevel 
587903831d35Sstevel static int
588003831d35Sstevel update_ks_topology(kstat_t *ksp, int rw)
588103831d35Sstevel {
588203831d35Sstevel 	scsb_state_t		*scsb;
588303831d35Sstevel 	mct_topology_t		*pks_topo;
588403831d35Sstevel 	fru_info_t		*fru_ptr;
588503831d35Sstevel 	int			i, val, error = DDI_SUCCESS, slotnum;
588603831d35Sstevel 
588703831d35Sstevel 	scsb = (scsb_state_t *)ksp->ks_private;
588803831d35Sstevel 	if (scsb_debug & 0x00080001)
588903831d35Sstevel 		cmn_err(CE_NOTE, "update_ks_topology: KS_UPDATE%sset",
589003831d35Sstevel 		    scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
589103831d35Sstevel 	/*
589203831d35Sstevel 	 * Let this succeed based on last known data
589303831d35Sstevel 	 *
589403831d35Sstevel 	 * if (scsb->scsb_state & SCSB_FROZEN) {
589503831d35Sstevel 	 *	return (DDI_FAILURE);
589603831d35Sstevel 	 * }
589703831d35Sstevel 	 */
589803831d35Sstevel 	if (rw == KSTAT_WRITE) {
589903831d35Sstevel 		return (EACCES);
590003831d35Sstevel 	}
590103831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
590203831d35Sstevel 	while (scsb->scsb_state & SCSB_KS_UPDATE) {
590303831d35Sstevel 		if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
590403831d35Sstevel 			mutex_exit(&scsb->scsb_mutex);
590503831d35Sstevel 			return (EINTR);
590603831d35Sstevel 		}
590703831d35Sstevel 	}
590803831d35Sstevel 	scsb->scsb_state |= SCSB_KS_UPDATE;
590903831d35Sstevel 	/*
591003831d35Sstevel 	 * If SSB not present and scsb not SCSB_FROZEN, check for SCB presence
591103831d35Sstevel 	 * by initiating an I2C read from the SCB.  If an error occurs,
591203831d35Sstevel 	 * scsb_freeze() will be called to update SCB info and scsb state.
591303831d35Sstevel 	 */
591403831d35Sstevel 	if (!(scsb->scsb_state & SCSB_SSB_PRESENT) &&
591503831d35Sstevel 	    !(scsb->scsb_state & SCSB_FROZEN)) {
591603831d35Sstevel 		uchar_t		data;
591703831d35Sstevel 		/* Read the SCB PROM ID */
591803831d35Sstevel 		if (data = scsb_rdwr_register(scsb, I2C_WR_RD,
591903831d35Sstevel 		    (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1))
592003831d35Sstevel 			if (scsb_debug & 0x00080002)
592103831d35Sstevel 				cmn_err(CE_NOTE, "update_ks_topology: SCB/I2C "
592203831d35Sstevel 				    "failure %d", data);
592303831d35Sstevel 	}
592403831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
592503831d35Sstevel 	pks_topo = (mct_topology_t *)ksp->ks_data;
592603831d35Sstevel 	for (i = SLOT; i < SCSB_UNIT_TYPES; ++i) {
592703831d35Sstevel 		pks_topo->max_units[i] = mct_system_info.max_units[i];
592803831d35Sstevel 	}
592903831d35Sstevel 
593003831d35Sstevel 	pks_topo->mid_plane.fru_status = FRU_PRESENT;
593103831d35Sstevel 	pks_topo->mid_plane.fru_unit = (scsb_unum_t)1;
593203831d35Sstevel 	pks_topo->mid_plane.fru_type = mct_system_info.mid_plane.fru_type;
593303831d35Sstevel 	pks_topo->mid_plane.fru_id = mct_system_info.mid_plane.fru_id;
593403831d35Sstevel 	pks_topo->mid_plane.fru_version = mct_system_info.mid_plane.fru_version;
593503831d35Sstevel 	pks_topo->mid_plane.fru_health = MCT_HEALTH_OK;
593603831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[SLOT];
593703831d35Sstevel 	for (i = 0; i < pks_topo->max_units[SLOT]; ++i, ++fru_ptr) {
593803831d35Sstevel 		pks_topo->mct_slots[i].fru_status = fru_ptr->fru_status;
593903831d35Sstevel 		pks_topo->mct_slots[i].fru_type = fru_ptr->fru_type;
594003831d35Sstevel 		pks_topo->mct_slots[i].fru_unit = fru_ptr->fru_unit;
594103831d35Sstevel 		pks_topo->mct_slots[i].fru_id = fru_ptr->fru_id;
594203831d35Sstevel 		pks_topo->mct_slots[i].fru_version = fru_ptr->fru_version;
594303831d35Sstevel 		/*
594403831d35Sstevel 		 * XXX: need to check healthy regs to set fru_health
594503831d35Sstevel 		 */
594603831d35Sstevel 		slotnum = tonga_psl_to_ssl(scsb, i+1);
594703831d35Sstevel 		val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
594803831d35Sstevel 		    SCSB_FRU_OP_GET_BITVAL);
594903831d35Sstevel 		pks_topo->mct_slots[i].fru_health = (val) ?
595003831d35Sstevel 		    MCT_HEALTH_OK : MCT_HEALTH_NOK;
595103831d35Sstevel 	}
595203831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[PDU];
595303831d35Sstevel 	for (i = 0; i < pks_topo->max_units[PDU]; ++i, ++fru_ptr) {
595403831d35Sstevel 		pks_topo->mct_pdu[i].fru_status = fru_ptr->fru_status;
595503831d35Sstevel 		pks_topo->mct_pdu[i].fru_type = fru_ptr->fru_type;
595603831d35Sstevel 		pks_topo->mct_pdu[i].fru_unit = fru_ptr->fru_unit;
595703831d35Sstevel 		pks_topo->mct_pdu[i].fru_id = fru_ptr->fru_id;
595803831d35Sstevel 		pks_topo->mct_pdu[i].fru_version = fru_ptr->fru_version;
595903831d35Sstevel 		pks_topo->mct_pdu[i].fru_health = MCT_HEALTH_NA;
596003831d35Sstevel 	}
596103831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[PS];
596203831d35Sstevel 	for (i = 0; i < pks_topo->max_units[PS]; ++i, ++fru_ptr) {
596303831d35Sstevel 		pks_topo->mct_ps[i].fru_status = fru_ptr->fru_status;
596403831d35Sstevel 		pks_topo->mct_ps[i].fru_type = fru_ptr->fru_type;
596503831d35Sstevel 		pks_topo->mct_ps[i].fru_unit = fru_ptr->fru_unit;
596603831d35Sstevel 		pks_topo->mct_ps[i].fru_id = fru_ptr->fru_id;
596703831d35Sstevel 		pks_topo->mct_ps[i].fru_version = fru_ptr->fru_version;
596803831d35Sstevel 		pks_topo->mct_ps[i].fru_health = MCT_HEALTH_NA;
596903831d35Sstevel 	}
597003831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[DISK];
597103831d35Sstevel 	for (i = 0; i < pks_topo->max_units[DISK]; ++i, ++fru_ptr) {
597203831d35Sstevel 		pks_topo->mct_disk[i].fru_status = fru_ptr->fru_status;
597303831d35Sstevel 		pks_topo->mct_disk[i].fru_type = fru_ptr->fru_type;
597403831d35Sstevel 		pks_topo->mct_disk[i].fru_unit = fru_ptr->fru_unit;
597503831d35Sstevel 		pks_topo->mct_disk[i].fru_id = fru_ptr->fru_id;
597603831d35Sstevel 		pks_topo->mct_disk[i].fru_version = fru_ptr->fru_version;
597703831d35Sstevel 		pks_topo->mct_disk[i].fru_health = MCT_HEALTH_NA;
597803831d35Sstevel 	}
597903831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[FAN];
598003831d35Sstevel 	for (i = 0; i < pks_topo->max_units[FAN]; ++i, ++fru_ptr) {
598103831d35Sstevel 		pks_topo->mct_fan[i].fru_status = fru_ptr->fru_status;
598203831d35Sstevel 		pks_topo->mct_fan[i].fru_type = fru_ptr->fru_type;
598303831d35Sstevel 		pks_topo->mct_fan[i].fru_unit = fru_ptr->fru_unit;
598403831d35Sstevel 		pks_topo->mct_fan[i].fru_id = fru_ptr->fru_id;
598503831d35Sstevel 		pks_topo->mct_fan[i].fru_version = fru_ptr->fru_version;
598603831d35Sstevel 		pks_topo->mct_fan[i].fru_health = MCT_HEALTH_NA;
598703831d35Sstevel 	}
598803831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[SCB];
598903831d35Sstevel 	for (i = 0; i < pks_topo->max_units[SCB]; ++i, ++fru_ptr) {
599003831d35Sstevel 		pks_topo->mct_scb[i].fru_status = fru_ptr->fru_status;
599103831d35Sstevel 		pks_topo->mct_scb[i].fru_type = fru_ptr->fru_type;
599203831d35Sstevel 		pks_topo->mct_scb[i].fru_unit = fru_ptr->fru_unit;
599303831d35Sstevel 		pks_topo->mct_scb[i].fru_id = fru_ptr->fru_id;
599403831d35Sstevel 		pks_topo->mct_scb[i].fru_version = fru_ptr->fru_version;
599503831d35Sstevel 		/*
599603831d35Sstevel 		 * To get the scsb health, if there was no i2c transaction
599703831d35Sstevel 		 * until this read, generate an i2c transaction.
599803831d35Sstevel 		 */
599903831d35Sstevel 		if (scsb->scsb_kstat_flag == B_FALSE) {
600003831d35Sstevel 			uchar_t		data;
6001*07d06da5SSurya Prakki 			(void) scsb_blind_read(scsb, I2C_WR_RD,
600203831d35Sstevel 			    (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1);
600303831d35Sstevel 		}
600403831d35Sstevel 		pks_topo->mct_scb[i].fru_health = ((scsb->scsb_err_flag ==
600503831d35Sstevel 		    B_TRUE || scsb->scsb_i2c_errcnt > scsb_err_threshold)
600603831d35Sstevel 		    ?  MCT_HEALTH_NOK : MCT_HEALTH_OK);
600703831d35Sstevel #ifdef DEBUG
600803831d35Sstevel 		if (pks_topo->mct_scb[i].fru_health == MCT_HEALTH_NOK)
600903831d35Sstevel 			cmn_err(CE_WARN, "SCSB kstat health:%d", pks_topo->
601003831d35Sstevel 			    mct_scb[i].fru_health);
601103831d35Sstevel #endif
601203831d35Sstevel 		scsb->scsb_err_flag = B_FALSE; /* clear error flag once read */
601303831d35Sstevel 		scsb->scsb_kstat_flag = B_FALSE; /* false? read from i2c */
601403831d35Sstevel 	}
601503831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[SSB];
601603831d35Sstevel 	for (i = 0; i < pks_topo->max_units[SSB]; ++i, ++fru_ptr) {
601703831d35Sstevel 		pks_topo->mct_ssb[i].fru_status = fru_ptr->fru_status;
601803831d35Sstevel 		pks_topo->mct_ssb[i].fru_type = fru_ptr->fru_type;
601903831d35Sstevel 		pks_topo->mct_ssb[i].fru_unit = fru_ptr->fru_unit;
602003831d35Sstevel 		pks_topo->mct_ssb[i].fru_id = fru_ptr->fru_id;
602103831d35Sstevel 		pks_topo->mct_ssb[i].fru_version = fru_ptr->fru_version;
602203831d35Sstevel 		pks_topo->mct_ssb[i].fru_health = MCT_HEALTH_NA;
602303831d35Sstevel 	}
602403831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[ALARM];
602503831d35Sstevel 	for (i = 0; i < pks_topo->max_units[ALARM]; ++i, ++fru_ptr) {
602603831d35Sstevel 		pks_topo->mct_alarm[i].fru_status = fru_ptr->fru_status;
602703831d35Sstevel 		pks_topo->mct_alarm[i].fru_type = fru_ptr->fru_type;
602803831d35Sstevel 		pks_topo->mct_alarm[i].fru_unit = fru_ptr->fru_unit;
602903831d35Sstevel 		pks_topo->mct_alarm[i].fru_id = fru_ptr->fru_id;
603003831d35Sstevel 		pks_topo->mct_alarm[i].fru_version = fru_ptr->fru_version;
603103831d35Sstevel 		pks_topo->mct_alarm[i].fru_health = MCT_HEALTH_NA;
603203831d35Sstevel 	}
603303831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[CFTM];
603403831d35Sstevel 	for (i = 0; i < pks_topo->max_units[CFTM]; ++i, ++fru_ptr) {
603503831d35Sstevel 		pks_topo->mct_cftm[i].fru_status = fru_ptr->fru_status;
603603831d35Sstevel 		pks_topo->mct_cftm[i].fru_type = fru_ptr->fru_type;
603703831d35Sstevel 		pks_topo->mct_cftm[i].fru_unit = fru_ptr->fru_unit;
603803831d35Sstevel 		pks_topo->mct_cftm[i].fru_id = fru_ptr->fru_id;
603903831d35Sstevel 		pks_topo->mct_cftm[i].fru_version = fru_ptr->fru_version;
604003831d35Sstevel 		pks_topo->mct_cftm[i].fru_health = MCT_HEALTH_NA;
604103831d35Sstevel 	}
604203831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[CRTM];
604303831d35Sstevel 	for (i = 0; i < pks_topo->max_units[CRTM]; ++i, ++fru_ptr) {
604403831d35Sstevel 		pks_topo->mct_crtm[i].fru_status = fru_ptr->fru_status;
604503831d35Sstevel 		pks_topo->mct_crtm[i].fru_type = fru_ptr->fru_type;
604603831d35Sstevel 		pks_topo->mct_crtm[i].fru_unit = fru_ptr->fru_unit;
604703831d35Sstevel 		pks_topo->mct_crtm[i].fru_id = fru_ptr->fru_id;
604803831d35Sstevel 		pks_topo->mct_crtm[i].fru_version = fru_ptr->fru_version;
604903831d35Sstevel 		pks_topo->mct_crtm[i].fru_health = MCT_HEALTH_NA;
605003831d35Sstevel 	}
605103831d35Sstevel 	fru_ptr = mct_system_info.fru_info_list[PRTM];
605203831d35Sstevel 	for (i = 0; i < pks_topo->max_units[PRTM]; ++i, ++fru_ptr) {
605303831d35Sstevel 		pks_topo->mct_prtm[i].fru_status = fru_ptr->fru_status;
605403831d35Sstevel 		pks_topo->mct_prtm[i].fru_type = fru_ptr->fru_type;
605503831d35Sstevel 		pks_topo->mct_prtm[i].fru_unit = fru_ptr->fru_unit;
605603831d35Sstevel 		pks_topo->mct_prtm[i].fru_id = fru_ptr->fru_id;
605703831d35Sstevel 		pks_topo->mct_prtm[i].fru_version = fru_ptr->fru_version;
605803831d35Sstevel 		pks_topo->mct_prtm[i].fru_health = MCT_HEALTH_NA;
605903831d35Sstevel 	}
606003831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
606103831d35Sstevel 	scsb->scsb_state &= ~SCSB_KS_UPDATE;
606203831d35Sstevel 	cv_signal(&scsb->scsb_cv);
606303831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
606403831d35Sstevel 	return (error);
606503831d35Sstevel }
606603831d35Sstevel 
606703831d35Sstevel static void
606803831d35Sstevel scsb_free_kstats(scsb_state_t *scsb)
606903831d35Sstevel {
607003831d35Sstevel 	if (!(scsb->scsb_state & SCSB_KSTATS))
607103831d35Sstevel 		return;
607203831d35Sstevel 	/*
607303831d35Sstevel 	 * free the allocated kstat data
607403831d35Sstevel 	 */
607503831d35Sstevel 	if (scsb->ks_evcreg != NULL) {
607603831d35Sstevel 		kstat_delete(scsb->ks_evcreg);
607703831d35Sstevel 	}
607803831d35Sstevel 	if (scsb->ks_topology != NULL) {
607903831d35Sstevel 		kstat_delete(scsb->ks_topology);
608003831d35Sstevel 	}
608103831d35Sstevel 	if (scsb->ks_state != NULL) {
608203831d35Sstevel 		kstat_delete(scsb->ks_state);
608303831d35Sstevel 	}
608403831d35Sstevel 	if (scsb->ks_leddata != NULL) {
608503831d35Sstevel 		kstat_delete(scsb->ks_leddata);
608603831d35Sstevel 	}
608703831d35Sstevel 	scsb->ks_leddata = NULL;
608803831d35Sstevel 	scsb->ks_state = NULL;
608903831d35Sstevel 	scsb->ks_topology = NULL;
609003831d35Sstevel 	scsb->ks_evcreg = NULL;
609103831d35Sstevel 	scsb->scsb_state &= ~SCSB_KSTATS;
609203831d35Sstevel }
609303831d35Sstevel 
609403831d35Sstevel 
609503831d35Sstevel /*
609603831d35Sstevel  * --------------------------------------
609703831d35Sstevel  * Miscellaneous scsb internal functions.
609803831d35Sstevel  * --------------------------------------
609903831d35Sstevel  *
610003831d35Sstevel  * allocate I2C transfer structure
610103831d35Sstevel  */
610203831d35Sstevel static i2c_transfer_t *
610303831d35Sstevel scsb_alloc_i2ctx(i2c_client_hdl_t phandle, uint_t sleep)
610403831d35Sstevel {
610503831d35Sstevel 	i2c_transfer_t	*tp;
610603831d35Sstevel 
610703831d35Sstevel 	if (i2c_transfer_alloc(phandle, &tp, SCSB_DATA_REGISTERS + 2,
610803831d35Sstevel 	    SCSB_DATA_REGISTERS + 2, sleep) == I2C_FAILURE) {
610903831d35Sstevel 		return (NULL);
611003831d35Sstevel 	}
611103831d35Sstevel 	return (tp);
611203831d35Sstevel }
611303831d35Sstevel 
611403831d35Sstevel /*
611503831d35Sstevel  * free I2C transfer structure
611603831d35Sstevel  */
611703831d35Sstevel static void
611803831d35Sstevel scsb_free_i2ctx(i2c_client_hdl_t phandle, i2c_transfer_t *tp)
611903831d35Sstevel {
612003831d35Sstevel 	i2c_transfer_free(phandle, tp);
612103831d35Sstevel }
612203831d35Sstevel 
612303831d35Sstevel static	void
612403831d35Sstevel update_fru_info(scsb_state_t *scsb, fru_info_t *fru_ptr)
612503831d35Sstevel {
612603831d35Sstevel 	int		index;
612703831d35Sstevel 	uchar_t		reg, bit;
612803831d35Sstevel 	fru_info_t	*acslot_ptr = NULL;
612903831d35Sstevel 	fru_id_t	acslot_id = 0;
613003831d35Sstevel 	if (scsb_debug & 0x00100001)
6131*07d06da5SSurya Prakki 		cmn_err(CE_NOTE, "update_fru_info(scsb,0x%p)", (void *)fru_ptr);
613203831d35Sstevel 	if (fru_ptr == (fru_info_t *)NULL ||
613303831d35Sstevel 	    fru_ptr->i2c_info == (fru_i2c_info_t *)NULL)
613403831d35Sstevel 		return;
613503831d35Sstevel 	/*
613603831d35Sstevel 	 * If this is an Alarm Card update, then we also need to get
613703831d35Sstevel 	 * Alarm Card Slot fru_ptr to update it's fru_type, and maybe fru_id
613803831d35Sstevel 	 */
613903831d35Sstevel 	if (fru_ptr->fru_id == fru_id_table[FRU_INDEX(SCTRL_EVENT_ALARM)]) {
614003831d35Sstevel 		/*
614103831d35Sstevel 		 * SCTRL_EVENT_SLOT1 == 0x01 so
614203831d35Sstevel 		 * fru_id_table[] index for Slot 1 == 0
614303831d35Sstevel 		 */
614403831d35Sstevel 		acslot_id = fru_id_table[(scsb->ac_slotnum - 1)];
614503831d35Sstevel 		acslot_ptr = find_fru_info(acslot_id);
614603831d35Sstevel 	}
614703831d35Sstevel 	reg = fru_ptr->i2c_info->syscfg_reg;
614803831d35Sstevel 	bit = fru_ptr->i2c_info->syscfg_bit;
614903831d35Sstevel 	if (reg == 0 && fru_ptr->fru_type == SCB) {
615003831d35Sstevel 		if (scsb->scsb_state & SCSB_SCB_PRESENT)
615103831d35Sstevel 			fru_ptr->fru_status = FRU_PRESENT;
615203831d35Sstevel 		else
615303831d35Sstevel 			fru_ptr->fru_status = FRU_NOT_PRESENT;
615403831d35Sstevel 	} else if (reg) {
615503831d35Sstevel 		index = SCSB_REG_INDEX(reg);
615603831d35Sstevel 		if (scsb->scsb_data_reg[index] & (1 << bit)) {
615703831d35Sstevel 			fru_ptr->fru_status = FRU_PRESENT;
615803831d35Sstevel 			/*
615903831d35Sstevel 			 * XXX:	need to add version register, and maybe a
616003831d35Sstevel 			 *	 method, to the fru_ptr->i2c_info structure.
616103831d35Sstevel 			 *
616203831d35Sstevel 			 * fru_ptr->fru_version = (fru_version_t)0;
616303831d35Sstevel 			 */
616403831d35Sstevel 			/*
616503831d35Sstevel 			 * Because scsb_intr() sometimes gets the AC present
616603831d35Sstevel 			 * INT before the ACSLOT present INT,
616703831d35Sstevel 			 * do not check the ACSLOT fru_status
616803831d35Sstevel 			 *
616903831d35Sstevel 			 * if (acslot_ptr != NULL && acslot_ptr->fru_status ==
617003831d35Sstevel 			 *					FRU_PRESENT)
617103831d35Sstevel 			 */
617203831d35Sstevel 			if (acslot_ptr != NULL)
617303831d35Sstevel 				acslot_ptr->fru_type = (scsb_utype_t)OC_AC;
617403831d35Sstevel 		} else {
617503831d35Sstevel 			fru_ptr->fru_status = FRU_NOT_PRESENT;
617603831d35Sstevel 			/*
617703831d35Sstevel 			 * fru_ptr->fru_version = (fru_version_t)0;
617803831d35Sstevel 			 */
617903831d35Sstevel 			if (acslot_ptr != NULL) {
618003831d35Sstevel 				/* AC just removed, but AC Slot is occupied? */
618103831d35Sstevel 				if (acslot_ptr->fru_status == FRU_PRESENT)
618203831d35Sstevel 					/* for now it's unknown */
618303831d35Sstevel 					acslot_ptr->fru_type =
618403831d35Sstevel 					    (scsb_utype_t)OC_UNKN;
618503831d35Sstevel 				else
618603831d35Sstevel 					acslot_ptr->fru_type =
618703831d35Sstevel 					    (scsb_utype_t)OC_UNKN;
618803831d35Sstevel 			}
618903831d35Sstevel 		}
619003831d35Sstevel 	}
619103831d35Sstevel 	if (scsb_debug & 0x00100000)
619203831d35Sstevel 		cmn_err(CE_NOTE,
619303831d35Sstevel 		    "update_fru_info: type %d unit %d is %spresent",
619403831d35Sstevel 		    fru_ptr->fru_type, fru_ptr->fru_unit,
619503831d35Sstevel 		    fru_ptr->fru_status == FRU_PRESENT
619603831d35Sstevel 		    ? "" : "not ");
619703831d35Sstevel }
619803831d35Sstevel 
619903831d35Sstevel /*
620003831d35Sstevel  * Convert EVENT code to FRU index
620103831d35Sstevel  * by finding the highest bit number in 32 bit word
620203831d35Sstevel  */
620303831d35Sstevel static int
620403831d35Sstevel event_to_index(uint32_t evcode)
620503831d35Sstevel {
620603831d35Sstevel 	int	i = 0;
620703831d35Sstevel 	if (evcode == 0)
620803831d35Sstevel 		return (MCT_MAX_FRUS - 1);
620903831d35Sstevel 	for (; (evcode >>= 1); i++)
621003831d35Sstevel 		;
621103831d35Sstevel 	return (i);
621203831d35Sstevel }
621303831d35Sstevel 
621403831d35Sstevel #ifdef DEBUG
621503831d35Sstevel void
621603831d35Sstevel scsb_debug_prnt(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
621703831d35Sstevel 	uintptr_t a4, uintptr_t a5)
621803831d35Sstevel {
621903831d35Sstevel 	if (scsb_debug & 0x8000 ||
622003831d35Sstevel 	    (*fmt == 'X' && scsb_debug & 0x00010000)) {
622103831d35Sstevel 		if (*fmt == 'X')
622203831d35Sstevel 			++fmt;
622303831d35Sstevel 		prom_printf("scsb: ");
622403831d35Sstevel 		prom_printf(fmt, a1, a2, a3, a4, a5);
622503831d35Sstevel 		prom_printf("\n");
622603831d35Sstevel 	}
622703831d35Sstevel }
622803831d35Sstevel #endif
622903831d35Sstevel 
623003831d35Sstevel /*
623103831d35Sstevel  * event code functions to deliver event codes
623203831d35Sstevel  * and to manage:
623303831d35Sstevel  *	the event code fifo
623403831d35Sstevel  *	the process handle table for registered processes interested in
623503831d35Sstevel  *	  event codes
623603831d35Sstevel  */
623703831d35Sstevel /*
623803831d35Sstevel  * Send signal to processes registered for event code delivery
623903831d35Sstevel  */
624003831d35Sstevel static void
624103831d35Sstevel signal_evc_procs(scsb_state_t *scsb)
624203831d35Sstevel {
624303831d35Sstevel 	int	i = 0, c = 0;
624403831d35Sstevel 	if (evc_proc_count == 0)
624503831d35Sstevel 		return;
624603831d35Sstevel 	for (; i < EVC_PROCS_MAX; ++i) {
624703831d35Sstevel 		if (evc_procs[i] != NULL) {
624803831d35Sstevel 			if (proc_signal(evc_procs[i], SIGPOLL)) {
624903831d35Sstevel 				if (scsb_debug & 0x02000002)
625003831d35Sstevel 					cmn_err(CE_WARN,
625103831d35Sstevel 					    "scsb:signal_evc_procs: "
625203831d35Sstevel 					    "signal to %d failed",
625319397407SSherry Moore 					    ((struct pid *)
625419397407SSherry Moore 					    evc_procs[i])->pid_id);
625503831d35Sstevel 				(void) del_event_proc(scsb,
625603831d35Sstevel 				    ((struct pid *)evc_procs[i])->pid_id);
625703831d35Sstevel 			}
625803831d35Sstevel 			if (++c >= evc_proc_count) {
625903831d35Sstevel 				if (scsb_debug & 0x02000000) {
626003831d35Sstevel 					cmn_err(CE_NOTE,
626103831d35Sstevel 					    "signal_evc_procs: signaled "
626203831d35Sstevel 					    "%d/%d processes", c,
626303831d35Sstevel 					    evc_proc_count);
626403831d35Sstevel 				}
626503831d35Sstevel 				break;
626603831d35Sstevel 			}
626703831d35Sstevel 		}
626803831d35Sstevel 	}
626903831d35Sstevel }
627003831d35Sstevel 
627103831d35Sstevel /*
627203831d35Sstevel  * bump FIFO ptr, taking care of wrap around
627303831d35Sstevel  */
627403831d35Sstevel static uint32_t *
627503831d35Sstevel inc_fifo_ptr(uint32_t *ptr)
627603831d35Sstevel {
627703831d35Sstevel 	if (++ptr >= evc_fifo + EVC_FIFO_SIZE)
627803831d35Sstevel 		ptr = evc_fifo;
627903831d35Sstevel 	return (ptr);
628003831d35Sstevel }
628103831d35Sstevel 
628203831d35Sstevel /* ARGSUSED */
628303831d35Sstevel static void
628403831d35Sstevel reset_evc_fifo(scsb_state_t *scsb)
628503831d35Sstevel {
628603831d35Sstevel 	evc_wptr = evc_fifo;
628703831d35Sstevel 	evc_rptr = evc_fifo;
628803831d35Sstevel 	evc_fifo_count = 0;
628903831d35Sstevel }
629003831d35Sstevel 
629103831d35Sstevel /*
629203831d35Sstevel  * Called from scsb_intr() when a new event occurs, to put new code in FIFO,
629303831d35Sstevel  * and signal any interested processes in evc_procs[].
629403831d35Sstevel  * Always succeeds.
629503831d35Sstevel  */
629603831d35Sstevel static void
629703831d35Sstevel add_event_code(scsb_state_t *scsb, uint32_t event_code)
629803831d35Sstevel {
629903831d35Sstevel 	if (event_proc_count(scsb) == 0) {
630003831d35Sstevel 		return;
630103831d35Sstevel 	}
630203831d35Sstevel 	*evc_wptr = event_code;
630303831d35Sstevel 	evc_wptr = inc_fifo_ptr(evc_wptr);
630403831d35Sstevel 	if (++evc_fifo_count > EVC_FIFO_SIZE) {
630503831d35Sstevel 		--evc_fifo_count;		/* lose the oldest event */
630603831d35Sstevel 		evc_rptr = inc_fifo_ptr(evc_rptr);
630703831d35Sstevel 	}
630803831d35Sstevel 	if (scsb_debug & 0x01000000) {
630903831d35Sstevel 		cmn_err(CE_NOTE, "add_event_code: 0x%x, FIFO size = %d",
631003831d35Sstevel 		    event_code, evc_fifo_count);
631103831d35Sstevel 	}
631203831d35Sstevel 	signal_evc_procs(scsb);
631303831d35Sstevel }
631403831d35Sstevel 
631503831d35Sstevel /*
631603831d35Sstevel  * called from check_event_procs() when the last registered process
631703831d35Sstevel  * retrieved the oldest event
631803831d35Sstevel  */
631903831d35Sstevel static uint32_t
632003831d35Sstevel del_event_code()
632103831d35Sstevel {
632203831d35Sstevel 	uint32_t evc = 0;
632303831d35Sstevel 	if (!evc_fifo_count)
632403831d35Sstevel 		return (scsb_event_code);
632503831d35Sstevel 	evc = *evc_rptr;
632603831d35Sstevel 	evc_rptr = inc_fifo_ptr(evc_rptr);
632703831d35Sstevel 	--evc_fifo_count;
632803831d35Sstevel 	if (scsb_debug & 0x01000000) {
632903831d35Sstevel 		cmn_err(CE_NOTE, "del_event_code: 0x%x, FIFO size = %d",
633003831d35Sstevel 		    evc, evc_fifo_count);
633103831d35Sstevel 	}
633203831d35Sstevel 	return (evc);
633303831d35Sstevel }
633403831d35Sstevel 
633503831d35Sstevel /*
633603831d35Sstevel  * called from check_event_procs() to retrieve the current event code
633703831d35Sstevel  */
633803831d35Sstevel static uint32_t
633903831d35Sstevel get_event_code()
634003831d35Sstevel {
634103831d35Sstevel 	if (!evc_fifo_count)
634203831d35Sstevel 		return (0);
634303831d35Sstevel 	return (*evc_rptr);
634403831d35Sstevel }
634503831d35Sstevel 
634603831d35Sstevel /*
634703831d35Sstevel  * called from an application interface (ie: an ioctl command)
634803831d35Sstevel  * to register a process id interested in SCB events.
634903831d35Sstevel  * NOTE: proc_ref() must be called from USER context, so since this is a
635003831d35Sstevel  * streams driver, a kstat interface is used for process registration.
635103831d35Sstevel  * return:
635203831d35Sstevel  *	0 = event_proc was added
635303831d35Sstevel  *	1 = out of space
635403831d35Sstevel  */
635503831d35Sstevel /* ARGSUSED */
635603831d35Sstevel static int
635703831d35Sstevel add_event_proc(scsb_state_t *scsb, pid_t pid)
635803831d35Sstevel {
635903831d35Sstevel 	int	i = 0;
636003831d35Sstevel 	void	*curr_proc;
636103831d35Sstevel 	pid_t	curr_pid;
636203831d35Sstevel 	if (evc_proc_count >= EVC_PROCS_MAX)
636303831d35Sstevel 		return (1);
636403831d35Sstevel 	curr_proc = proc_ref();
636503831d35Sstevel 	curr_pid = (pid_t)(((struct pid *)curr_proc)->pid_id);
636603831d35Sstevel 	if (curr_pid != pid) {
636703831d35Sstevel 		if (scsb_debug & 0x02000000) {
636803831d35Sstevel 			cmn_err(CE_WARN,
636903831d35Sstevel 			    "add_event_proc: current %d != requestor %d",
637003831d35Sstevel 			    curr_pid, pid);
637103831d35Sstevel 		} else {
637203831d35Sstevel 			proc_unref(curr_proc);
637303831d35Sstevel 			return (1);
637403831d35Sstevel 		}
637503831d35Sstevel 	}
637603831d35Sstevel 	for (; i < EVC_PROCS_MAX; ++i) {
637703831d35Sstevel 		if (evc_procs[i] == NULL) {
637803831d35Sstevel 			evc_procs[i] = curr_proc;
637903831d35Sstevel 			evc_proc_count++;
638003831d35Sstevel 			if (scsb_debug & 0x02000000) {
638103831d35Sstevel 				cmn_err(CE_NOTE,
638203831d35Sstevel 				    "add_event_proc: %d; evc_proc_count=%d",
638303831d35Sstevel 				    pid, evc_proc_count);
638403831d35Sstevel 			}
638503831d35Sstevel 			return (0);
638603831d35Sstevel 		}
638703831d35Sstevel 	}
638803831d35Sstevel 	proc_unref(curr_proc);
638903831d35Sstevel 	return (1);
639003831d35Sstevel }
639103831d35Sstevel 
639203831d35Sstevel /*
639303831d35Sstevel  * called from an application interface (ie: an ioctl command)
639403831d35Sstevel  * to unregister a process id interested in SCB events.
639503831d35Sstevel  * return:
639603831d35Sstevel  *	0 = event_proc was deleted
639703831d35Sstevel  *	1 = event_proc was not found, or table was empty
639803831d35Sstevel  */
639903831d35Sstevel /* ARGSUSED */
640003831d35Sstevel static int
640103831d35Sstevel del_event_proc(scsb_state_t *scsb, pid_t pid)
640203831d35Sstevel {
640303831d35Sstevel 	int	i = 0;
640403831d35Sstevel 	int	cnt = 0;
640503831d35Sstevel 	void	*this_proc;
640603831d35Sstevel 	if (evc_proc_count == 0)
640703831d35Sstevel 		return (1);
640803831d35Sstevel 	for (; i < EVC_PROCS_MAX; ++i) {
640903831d35Sstevel 		if (evc_procs[i] == NULL)
641003831d35Sstevel 			continue;
641103831d35Sstevel 		this_proc = evc_procs[i];
641203831d35Sstevel 		if (pid == ((struct pid *)this_proc)->pid_id) {
641303831d35Sstevel 			evc_procs[i] = NULL;
641403831d35Sstevel 			if (--evc_proc_count == 0) {
641503831d35Sstevel 				/*
641603831d35Sstevel 				 * reset evc fifo cound and pointers
641703831d35Sstevel 				 */
641803831d35Sstevel 				reset_evc_fifo(scsb);
641903831d35Sstevel 			}
642003831d35Sstevel 			if (scsb_debug & 0x02000000) {
642103831d35Sstevel 				cmn_err(CE_NOTE,
642203831d35Sstevel 				    "del_event_proc: %d; evc_proc_count=%d",
642303831d35Sstevel 				    pid, evc_proc_count);
642403831d35Sstevel 			}
642503831d35Sstevel 			proc_unref(this_proc);
642603831d35Sstevel 			return (0);
642703831d35Sstevel 		}
642803831d35Sstevel 		if (++cnt >= evc_proc_count)
642903831d35Sstevel 			break;
643003831d35Sstevel 	}
643103831d35Sstevel 	return (1);
643203831d35Sstevel }
643303831d35Sstevel 
643403831d35Sstevel /*
643503831d35Sstevel  * Can be called from an application interface
643603831d35Sstevel  * to rewind the pointers and counters, and zero the table
643703831d35Sstevel  * return:
643803831d35Sstevel  */
643903831d35Sstevel /* ARGSUSED */
644003831d35Sstevel static void
644103831d35Sstevel rew_event_proc(scsb_state_t *scsb)
644203831d35Sstevel {
644303831d35Sstevel 	int	i = 0;
644403831d35Sstevel 	if (scsb_debug & 0x02000001) {
644503831d35Sstevel 		cmn_err(CE_NOTE, "rew_event_proc: evc_proc_count=%d",
644603831d35Sstevel 		    evc_proc_count);
644703831d35Sstevel 	}
644803831d35Sstevel 	for (; i < EVC_PROCS_MAX; ++i) {
644903831d35Sstevel 		if (evc_procs[i] != NULL) {
645003831d35Sstevel 			proc_unref(evc_procs[i]);
645103831d35Sstevel 			evc_procs[i] = NULL;
645203831d35Sstevel 		}
645303831d35Sstevel 	}
645403831d35Sstevel 	evc_proc_count = 0;
645503831d35Sstevel }
645603831d35Sstevel 
645703831d35Sstevel /* ARGSUSED */
645803831d35Sstevel static int
645903831d35Sstevel event_proc_count(scsb_state_t *scsb)
646003831d35Sstevel {
646103831d35Sstevel 	return (evc_proc_count);
646203831d35Sstevel }
646303831d35Sstevel 
646403831d35Sstevel /*
646503831d35Sstevel  * return:
646603831d35Sstevel  *	1 = pid was found
646703831d35Sstevel  *	0 = pid was not found, or table was empty
646803831d35Sstevel  */
646903831d35Sstevel static int
647003831d35Sstevel find_evc_proc(pid_t pid)
647103831d35Sstevel {
647203831d35Sstevel 	int	i = 0;
647303831d35Sstevel 	int	cnt = 0;
647403831d35Sstevel 	if (evc_proc_count == 0)
647503831d35Sstevel 		return (0);
647603831d35Sstevel 	for (; i < EVC_PROCS_MAX; ++i) {
647703831d35Sstevel 		if (evc_procs[i] == NULL)
647803831d35Sstevel 			continue;
647903831d35Sstevel 		if (pid == ((struct pid *)evc_procs[i])->pid_id)
648003831d35Sstevel 			return (1);
648103831d35Sstevel 		if (++cnt >= evc_proc_count)
648203831d35Sstevel 			break;
648303831d35Sstevel 	}
648403831d35Sstevel 	return (0);
648503831d35Sstevel }
648603831d35Sstevel 
648703831d35Sstevel /*
648803831d35Sstevel  * called from update_ks_state() to compare evc_proc_count with
648903831d35Sstevel  * evc_requests, also mainted by this same function
649003831d35Sstevel  * This function could check the current process id, since this will be a user
649103831d35Sstevel  * context call, and only bump evc_requests if the calling process is
649203831d35Sstevel  * registered for event code delivery.
649303831d35Sstevel  * return:
649403831d35Sstevel  *	EVC_NO_EVENT_CODE	: no event_code on fifo
649503831d35Sstevel  *	EVC_NO_CURR_PROC	: current process not in table,
649603831d35Sstevel  *				  but have an event_code
649703831d35Sstevel  *	EVC_NEW_EVENT_CODE	: return_evc is new ks_state->event_code
649803831d35Sstevel  *	EVC_OR_EVENT_CODE	: OR return_evc with ks_state->event_code
649903831d35Sstevel  *	EVC_FAILURE		: unrecoverable error condition.
650003831d35Sstevel  */
650103831d35Sstevel static int
650203831d35Sstevel check_event_procs(uint32_t *return_evc)
650303831d35Sstevel {
650403831d35Sstevel 	void		*curr_proc;
650503831d35Sstevel 	pid_t		curr_pid = 0;
650603831d35Sstevel 	int		return_val = 0;
650703831d35Sstevel 	static int	evc_requests = 0;
650803831d35Sstevel 	/*
650903831d35Sstevel 	 * get current process handle, and check the event_procs table
651003831d35Sstevel 	 */
651103831d35Sstevel 	if (evc_proc_count == 0) {
651203831d35Sstevel 		*return_evc = del_event_code();
651303831d35Sstevel 		return_val = EVC_NO_CURR_PROC;
651403831d35Sstevel 	} else {
651503831d35Sstevel 		curr_proc = proc_ref();
651603831d35Sstevel 		curr_pid = ((struct pid *)curr_proc)->pid_id;
651703831d35Sstevel 		proc_unref(curr_proc);
651803831d35Sstevel 		if (!find_evc_proc(curr_pid)) {
651903831d35Sstevel 			*return_evc = get_event_code();
652003831d35Sstevel 			return_val = EVC_NO_CURR_PROC;
652103831d35Sstevel 		} else if (++evc_requests >= evc_proc_count) {
652203831d35Sstevel 			evc_requests = 0;
652303831d35Sstevel 			*return_evc = del_event_code();
652403831d35Sstevel 			return_val = EVC_NEW_EVENT_CODE;
652503831d35Sstevel 		} else {
652603831d35Sstevel 			*return_evc = get_event_code();
652703831d35Sstevel 		}
652803831d35Sstevel 		if (!return_val)
652903831d35Sstevel 			return_val = EVC_OR_EVENT_CODE;
653003831d35Sstevel 	}
653103831d35Sstevel 	if (scsb_debug & 0x02000000) {
653203831d35Sstevel 		cmn_err(CE_NOTE, "check_event_procs: pid=%d, evc=0x%x, "
653303831d35Sstevel 		    "requests=%d, returning 0x%x", curr_pid,
653403831d35Sstevel 		    *return_evc, evc_requests, return_val);
653503831d35Sstevel 	}
653603831d35Sstevel 	return (return_val);
653703831d35Sstevel }
653803831d35Sstevel 
653903831d35Sstevel static int
654003831d35Sstevel scsb_queue_put(queue_t *rq, int count, uint32_t *data, char *caller)
654103831d35Sstevel {
654203831d35Sstevel 	mblk_t		*mp;
654303831d35Sstevel 	if (scsb_debug & 0x4001) {
654403831d35Sstevel 		cmn_err(CE_NOTE, "scsb_queue_put(0x%p, %d, 0x%x, %s)",
6545*07d06da5SSurya Prakki 		    (void *)rq, count, *data, caller);
654603831d35Sstevel 	}
654703831d35Sstevel 	mp = allocb(sizeof (uint32_t) * count, BPRI_HI);
654803831d35Sstevel 	if (mp == NULL) {
654903831d35Sstevel 		cmn_err(CE_WARN, "%s: allocb failed",
655003831d35Sstevel 		    caller);
655103831d35Sstevel 		return (B_FALSE);
655203831d35Sstevel 	}
655303831d35Sstevel 	while (count--) {
655403831d35Sstevel 		*((uint32_t *)mp->b_wptr) = *data;
655503831d35Sstevel 		mp->b_wptr += sizeof (*data);
655603831d35Sstevel 		++data;
655703831d35Sstevel 	}
655803831d35Sstevel 	putnext(rq, mp);
655903831d35Sstevel 	return (B_TRUE);
656003831d35Sstevel }
656103831d35Sstevel 
656203831d35Sstevel /* CLONE */
656303831d35Sstevel static int
656403831d35Sstevel scsb_queue_ops(scsb_state_t	*scsb,
656503831d35Sstevel 		int		op,
656603831d35Sstevel 		int		oparg,
656703831d35Sstevel 		void		*opdata,
656803831d35Sstevel 		char		*caller)
656903831d35Sstevel {
657003831d35Sstevel 	clone_dev_t	*clptr;
657103831d35Sstevel 	int		clone, find_open, find_available, retval = QOP_FAILED;
657203831d35Sstevel 
657303831d35Sstevel 	switch (op) {
657403831d35Sstevel 	case QPUT_INT32:
657503831d35Sstevel 		if (scsb->scsb_opens && scsb->scsb_rq != NULL &&
657603831d35Sstevel 		    scsb_queue_put(scsb->scsb_rq, oparg,
657703831d35Sstevel 		    (uint32_t *)opdata, caller) == B_FALSE) {
657803831d35Sstevel 			return (QOP_FAILED);
657903831d35Sstevel 		}
658003831d35Sstevel 	/*FALLTHROUGH*/	/* to look for opened clones */
658103831d35Sstevel 	case QPROCSOFF:
658203831d35Sstevel 		retval = QOP_OK;
658303831d35Sstevel 	/*FALLTHROUGH*/
658403831d35Sstevel 	case QFIRST_OPEN:
658503831d35Sstevel 	case QFIND_QUEUE:
658603831d35Sstevel 		find_open = 1;
658703831d35Sstevel 		find_available = 0;
658803831d35Sstevel 		break;
658903831d35Sstevel 	case QFIRST_AVAILABLE:
659003831d35Sstevel 		find_available = 1;
659103831d35Sstevel 		find_open = 0;
659203831d35Sstevel 		break;
659303831d35Sstevel 	}
659403831d35Sstevel 	for (clone = SCSB_CLONES_FIRST; clone < SCSB_CLONES_MAX; clone++) {
659503831d35Sstevel 		clptr = &scsb->clone_devs[clone];
659603831d35Sstevel 		if (find_open && clptr->cl_flags & SCSB_OPEN) {
659703831d35Sstevel 			if (clptr->cl_rq == NULL) {
659803831d35Sstevel 				cmn_err(CE_WARN, "%s: Clone %d has no queue",
659903831d35Sstevel 				    caller, clptr->cl_minor);
660003831d35Sstevel 				return (QOP_FAILED);
660103831d35Sstevel 			}
660203831d35Sstevel 			switch (op) {
660303831d35Sstevel 			case QPROCSOFF:
660403831d35Sstevel 				qprocsoff(clptr->cl_rq);
660503831d35Sstevel 				break;
660603831d35Sstevel 			case QPUT_INT32:
660703831d35Sstevel 				if (scsb_queue_put(clptr->cl_rq, oparg,
660803831d35Sstevel 				    (uint32_t *)opdata, caller)
660903831d35Sstevel 				    == B_FALSE) {
661003831d35Sstevel 					retval = QOP_FAILED;
661103831d35Sstevel 				}
661203831d35Sstevel 				break;
661303831d35Sstevel 			case QFIRST_OPEN:
661403831d35Sstevel 				return (clone);
661503831d35Sstevel 			case QFIND_QUEUE:
661603831d35Sstevel 				if (clptr->cl_rq == (queue_t *)opdata) {
661703831d35Sstevel 					return (clone);
661803831d35Sstevel 				}
661903831d35Sstevel 				break;
662003831d35Sstevel 			}
662103831d35Sstevel 		} else if (find_available && clptr->cl_flags == 0) {
662203831d35Sstevel 			switch (op) {
662303831d35Sstevel 			case QFIRST_AVAILABLE:
662403831d35Sstevel 				return (clone);
662503831d35Sstevel 			}
662603831d35Sstevel 		}
662703831d35Sstevel 	}
662803831d35Sstevel 	return (retval);
662903831d35Sstevel }
663003831d35Sstevel 
663103831d35Sstevel /*
663203831d35Sstevel  * Find out if a bit is set for the FRU type and unit number in the register
663303831d35Sstevel  * set defined by the register base table index, base.
663403831d35Sstevel  * Returns TRUE if bit is set, or FALSE.
663503831d35Sstevel  */
663603831d35Sstevel static int
663703831d35Sstevel scsb_fru_op(scsb_state_t *scsb, scsb_utype_t fru_type, int unit, int base,
663803831d35Sstevel 									int op)
663903831d35Sstevel {
664003831d35Sstevel 	int		rc;
664103831d35Sstevel 	uchar_t		reg;
664203831d35Sstevel 	int		tmp, idx, code, offset;
664303831d35Sstevel 
664403831d35Sstevel #if 0
664503831d35Sstevel 		reg = SCSB_REG_ADDR(i);
664603831d35Sstevel 		ac_mask = 1 << FRU_OFFSET(SCTRL_EVENT_ALARM, SCTRL_RESET_BASE);
664703831d35Sstevel 		ac_val = scsb->scsb_data_reg[index+1] & ac_mask;
664803831d35Sstevel #endif
664903831d35Sstevel 	/* get the event code based on which we get the reg and bit offsets */
665003831d35Sstevel 	code   = FRU_UNIT_TO_EVCODE(fru_type, unit);
665103831d35Sstevel 	/* get the bit offset in the 8bit register corresponding to the event */
665203831d35Sstevel 	offset = FRU_OFFSET(code, base);
665303831d35Sstevel 	/* register offset from the base register, based on the event code */
665403831d35Sstevel 	if ((fru_type == ALARM) && (base == SCTRL_RESET_BASE))
665503831d35Sstevel 		tmp = ALARM_RESET_REG_INDEX(code, base);
665603831d35Sstevel 	else
665703831d35Sstevel 		tmp = FRU_REG_INDEX(code, base);
665803831d35Sstevel 	/* get the global offset of the register in the parent address space */
665903831d35Sstevel 	reg    = SCSB_REG_ADDR(tmp);
666003831d35Sstevel 	/* get the global index of the register in this SCSB's address space */
666103831d35Sstevel 	idx    = SCSB_REG_INDEX(reg);
666203831d35Sstevel 	DEBUG4("scsb_fru_op(start): code=%x, offset=%x, tmp=%x, reg=%x\n",
666303831d35Sstevel 	    code, offset, tmp, reg);
666403831d35Sstevel 	switch (op) {
666503831d35Sstevel 		case SCSB_FRU_OP_GET_REG:
666603831d35Sstevel 			rc = reg;
666703831d35Sstevel 			break;
666803831d35Sstevel 		case SCSB_FRU_OP_GET_BITVAL:
666903831d35Sstevel 			rc = (scsb->scsb_data_reg[idx] & (1 << offset))
667003831d35Sstevel 			    >> offset;
667103831d35Sstevel 			break;
667203831d35Sstevel 		case SCSB_FRU_OP_GET_REGDATA:
667303831d35Sstevel 			rc = scsb->scsb_data_reg[idx];
667403831d35Sstevel 			break;
667503831d35Sstevel 		case SCSB_FRU_OP_SET_REGBIT:
667603831d35Sstevel 			rc = (1 << offset) & 0xff;
667703831d35Sstevel 			break;
667803831d35Sstevel 		default:
667903831d35Sstevel 			break;
668003831d35Sstevel 	}
668103831d35Sstevel 	DEBUG4("scsb_fru_op: unit=%x, base=%x, op=%d, rc=%x\n", unit, base,
668203831d35Sstevel 	    op, rc);
668303831d35Sstevel 	return (rc);
668403831d35Sstevel }
668503831d35Sstevel 
668603831d35Sstevel /*
668703831d35Sstevel  * All HSC related functions can fail, but an attempt is made to atleast
668803831d35Sstevel  * return the right shadow state  on get-state function when SCB is removed.
668903831d35Sstevel  */
669003831d35Sstevel int
669103831d35Sstevel scsb_get_slot_state(scsb_state_t *scsb, int pslotnum, int *rstate)
669203831d35Sstevel {
669303831d35Sstevel 	int		slotnum, val = 0, rc;
669403831d35Sstevel 
669503831d35Sstevel 	/*
669603831d35Sstevel 	 * When SCB is removed, we could be called with the lock held.
669703831d35Sstevel 	 * We call check_config_status anyway since it is a read-only operation
669803831d35Sstevel 	 * and HSC could be invoking this function at interrupt context.
669903831d35Sstevel 	 * If scsb is already in the doing interrupt postprocess, wait..
670003831d35Sstevel 	 */
670103831d35Sstevel 
670203831d35Sstevel 	rc = scsb_check_config_status(scsb);
670303831d35Sstevel 
670403831d35Sstevel 	/* check if error is because SCB is removed */
670503831d35Sstevel 	if ((rc != EAGAIN) && (rc != DDI_SUCCESS))
670603831d35Sstevel 		return (DDI_FAILURE);
670703831d35Sstevel 	slotnum = tonga_psl_to_ssl(scsb, pslotnum);
670803831d35Sstevel 	val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_SYSCFG_BASE,
670903831d35Sstevel 	    SCSB_FRU_OP_GET_BITVAL);
671003831d35Sstevel 	if (! val) {
671103831d35Sstevel 		*rstate = HPC_SLOT_EMPTY;
671203831d35Sstevel 		return (0);
671303831d35Sstevel 	}
671403831d35Sstevel 	/*
671503831d35Sstevel 	 * now, lets determine if it is connected or disconnected.
671603831d35Sstevel 	 * If reset is asserted, then the slot is disconnected.
671703831d35Sstevel 	 */
671803831d35Sstevel 	rc = scsb_reset_slot(scsb, pslotnum, SCSB_GET_SLOT_RESET_STATUS);
671903831d35Sstevel 	/* check if error is because SCB is removed */
672003831d35Sstevel 	if ((rc != EAGAIN) && (rc != DDI_SUCCESS))
672103831d35Sstevel 		return (DDI_FAILURE);
672203831d35Sstevel 	val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE,
672303831d35Sstevel 	    SCSB_FRU_OP_GET_BITVAL);
672403831d35Sstevel 	if (val)
672503831d35Sstevel 		*rstate = HPC_SLOT_DISCONNECTED;
672603831d35Sstevel 	else {
672703831d35Sstevel 		if (scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
672803831d35Sstevel 		    SCSB_FRU_OP_GET_BITVAL)) {
672903831d35Sstevel 			*rstate = HPC_SLOT_CONNECTED;
673003831d35Sstevel 		} else {
673103831d35Sstevel 			cmn_err(CE_WARN, "%s#%d: Reset Not Asserted on "
673203831d35Sstevel 			    "Healthy# Failed slot %d!",
673303831d35Sstevel 			    ddi_driver_name(scsb->scsb_dev),
673403831d35Sstevel 			    ddi_get_instance(scsb->scsb_dev), slotnum);
673503831d35Sstevel 			*rstate = HPC_SLOT_DISCONNECTED;
673603831d35Sstevel 		}
673703831d35Sstevel 	}
673803831d35Sstevel 	return (0);
673903831d35Sstevel }
674003831d35Sstevel 
674103831d35Sstevel int
674203831d35Sstevel scsb_reset_slot(scsb_state_t *scsb, int pslotnum, int reset_flag)
674303831d35Sstevel {
674403831d35Sstevel 	int		slotnum, error, val, alarm_card = 0;
674503831d35Sstevel 	i2c_transfer_t	*i2cxferp;
674603831d35Sstevel 	uchar_t		reg;
674703831d35Sstevel 	int		index, condition_exists = 0, ac_val;
674803831d35Sstevel 
674903831d35Sstevel 	if (scsb_debug & 0x8001)
675003831d35Sstevel 		cmn_err(CE_NOTE, "scsb_reset_slot(%d), flag %x", pslotnum,
675103831d35Sstevel 		    reset_flag);
675203831d35Sstevel 	if (scsb->scsb_state & SCSB_FROZEN)
675303831d35Sstevel 		return (EAGAIN);
675403831d35Sstevel 	if ((i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle,
675503831d35Sstevel 	    I2C_NOSLEEP)) == NULL) {
675603831d35Sstevel 		return (ENOMEM);
675703831d35Sstevel 	}
675803831d35Sstevel 	slotnum = tonga_psl_to_ssl(scsb, pslotnum);
675903831d35Sstevel 
676003831d35Sstevel 	if (scsb_is_alarm_card_slot(scsb, pslotnum) == B_TRUE) {
676103831d35Sstevel 		DEBUG0("alarm card  reset/unreset op:\n");
676203831d35Sstevel 		alarm_card = 1;
676303831d35Sstevel 	}
676403831d35Sstevel 	reg = SCSB_REG_ADDR(SCTRL_RESET_BASE);
676503831d35Sstevel 	index = SCSB_REG_INDEX(reg);
676603831d35Sstevel 
676703831d35Sstevel 	mutex_enter(&scsb->scsb_mutex);
676803831d35Sstevel 	i2cxferp->i2c_flags = I2C_WR_RD;
676903831d35Sstevel 	i2cxferp->i2c_rlen = SCTRL_RESET_NUMREGS;
677003831d35Sstevel 	i2cxferp->i2c_wbuf[0] = reg;
677103831d35Sstevel 	i2cxferp->i2c_wlen = 1;
677203831d35Sstevel 	scsb->scsb_kstat_flag = B_TRUE;	/* we did an i2c transaction */
677303831d35Sstevel 	if ((error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) == 0) {
677403831d35Sstevel 		scsb->scsb_i2c_errcnt = 0;
677503831d35Sstevel 		/*
677603831d35Sstevel 		 * XXX: following statements assume 2 reset registers,
677703831d35Sstevel 		 * which is the case for our current SCB revisions.
677803831d35Sstevel 		 */
677903831d35Sstevel 		scsb->scsb_data_reg[index]   = i2cxferp->i2c_rbuf[0];
678003831d35Sstevel 		scsb->scsb_data_reg[index+1] = i2cxferp->i2c_rbuf[1];
678103831d35Sstevel 	} else {
678203831d35Sstevel 		scsb->scsb_i2c_errcnt++;
678303831d35Sstevel 		if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
678403831d35Sstevel 			scsb->scsb_err_flag = B_TRUE; /* latch until kstat */
678503831d35Sstevel 		if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
678603831d35Sstevel 			if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
678703831d35Sstevel 				mutex_exit(&scsb->scsb_mutex);
678803831d35Sstevel 				scsb_freeze(scsb);
678903831d35Sstevel 				mutex_enter(&scsb->scsb_mutex);
679003831d35Sstevel 		}
679103831d35Sstevel 		cmn_err(CE_WARN, "%s#%d: scsb_reset_slot: error"
679203831d35Sstevel 		    " reading Reset regs\n",
679303831d35Sstevel 		    ddi_driver_name(scsb->scsb_dev),
679403831d35Sstevel 		    ddi_get_instance(scsb->scsb_dev));
679503831d35Sstevel 		error = DDI_FAILURE;
679603831d35Sstevel 	}
679703831d35Sstevel 
679803831d35Sstevel 	DEBUG2("pre-reset regs = %x,%x\n", scsb->scsb_data_reg[index],
679903831d35Sstevel 	    scsb->scsb_data_reg[index+1]);
680003831d35Sstevel 	if ((reset_flag == SCSB_GET_SLOT_RESET_STATUS) || (error)) {
680103831d35Sstevel 		mutex_exit(&scsb->scsb_mutex);
680203831d35Sstevel 		scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
680303831d35Sstevel 		return (error);
680403831d35Sstevel 	}
680503831d35Sstevel 
680603831d35Sstevel 	val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE,
680703831d35Sstevel 	    SCSB_FRU_OP_GET_BITVAL);
680803831d35Sstevel 	if (alarm_card) {
680903831d35Sstevel 		ac_val = scsb_fru_op(scsb, ALARM, 1, SCTRL_RESET_BASE,
681003831d35Sstevel 		    SCSB_FRU_OP_GET_BITVAL);
681103831d35Sstevel 	}
681203831d35Sstevel 	if (val && (reset_flag == SCSB_RESET_SLOT)) {
681303831d35Sstevel 		if (alarm_card) {
681403831d35Sstevel 			if (ac_val) {
681503831d35Sstevel 				condition_exists = 1;
681603831d35Sstevel 				DEBUG0("Alarm_RST# already active.\n");
681703831d35Sstevel 			}
681803831d35Sstevel #ifndef	lint
681903831d35Sstevel 			else
682003831d35Sstevel 				DEBUG1("Alarm_RST# not active! "
682103831d35Sstevel 				    "Slot%d_RST# active!\n", pslotnum);
682203831d35Sstevel #endif
682303831d35Sstevel 		} else {
682403831d35Sstevel 			condition_exists = 1;
682503831d35Sstevel 			DEBUG1("Slot%d_RST# already active!\n", pslotnum);
682603831d35Sstevel 		}
682703831d35Sstevel 	}
682803831d35Sstevel 	else
682903831d35Sstevel 		if ((val == 0) && (reset_flag == SCSB_UNRESET_SLOT)) {
683003831d35Sstevel 			if (alarm_card) {
683103831d35Sstevel 				if (!ac_val) {
683203831d35Sstevel 					DEBUG0("Alarm_RST# not active.\n");
683303831d35Sstevel 					condition_exists = 1;
683403831d35Sstevel 				}
683503831d35Sstevel #ifndef	lint
683603831d35Sstevel 				else
683703831d35Sstevel 					DEBUG1("Alarm_RST# active"
683803831d35Sstevel 					    " Slot%d_RST# not active!\n",
683903831d35Sstevel 					    pslotnum);
684003831d35Sstevel #endif
684103831d35Sstevel 			} else {
684203831d35Sstevel 				condition_exists = 1;
684303831d35Sstevel 				DEBUG1("Slot%d_RST# already not active!\n",
684403831d35Sstevel 				    pslotnum);
684503831d35Sstevel 			}
684603831d35Sstevel 		}
684703831d35Sstevel 
684803831d35Sstevel 	if (! condition_exists) {
684903831d35Sstevel 		i2cxferp->i2c_flags = I2C_WR;
685003831d35Sstevel 		i2cxferp->i2c_wlen = 2;
685103831d35Sstevel 		i2cxferp->i2c_wbuf[0] = scsb_fru_op(scsb, SLOT, slotnum,
685203831d35Sstevel 		    SCTRL_RESET_BASE, SCSB_FRU_OP_GET_REG);
685303831d35Sstevel 		if (reset_flag == SCSB_RESET_SLOT) {
685403831d35Sstevel 			i2cxferp->i2c_wbuf[1] =
685503831d35Sstevel 			    scsb_fru_op(scsb, SLOT, slotnum,
685603831d35Sstevel 			    SCTRL_RESET_BASE,
685703831d35Sstevel 			    SCSB_FRU_OP_GET_REGDATA) |
685803831d35Sstevel 			    scsb_fru_op(scsb, SLOT, slotnum,
685903831d35Sstevel 			    SCTRL_RESET_BASE,
686003831d35Sstevel 			    SCSB_FRU_OP_SET_REGBIT);
686103831d35Sstevel #ifdef	DEBUG		/* dont reset Alarm Card line unless in debug mode */
686203831d35Sstevel 			if (alarm_card)
686303831d35Sstevel 				i2cxferp->i2c_wbuf[1] |=
686403831d35Sstevel 				    scsb_fru_op(scsb, ALARM, 1,
686503831d35Sstevel 				    SCTRL_RESET_BASE,
686603831d35Sstevel 				    SCSB_FRU_OP_SET_REGBIT);
686703831d35Sstevel #endif
686803831d35Sstevel 		} else {
686903831d35Sstevel 			i2cxferp->i2c_wbuf[1] =
687003831d35Sstevel 			    scsb_fru_op(scsb, SLOT, slotnum,
687103831d35Sstevel 			    SCTRL_RESET_BASE,
687203831d35Sstevel 			    SCSB_FRU_OP_GET_REGDATA) &
687303831d35Sstevel 			    ~(scsb_fru_op(scsb, SLOT, slotnum,
687403831d35Sstevel 			    SCTRL_RESET_BASE,
687503831d35Sstevel 			    SCSB_FRU_OP_SET_REGBIT));
687603831d35Sstevel #ifdef	DEBUG		/* dont Unreset Alarm Card line unless in debug mode */
687703831d35Sstevel 			if (alarm_card)
687803831d35Sstevel 				i2cxferp->i2c_wbuf[1] &=
687903831d35Sstevel 				    scsb_fru_op(scsb, ALARM, 1,
688003831d35Sstevel 				    SCTRL_RESET_BASE,
688103831d35Sstevel 				    SCSB_FRU_OP_SET_REGBIT);
688203831d35Sstevel #endif
688303831d35Sstevel 		}
688403831d35Sstevel 
688503831d35Sstevel 		if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
688603831d35Sstevel 			scsb->scsb_i2c_errcnt++;
688703831d35Sstevel 			if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
688803831d35Sstevel 				scsb->scsb_err_flag = B_TRUE; /* latch error */
688903831d35Sstevel 			mutex_exit(&scsb->scsb_mutex);
689003831d35Sstevel 			if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
689103831d35Sstevel 				if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
689203831d35Sstevel 					scsb_freeze(scsb);
689303831d35Sstevel 			}
689403831d35Sstevel 			cmn_err(CE_WARN, "%s#%d: reset_slot: error writing to"
689503831d35Sstevel 			    " Reset regs (op=%d, data=%x)\n",
689603831d35Sstevel 			    ddi_driver_name(scsb->scsb_dev),
689703831d35Sstevel 			    ddi_get_instance(scsb->scsb_dev),
689803831d35Sstevel 			    reset_flag, i2cxferp->i2c_wbuf[1]);
689903831d35Sstevel 			scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
690003831d35Sstevel 			return (DDI_FAILURE);
690103831d35Sstevel 		}
690203831d35Sstevel 
690303831d35Sstevel 		scsb->scsb_i2c_errcnt = 0;
690403831d35Sstevel 		/* now read back and update our scsb structure */
690503831d35Sstevel 		i2cxferp->i2c_flags = I2C_WR_RD;
690603831d35Sstevel 		i2cxferp->i2c_rlen = SCTRL_RESET_NUMREGS;
690703831d35Sstevel 		i2cxferp->i2c_wbuf[0] = reg;
690803831d35Sstevel 		i2cxferp->i2c_wlen = 1;
690903831d35Sstevel 		if ((error = nct_i2c_transfer(scsb->scsb_phandle,
691003831d35Sstevel 		    i2cxferp)) == 0) {
691103831d35Sstevel 			scsb->scsb_i2c_errcnt = 0;
691203831d35Sstevel 			scsb->scsb_data_reg[index]   = i2cxferp->i2c_rbuf[0];
691303831d35Sstevel 			scsb->scsb_data_reg[index+1] = i2cxferp->i2c_rbuf[1];
691403831d35Sstevel 		} else {
691503831d35Sstevel 			scsb->scsb_i2c_errcnt++;
691603831d35Sstevel 			if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
691703831d35Sstevel 				scsb->scsb_err_flag = B_TRUE; /* latch error */
691803831d35Sstevel 			mutex_exit(&scsb->scsb_mutex);
691903831d35Sstevel 			if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
692003831d35Sstevel 				if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
692103831d35Sstevel 					scsb_freeze(scsb);
692203831d35Sstevel 			}
692303831d35Sstevel 			cmn_err(CE_WARN, "%s#%d: scsb_reset_slot: error"
692403831d35Sstevel 			    " reading Reset regs (post reset)\n",
692503831d35Sstevel 			    ddi_driver_name(scsb->scsb_dev),
692603831d35Sstevel 			    ddi_get_instance(scsb->scsb_dev));
692703831d35Sstevel 			scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
692803831d35Sstevel 			return (DDI_FAILURE);
692903831d35Sstevel 		}
693003831d35Sstevel 		/* XXX: P1.5 */
693103831d35Sstevel 		DEBUG2("post-reset regs = %x,%x\n", scsb->scsb_data_reg[index],
693203831d35Sstevel 		    scsb->scsb_data_reg[index+1]);
693303831d35Sstevel 		val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE,
693403831d35Sstevel 		    SCSB_FRU_OP_GET_BITVAL);
693503831d35Sstevel #ifdef	DEBUG
693603831d35Sstevel 		if (alarm_card)
693703831d35Sstevel 			ac_val = scsb_fru_op(scsb, ALARM, 1, SCTRL_RESET_BASE,
693803831d35Sstevel 			    SCSB_FRU_OP_GET_BITVAL);
693903831d35Sstevel #endif
694003831d35Sstevel 		if (val && (reset_flag == SCSB_UNRESET_SLOT)) {
694103831d35Sstevel 			cmn_err(CE_WARN, "Cannot UnReset Slot %d (reg=%x)\n",
694203831d35Sstevel 			    pslotnum,
694303831d35Sstevel 			    scsb_fru_op(scsb, SLOT, slotnum,
694403831d35Sstevel 			    SCTRL_RESET_BASE,
694503831d35Sstevel 			    SCSB_FRU_OP_GET_REGDATA));
694603831d35Sstevel #ifdef	DEBUG
694703831d35Sstevel 			if (alarm_card) {
694803831d35Sstevel 				if (ac_val)
694903831d35Sstevel 					cmn_err(CE_WARN, "Cannot Unreset "
695003831d35Sstevel 					    "Alarm_RST#.\n");
695103831d35Sstevel 			}
695203831d35Sstevel #endif
695303831d35Sstevel 		}
695403831d35Sstevel 		else
695503831d35Sstevel 			if ((val == 0) && (reset_flag == SCSB_RESET_SLOT)) {
695603831d35Sstevel 				cmn_err(CE_WARN, "Cannot Reset Slot %d, "
695703831d35Sstevel 				    "reg=%x\n", pslotnum,
695803831d35Sstevel 				    scsb_fru_op(scsb, SLOT, slotnum,
695903831d35Sstevel 				    SCTRL_RESET_BASE,
696003831d35Sstevel 				    SCSB_FRU_OP_GET_REGDATA));
696103831d35Sstevel #ifdef	DEBUG
696203831d35Sstevel 				if (alarm_card) {
696303831d35Sstevel 					if (!ac_val)
696403831d35Sstevel 						cmn_err(CE_WARN, "Cannot reset "
696503831d35Sstevel 						    "Alarm_RST#.\n");
696603831d35Sstevel 				}
696703831d35Sstevel #endif
696803831d35Sstevel 			}
696903831d35Sstevel 	}
697003831d35Sstevel 
697103831d35Sstevel 	mutex_exit(&scsb->scsb_mutex);
697203831d35Sstevel 	scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
697303831d35Sstevel 
697403831d35Sstevel 	return (error);
697503831d35Sstevel }
697603831d35Sstevel 
697703831d35Sstevel int
697803831d35Sstevel scsb_connect_slot(scsb_state_t *scsb, int pslotnum, int healthy)
697903831d35Sstevel {
698003831d35Sstevel 	int slotnum, count = 0, val;
698103831d35Sstevel 	int slot_flag = 0;
698203831d35Sstevel 
698303831d35Sstevel 	/*
698403831d35Sstevel 	 * If Power needs to be handled, it should be done here.
698503831d35Sstevel 	 * Since there is no power handling for now, lets disable
698603831d35Sstevel 	 * reset, wait for healthy to come on and then call it
698703831d35Sstevel 	 * connected.
698803831d35Sstevel 	 * If HLTHY# does not come on (in how long is the question)
698903831d35Sstevel 	 * then we stay disconnected.
699003831d35Sstevel 	 */
699103831d35Sstevel 	slotnum = tonga_psl_to_ssl(scsb, pslotnum);
699203831d35Sstevel 
699303831d35Sstevel 	/*
699403831d35Sstevel 	 * P1.5 doesnt require polling healthy as we get an
699503831d35Sstevel 	 * interrupt. So we could just update our state as disconnected
699603831d35Sstevel 	 * and return waiting for the healthy# interrupt. To make it
699703831d35Sstevel 	 * more efficient, lets poll for healthy# a short while since we are
699803831d35Sstevel 	 * in the interrupt context anyway. If we dont get a healthy# we
699903831d35Sstevel 	 * return, and then wait for the interrupt. Probably the warning
700003831d35Sstevel 	 * message needs to be removed then. Need a PROM check flag here.
700103831d35Sstevel 	 */
700203831d35Sstevel 	while ((healthy == B_FALSE) && (count < scsb_healthy_poll_count)) {
700303831d35Sstevel 		if (scsb_read_bhealthy(scsb) != 0)
700403831d35Sstevel 			return (DDI_FAILURE);
700503831d35Sstevel 		val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
700603831d35Sstevel 		    SCSB_FRU_OP_GET_BITVAL);
700703831d35Sstevel 		if (val) {
700803831d35Sstevel 			healthy = B_TRUE;
700903831d35Sstevel 			break;
701003831d35Sstevel 		}
701103831d35Sstevel 		count++;
701203831d35Sstevel 		drv_usecwait(100);	/* cant delay(9f) in intr context */
701303831d35Sstevel 	}
701403831d35Sstevel 
701503831d35Sstevel 	if (healthy == B_FALSE && count == scsb_healthy_poll_count) {
701603831d35Sstevel 		if (scsb_debug & 0x00004000)
701703831d35Sstevel 			cmn_err(CE_WARN, "%s#%d: no HEALTHY# signal on"
701803831d35Sstevel 			    " slot %d", ddi_driver_name(scsb->scsb_dev),
701903831d35Sstevel 			    ddi_get_instance(scsb->scsb_dev), pslotnum);
702003831d35Sstevel 	}
702103831d35Sstevel 
702203831d35Sstevel 	if ((scsb_is_alarm_card_slot(scsb, pslotnum) == B_TRUE) &&
702303831d35Sstevel 	    (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES))
702403831d35Sstevel 		slot_flag = ALARM_CARD_ON_SLOT;
702503831d35Sstevel 	return (hsc_slot_occupancy(pslotnum, 1, slot_flag, healthy));
702603831d35Sstevel }
702703831d35Sstevel 
702803831d35Sstevel int
702903831d35Sstevel scsb_disconnect_slot(scsb_state_t *scsb, int occupied, int slotnum)
703003831d35Sstevel {
703103831d35Sstevel 	int slot_flag = 0;
703203831d35Sstevel 
703303831d35Sstevel 	/* Reset is must at extraction. Move on even if failure. */
703403831d35Sstevel 	if (scsb_reset_slot(scsb, slotnum, SCSB_RESET_SLOT) != 0) {
703503831d35Sstevel 		/*
703603831d35Sstevel 		 * If board is still in slot, which means there is a manual
703703831d35Sstevel 		 * disconnection in progress, return failure.
703803831d35Sstevel 		 * Otherwise, a board was removed anyway; so we need to
703903831d35Sstevel 		 * update the status and move on.
704003831d35Sstevel 		 */
704103831d35Sstevel 		if (occupied == B_TRUE)
704203831d35Sstevel 			return (DDI_FAILURE);
704303831d35Sstevel 	}
704403831d35Sstevel 	/*
704503831d35Sstevel 	 * the following bug needs to be fixed.
704603831d35Sstevel 	 * When this function is called from scsb_intr, scsb_state already
704703831d35Sstevel 	 * clears the 'AC card present' bit.
704803831d35Sstevel 	 * However, hsc module doesn't depend on slot_flag during removal.
704903831d35Sstevel 	 */
705003831d35Sstevel 	if ((scsb_is_alarm_card_slot(scsb, slotnum) == B_TRUE) &&
705103831d35Sstevel 	    (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES))
705203831d35Sstevel 		slot_flag = ALARM_CARD_ON_SLOT;
705303831d35Sstevel 	return (hsc_slot_occupancy(slotnum, occupied, slot_flag, B_FALSE));
705403831d35Sstevel }
705503831d35Sstevel 
705603831d35Sstevel static int
705703831d35Sstevel scsb_is_alarm_card_slot(scsb_state_t *scsb, int slotnum)
705803831d35Sstevel {
705903831d35Sstevel 	return ((scsb->ac_slotnum == slotnum)? B_TRUE:B_FALSE);
706003831d35Sstevel }
706103831d35Sstevel 
706203831d35Sstevel /*
706303831d35Sstevel  * Invoked both by the hsc and the scsb module to exchanges necessary
706403831d35Sstevel  * information regarding the alarm card.
706503831d35Sstevel  * scsb calls this function to unconfigure the alarm card while the
706603831d35Sstevel  * hsc calls this function at different times to check busy status,
706703831d35Sstevel  * and during post hotswap insert operation so that the user process
706803831d35Sstevel  * if one waiting can configure the alarm card.
706903831d35Sstevel  */
707003831d35Sstevel int
707103831d35Sstevel scsb_hsc_ac_op(scsb_state_t *scsb, int pslotnum, int op)
707203831d35Sstevel {
707303831d35Sstevel 	int		rc = B_FALSE;
707403831d35Sstevel 	uint32_t	event_code;
707503831d35Sstevel 
707603831d35Sstevel 	if (!(scsb->scsb_hsc_state & SCSB_HSC_INIT &&
707703831d35Sstevel 	    scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES)) {
707803831d35Sstevel 		cmn_err(CE_WARN,
707903831d35Sstevel 		    "scsb: HSC not initialized or AC not present!");
708003831d35Sstevel 		return (rc);
708103831d35Sstevel 	}
708203831d35Sstevel 	switch (op) {
708303831d35Sstevel 		/* hsc -> scsb */
708403831d35Sstevel 		case SCSB_HSC_AC_BUSY:
708503831d35Sstevel 			if (scsb->scsb_hsc_state & SCSB_ALARM_CARD_IN_USE)
708603831d35Sstevel 				rc = B_TRUE;
708703831d35Sstevel 			break;
708803831d35Sstevel 
708903831d35Sstevel 		/* API -> scsb */
709003831d35Sstevel 		/*
709103831d35Sstevel 		 * NOTE: this could be called multiple times from envmond if
709203831d35Sstevel 		 * the daemon is reinitialized with SIGHUP, or stopped and
709303831d35Sstevel 		 * restarted.
709403831d35Sstevel 		 */
709503831d35Sstevel 		case SCSB_HSC_AC_SET_BUSY:
709603831d35Sstevel 			DEBUG0("AC SET BUSY\n");
709703831d35Sstevel 			if (scsb_debug & 0x00010000) {
709803831d35Sstevel 				cmn_err(CE_NOTE,
709903831d35Sstevel 				    "scsb_hsc_ac_op(SCSB_HSC_AC_SET_BUSY)");
710003831d35Sstevel 			}
710103831d35Sstevel 			scsb->scsb_hsc_state |= SCSB_ALARM_CARD_IN_USE;
710203831d35Sstevel 			rc = B_TRUE;
710303831d35Sstevel 			break;
710403831d35Sstevel 
710503831d35Sstevel 		/* hsc -> scsb */
710603831d35Sstevel 		case SCSB_HSC_AC_CONFIGURED:
710703831d35Sstevel 			DEBUG0("AC configured\n");
710803831d35Sstevel 			if (scsb_debug & 0x00010000) {
710903831d35Sstevel 				cmn_err(CE_NOTE,
711003831d35Sstevel 				"scsb_hsc_ac_op(SCSB_HSC_AC_CONFIGURED)");
711103831d35Sstevel 			}
711203831d35Sstevel 			/*
711303831d35Sstevel 			 * wakeup anyone waiting on AC to be configured
711403831d35Sstevel 			 * Send the ALARM_CARD_CONFIGURE Event to all scsb
711503831d35Sstevel 			 * open streams.
711603831d35Sstevel 			 */
711703831d35Sstevel 			event_code = SCTRL_EVENT_ALARM_INSERTION;
711803831d35Sstevel 			(void) scsb_queue_ops(scsb, QPUT_INT32, 1,
711903831d35Sstevel 			    &event_code, "scsb_hsc_ac_op");
712003831d35Sstevel 			rc = B_TRUE;
712103831d35Sstevel 			break;
712203831d35Sstevel 
712303831d35Sstevel 		/* hsc -> scsb */
712403831d35Sstevel 		case SCSB_HSC_AC_REMOVAL_ALERT:
712503831d35Sstevel 			DEBUG0("AC removal alert\n");
712603831d35Sstevel 			if (scsb_debug & 0x00010000) {
712703831d35Sstevel 				cmn_err(CE_NOTE,
712803831d35Sstevel 				"scsb_hsc_ac_op(SCSB_HSC_AC_REMOVAL_ALERT)");
712903831d35Sstevel 			}
713003831d35Sstevel 			/*
713103831d35Sstevel 			 * Inform (envmond)alarmcard.so that it should save
713203831d35Sstevel 			 * the AC configuration, stop the
713303831d35Sstevel 			 * heartbeat, and shutdown the RSC link.
713403831d35Sstevel 			 */
713503831d35Sstevel 			event_code = SCTRL_EVENT_ALARM_REMOVAL;
713603831d35Sstevel 			(void) scsb_queue_ops(scsb, QPUT_INT32, 1,
713703831d35Sstevel 			    &event_code, "scsb_hsc_ac_op");
713803831d35Sstevel 			rc = B_TRUE;
713903831d35Sstevel 			break;
714003831d35Sstevel 
714103831d35Sstevel 		/* API -> scsb -> hsc */
714203831d35Sstevel 		case SCSB_HSC_AC_UNCONFIGURE:
714303831d35Sstevel 			DEBUG0("AC unconfigure\n");
714403831d35Sstevel 			if (scsb_debug & 0x00010000) {
714503831d35Sstevel 				cmn_err(CE_NOTE,
714603831d35Sstevel 				    "scsb_hsc_ac_op(SCSB_HSC_AC_UNCONFIG"
714703831d35Sstevel 				    "URE), AC NOT BUSY");
714803831d35Sstevel 			}
714903831d35Sstevel 			/*
715003831d35Sstevel 			 * send notification back to HSC to
715103831d35Sstevel 			 * unconfigure the AC, now that the env monitor
715203831d35Sstevel 			 * has given permission to do so.
715303831d35Sstevel 			 */
715403831d35Sstevel 			scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_IN_USE;
7155*07d06da5SSurya Prakki 			hsc_ac_op((int)scsb->scsb_instance, pslotnum,
715603831d35Sstevel 			    SCSB_HSC_AC_UNCONFIGURE, NULL);
715703831d35Sstevel 			rc = B_TRUE;
715803831d35Sstevel 			break;
715903831d35Sstevel 		default:
716003831d35Sstevel 			break;
716103831d35Sstevel 	}
716203831d35Sstevel 
716303831d35Sstevel 	return (rc);
716403831d35Sstevel }
716503831d35Sstevel 
716603831d35Sstevel static void
716703831d35Sstevel scsb_healthy_intr(scsb_state_t *scsb, int pslotnum)
716803831d35Sstevel {
716903831d35Sstevel 	int val, slotnum;
717003831d35Sstevel 	int healthy = B_FALSE;
717103831d35Sstevel 
717203831d35Sstevel 	DEBUG1("Healthy Intr on slot %d\n", pslotnum);
717303831d35Sstevel 	/*
717403831d35Sstevel 	 * The interrupt source register can have the healthy
717503831d35Sstevel 	 * bit set for non-existing slot, e.g slot 7 on Tonga.
717603831d35Sstevel 	 * It can also be seen on the Tonga CPU slot. So we make
717703831d35Sstevel 	 * sure we have a valid slot before proceeding.
717803831d35Sstevel 	 */
717903831d35Sstevel 	if (scsb->scsb_state & SCSB_IS_TONGA) {
718003831d35Sstevel 		if (pslotnum > TG_MAX_SLOTS || pslotnum == SC_TG_CPU_SLOT) {
718103831d35Sstevel 			if (scsb_debug & 0x08000000)
718203831d35Sstevel 				cmn_err(CE_NOTE, "Healthy interrupt bit set for"
718303831d35Sstevel 				    " slot %d", pslotnum);
718403831d35Sstevel 		return;
718503831d35Sstevel 		}
718603831d35Sstevel 	} else {
718703831d35Sstevel 		if (pslotnum > MC_MAX_SLOTS || pslotnum == SC_MC_CPU_SLOT ||
718803831d35Sstevel 		    (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
718903831d35Sstevel 		    pslotnum == SC_MC_CTC_SLOT)) {
719003831d35Sstevel 			if (scsb_debug & 0x08000000)
719103831d35Sstevel 				cmn_err(CE_NOTE, "Healthy interrupt bit set for"
719203831d35Sstevel 				    " slot %d", pslotnum);
719303831d35Sstevel 		return;
719403831d35Sstevel 		}
719503831d35Sstevel 	}
719603831d35Sstevel 
719703831d35Sstevel 	/*
719803831d35Sstevel 	 * The board healthy registers are already read before entering
719903831d35Sstevel 	 * this routine
720003831d35Sstevel 	 */
720103831d35Sstevel 	slotnum = tonga_psl_to_ssl(scsb, pslotnum);
720203831d35Sstevel 
720303831d35Sstevel 	/*
720403831d35Sstevel 	 * P1.5. Following works since slots 1 through 8 are in the same reg
720503831d35Sstevel 	 */
720603831d35Sstevel 	val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
720703831d35Sstevel 	    SCSB_FRU_OP_GET_BITVAL);
720803831d35Sstevel 	if (val)
720903831d35Sstevel 		healthy = B_TRUE;
7210*07d06da5SSurya Prakki 	(void) scsb_hsc_board_healthy(pslotnum, healthy);
721103831d35Sstevel }
721203831d35Sstevel 
721303831d35Sstevel /*
721403831d35Sstevel  * This function will try to read from scsb irrespective of whether
721503831d35Sstevel  * SSB is present or SCB is frozen, to get the health kstat information.
721603831d35Sstevel  */
721703831d35Sstevel static int
721803831d35Sstevel scsb_blind_read(scsb_state_t *scsb, int op, uchar_t reg, int len,
721903831d35Sstevel 				uchar_t *rwbuf, int i2c_alloc)
722003831d35Sstevel {
722103831d35Sstevel 	i2c_transfer_t	*i2cxferp;
722203831d35Sstevel 	int		i, rlen, wlen, error = 0;
722303831d35Sstevel 
722403831d35Sstevel 	if (scsb_debug & 0x0800) {
722503831d35Sstevel 		cmn_err(CE_NOTE, "scsb_rdwr_register(scsb,%s,%x,%x,buf):",
722603831d35Sstevel 		    (op == I2C_WR) ? "write" : "read",  reg, len);
722703831d35Sstevel 	}
722803831d35Sstevel 
722903831d35Sstevel 	if (i2c_alloc) {
723003831d35Sstevel 		i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle, I2C_NOSLEEP);
723103831d35Sstevel 		if (i2cxferp == NULL) {
723203831d35Sstevel 			if (scsb_debug & 0x0042)
723303831d35Sstevel 				cmn_err(CE_WARN, "scsb_rdwr_register: "
723403831d35Sstevel 				    "i2ctx allocation failure");
723503831d35Sstevel 			return (ENOMEM);
723603831d35Sstevel 		}
723703831d35Sstevel 	} else {
723803831d35Sstevel 		i2cxferp = scsb->scsb_i2ctp;
723903831d35Sstevel 	}
724003831d35Sstevel 	switch (op) {
724103831d35Sstevel 	case I2C_WR:
724203831d35Sstevel 		wlen = len + 1;	/* add the address */
724303831d35Sstevel 		rlen = 0;
724403831d35Sstevel 		i2cxferp->i2c_wbuf[0] = reg;
724503831d35Sstevel 		for (i = 0; i < len; ++i) {
724603831d35Sstevel 				i2cxferp->i2c_wbuf[1 + i] = rwbuf[i];
724703831d35Sstevel 			if (scsb_debug & 0x0080)
724803831d35Sstevel 				cmn_err(CE_NOTE,
724903831d35Sstevel 				"scsb_rdwr_register: writing rwbuf[%d]=0x%x",
725003831d35Sstevel 				    i, rwbuf[i]);
725103831d35Sstevel 		}
725203831d35Sstevel 		break;
725303831d35Sstevel 	case I2C_WR_RD:
725403831d35Sstevel 		wlen = 1;	/* for the address */
725503831d35Sstevel 		rlen = len;
725603831d35Sstevel 		i2cxferp->i2c_wbuf[0] = reg;
725703831d35Sstevel 		break;
725803831d35Sstevel 	default:
725903831d35Sstevel 		if (i2c_alloc)
726003831d35Sstevel 			scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
726103831d35Sstevel 		return (EINVAL);
726203831d35Sstevel 	}
726303831d35Sstevel 	/* select the register address */
726403831d35Sstevel 	i2cxferp->i2c_flags = op;
726503831d35Sstevel 	i2cxferp->i2c_rlen = rlen;
726603831d35Sstevel 	i2cxferp->i2c_wlen = wlen;
726703831d35Sstevel 	i2cxferp->i2c_wbuf[0] = reg;
726803831d35Sstevel 	scsb->scsb_kstat_flag = B_TRUE;	/* we did a i2c transaction */
726903831d35Sstevel 	if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
727003831d35Sstevel 		error = EIO;
727103831d35Sstevel 	} else if (rlen) {
727203831d35Sstevel 		/* copy to rwbuf[] */
727303831d35Sstevel 		for (i = 0; i < len; ++i) {
727403831d35Sstevel 			rwbuf[i] = i2cxferp->i2c_rbuf[i];
727503831d35Sstevel 			if (scsb_debug & 0x0080)
727603831d35Sstevel 				cmn_err(CE_NOTE,
727703831d35Sstevel 				"scsb_rdwr_register: read rwbuf[%d]=0x%x",
727803831d35Sstevel 				    i, rwbuf[i]);
727903831d35Sstevel 		}
728003831d35Sstevel 	}
728103831d35Sstevel 	if (i2c_alloc)
728203831d35Sstevel 		scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
728303831d35Sstevel 	if (error) {
728403831d35Sstevel 		scsb->scsb_i2c_errcnt++;
728503831d35Sstevel 		if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
728603831d35Sstevel 			scsb->scsb_err_flag = B_TRUE; /* latch error */
728703831d35Sstevel 	} else {
728803831d35Sstevel 		scsb->scsb_i2c_errcnt = 0;
728903831d35Sstevel 	}
729003831d35Sstevel 
729103831d35Sstevel 	return (error);
729203831d35Sstevel }
729303831d35Sstevel 
729403831d35Sstevel /*
729503831d35Sstevel  * This function will quiesce the PSM_INT line by masking the
729603831d35Sstevel  * global PSM_INT and writing 1 to SCB_INIT ( for P1.5 and later )
729703831d35Sstevel  * This effectively translates to writing 0x20 to 0xE1 register.
729803831d35Sstevel  */
729903831d35Sstevel static int
730003831d35Sstevel scsb_quiesce_psmint(scsb_state_t *scsb)
730103831d35Sstevel {
730203831d35Sstevel 	register int	i;
730303831d35Sstevel 	uchar_t	reg, wdata = 0;
730403831d35Sstevel 	uchar_t	tmp_reg, intr_addr, clr_bits = 0;
730503831d35Sstevel 	int error, iid, intr_idx, offset;
730603831d35Sstevel 
730703831d35Sstevel 	/*
730803831d35Sstevel 	 * For P1.5, set the SCB_INIT bit in the System Command register,
730903831d35Sstevel 	 * and disable global PSM_INT. Before this we need to read the
731003831d35Sstevel 	 * interrupt source register corresponding to INIT_SCB and
731103831d35Sstevel 	 * clear if set.
731203831d35Sstevel 	 */
731303831d35Sstevel 	if (IS_SCB_P15) {
731403831d35Sstevel 		/*
731503831d35Sstevel 		 * Read INTSRC6 and write back 0x20 in case INIT_SCB is set
731603831d35Sstevel 		 */
731703831d35Sstevel 		intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
731803831d35Sstevel 		tmp_reg = SCSB_REG_ADDR(SCTRL_INTSRC_SCB_P15);
731903831d35Sstevel 		iid = SCSB_REG_INDEX(intr_addr);
732003831d35Sstevel 		intr_idx = SCSB_REG_INDEX(tmp_reg) - iid;
732103831d35Sstevel 		offset = FRU_OFFSET(SCTRL_EVENT_SCB, SCTRL_INTPTR_BASE);
732203831d35Sstevel 		clr_bits = 1 << offset;
732303831d35Sstevel 
732403831d35Sstevel 		error = scsb_rdwr_register(scsb, I2C_WR_RD, tmp_reg,
732503831d35Sstevel 		    1, &scb_intr_regs[intr_idx], 0);
732603831d35Sstevel 		/*
732703831d35Sstevel 		 * Now mask the global PSM_INT and write INIT_SCB in case
732803831d35Sstevel 		 * this is an INIT_SCB interrupt
732903831d35Sstevel 		 */
733003831d35Sstevel 		wdata = 1 << SYS_OFFSET(SCTRL_SYS_SCB_INIT);
733103831d35Sstevel 		i = SYS_REG_INDEX(SCTRL_SYS_SCB_INIT, SCTRL_SYS_CMD_BASE);
733203831d35Sstevel 		reg = SCSB_REG_ADDR(i);
733303831d35Sstevel 		error = scsb_rdwr_register(scsb, I2C_WR, reg, 1,
733403831d35Sstevel 		    &wdata, 0);
733503831d35Sstevel 
733603831d35Sstevel 		if (scb_intr_regs[intr_idx] & clr_bits) {
733703831d35Sstevel 			/*
733803831d35Sstevel 			 * There is an SCB_INIT interrupt, which we must clear
733903831d35Sstevel 			 * first to keep SCB_INIT from keeping PSM_INT asserted.
734003831d35Sstevel 			 */
734103831d35Sstevel 			error = scsb_rdwr_register(scsb, I2C_WR, tmp_reg,
734203831d35Sstevel 			    1, &clr_bits, 0);
734303831d35Sstevel 		}
734403831d35Sstevel 
734503831d35Sstevel 		if (error) {
734603831d35Sstevel 			cmn_err(CE_WARN, "scsb%d:scsb_quiesce_psmint: "
734703831d35Sstevel 			    " I2C TRANSFER Failed", scsb->scsb_instance);
734803831d35Sstevel 			if (scsb_debug & 0x0006) {
734903831d35Sstevel 				cmn_err(CE_NOTE, "scsb_attach: "
735003831d35Sstevel 				    " failed to set SCB_INIT");
735103831d35Sstevel 			}
735203831d35Sstevel 		}
735303831d35Sstevel 		scsb->scsb_state &= ~SCSB_PSM_INT_ENABLED;
735403831d35Sstevel 	} else { /* P1.0 or earlier */
735503831d35Sstevel 		/*
735603831d35Sstevel 		 * read the interrupt source registers, and then
735703831d35Sstevel 		 * write them back.
735803831d35Sstevel 		 */
735903831d35Sstevel 		/* read the interrupt register from scsb */
736003831d35Sstevel 		if (error = scsb_rdwr_register(scsb, I2C_WR_RD, intr_addr,
736103831d35Sstevel 		    SCTRL_INTR_NUMREGS, scb_intr_regs, 0)) {
736203831d35Sstevel 			cmn_err(CE_WARN, "scsb_intr: "
736303831d35Sstevel 			    " Failed read of interrupt registers.");
736403831d35Sstevel 			scsb->scsb_state &= ~SCSB_IN_INTR;
736503831d35Sstevel 		}
736603831d35Sstevel 
736703831d35Sstevel 		/*
736803831d35Sstevel 		 * Write to the interrupt source registers to stop scsb
736903831d35Sstevel 		 * from interrupting.
737003831d35Sstevel 		 */
737103831d35Sstevel 		if (error = scsb_rdwr_register(scsb, I2C_WR, intr_addr,
737203831d35Sstevel 		    SCTRL_INTR_NUMREGS, scb_intr_regs, 0)) {
737303831d35Sstevel 			cmn_err(CE_WARN, "scsb_intr: Failed write to interrupt"
737403831d35Sstevel 			    " registers.");
737503831d35Sstevel 			scsb->scsb_state &= ~SCSB_IN_INTR;
737603831d35Sstevel 		}
737703831d35Sstevel 
737803831d35Sstevel 	}
737903831d35Sstevel 
738003831d35Sstevel 	if (error)
738103831d35Sstevel 		return (DDI_FAILURE);
738203831d35Sstevel 	else
738303831d35Sstevel 		return (DDI_SUCCESS);
738403831d35Sstevel }
738503831d35Sstevel 
738603831d35Sstevel /*
738703831d35Sstevel  * Enables or disables the global PSM_INT interrupt for P1.5, depending
738803831d35Sstevel  * on the flag, flag = 0 => disable, else enable.
738903831d35Sstevel  */
739003831d35Sstevel static int
739103831d35Sstevel scsb_toggle_psmint(scsb_state_t *scsb, int enable)
739203831d35Sstevel {
739303831d35Sstevel 	int i;
739403831d35Sstevel 	uchar_t reg, on = 0, rmask = 0x0, off = 0;
739503831d35Sstevel 
739603831d35Sstevel 	if (enable == B_TRUE) {
739703831d35Sstevel 		on = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
739803831d35Sstevel 	} else {
739903831d35Sstevel 		off = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
740003831d35Sstevel 	}
740103831d35Sstevel 
740203831d35Sstevel 	i = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE, SCTRL_SYS_CMD_BASE);
740303831d35Sstevel 	reg = SCSB_REG_ADDR(i);
740403831d35Sstevel 	if (scsb_write_mask(scsb, reg, rmask, on, off)) {
740503831d35Sstevel 		cmn_err(CE_WARN, "scsb_toggle_psmint: Cannot turn %s PSM_INT",
740603831d35Sstevel 		    enable == 1 ? "on" : "off");
740703831d35Sstevel 		return (DDI_FAILURE);
740803831d35Sstevel 	}
740903831d35Sstevel 	if (enable == 0) {
741003831d35Sstevel 		scsb->scsb_state &= ~SCSB_PSM_INT_ENABLED;
741103831d35Sstevel 	} else {
741203831d35Sstevel 		scsb->scsb_state |= SCSB_PSM_INT_ENABLED;
741303831d35Sstevel 	}
741403831d35Sstevel 
741503831d35Sstevel 	return (DDI_SUCCESS);
741603831d35Sstevel }
741703831d35Sstevel 
741803831d35Sstevel /*
741903831d35Sstevel  * This routine is to be used by all the drivers using this i2c bus
742003831d35Sstevel  * to synchronize their transfer operations.
742103831d35Sstevel  */
742203831d35Sstevel int
742303831d35Sstevel nct_i2c_transfer(i2c_client_hdl_t i2c_hdl, i2c_transfer_t *i2c_tran)
742403831d35Sstevel {
742503831d35Sstevel 	int retval, initmux = nct_mutex_init;
742603831d35Sstevel 
742703831d35Sstevel 	/*
742803831d35Sstevel 	 * If scsb interrupt mutex is initialized, also hold the
742903831d35Sstevel 	 * interrupt mutex to let the i2c_transfer() to complete
743003831d35Sstevel 	 */
743103831d35Sstevel 
743203831d35Sstevel 	if (initmux & MUTEX_INIT) {
743303831d35Sstevel 		mutex_enter(scb_intr_mutex);
743403831d35Sstevel 	}
743503831d35Sstevel 
743603831d35Sstevel 	retval = i2c_transfer(i2c_hdl, i2c_tran);
743703831d35Sstevel 
743803831d35Sstevel 	if (initmux & MUTEX_INIT) {
743903831d35Sstevel 		mutex_exit(scb_intr_mutex);
744003831d35Sstevel 	}
744103831d35Sstevel 
744203831d35Sstevel 	return (retval);
744303831d35Sstevel }
7444