xref: /titanic_51/usr/src/uts/sun4u/starcat/io/iosram.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 /*
23d3d50737SRafael Vanoni  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel /*
2803831d35Sstevel  * IOSRAM leaf driver to SBBC nexus driver.  This driver is used
2903831d35Sstevel  * by Starcat Domain SW to read/write from/to the IO sram.
3003831d35Sstevel  */
3103831d35Sstevel 
3203831d35Sstevel #include <sys/types.h>
3303831d35Sstevel #include <sys/conf.h>
3403831d35Sstevel #include <sys/ddi.h>
3503831d35Sstevel #include <sys/sunddi.h>
3603831d35Sstevel #include <sys/ddi_impldefs.h>
3703831d35Sstevel #include <sys/obpdefs.h>
3803831d35Sstevel #include <sys/promif.h>
3903831d35Sstevel #include <sys/prom_plat.h>
4003831d35Sstevel #include <sys/cmn_err.h>
4103831d35Sstevel #include <sys/conf.h>		/* req. by dev_ops flags MTSAFE etc. */
4203831d35Sstevel #include <sys/modctl.h>		/* for modldrv */
4303831d35Sstevel #include <sys/stat.h>		/* ddi_create_minor_node S_IFCHR */
4403831d35Sstevel #include <sys/errno.h>
4503831d35Sstevel #include <sys/kmem.h>
4603831d35Sstevel #include <sys/kstat.h>
4703831d35Sstevel #include <sys/debug.h>
4803831d35Sstevel 
4903831d35Sstevel #include <sys/axq.h>
5003831d35Sstevel #include <sys/iosramreg.h>
5103831d35Sstevel #include <sys/iosramio.h>
5203831d35Sstevel #include <sys/iosramvar.h>
5303831d35Sstevel 
5403831d35Sstevel 
5503831d35Sstevel #if defined(DEBUG)
5603831d35Sstevel int	iosram_debug = 0;
5703831d35Sstevel static void iosram_dprintf(const char *fmt, ...);
5803831d35Sstevel #define	DPRINTF(level, arg)	\
5903831d35Sstevel 		{ if (iosram_debug >= level) iosram_dprintf arg; }
6003831d35Sstevel #else	/* !DEBUG */
6103831d35Sstevel #define	DPRINTF(level, arg)
6203831d35Sstevel #endif	/* !DEBUG */
6303831d35Sstevel 
6403831d35Sstevel 
6503831d35Sstevel /*
6603831d35Sstevel  * IOSRAM module global state
6703831d35Sstevel  */
6803831d35Sstevel static void	*iosramsoft_statep;	/* IOSRAM state pointer */
6903831d35Sstevel static kmutex_t	iosram_mutex;		/* mutex lock */
7003831d35Sstevel 
7103831d35Sstevel static iosram_chunk_t	*chunks = NULL;	/* array of TOC entries */
7203831d35Sstevel static int	nchunks = 0;		/* # of TOC entries */
7303831d35Sstevel static iosram_chunk_t	*iosram_hashtab[IOSRAM_HASHSZ];	/* key hash table */
7403831d35Sstevel 
7503831d35Sstevel static kcondvar_t	iosram_tswitch_wait;	/* tunnel switch wait cv */
7603831d35Sstevel static int	iosram_tswitch_wakeup = 0;	/* flag indicationg one or */
7703831d35Sstevel 						/* more threads waiting on */
7803831d35Sstevel 						/* iosram_tswitch_wait cv */
7903831d35Sstevel static int	iosram_tswitch_active = 0;	/* tunnel switch active flag */
8003831d35Sstevel static int	iosram_tswitch_aborted = 0;	/* tunnel switch abort flag */
8103831d35Sstevel static clock_t	iosram_tswitch_tstamp = 0;	/* lbolt of last tswitch end */
8203831d35Sstevel static kcondvar_t	iosram_rw_wait;		/* read/write wait cv */
8303831d35Sstevel static int	iosram_rw_wakeup = 0;		/* flag indicationg one or */
8403831d35Sstevel 						/* more threads waiting on */
8503831d35Sstevel 						/* iosram_rw_wait cv */
8603831d35Sstevel static int	iosram_rw_active = 0;		/* # threads accessing IOSRAM */
8703831d35Sstevel #if defined(DEBUG)
8803831d35Sstevel static int	iosram_rw_active_max = 0;
8903831d35Sstevel #endif
9003831d35Sstevel 
9103831d35Sstevel static struct iosramsoft *iosram_new_master = NULL;	/* new tunnel target */
9203831d35Sstevel static struct iosramsoft *iosram_master = NULL;		/* master tunnel */
9303831d35Sstevel static struct iosramsoft *iosram_instances = NULL;	/* list of softstates */
9403831d35Sstevel 
9503831d35Sstevel static ddi_acc_handle_t	iosram_handle = NULL;	/* master IOSRAM map handle */
9603831d35Sstevel 
9703831d35Sstevel static void	(*iosram_hdrchange_handler)() = NULL;
9803831d35Sstevel 
9903831d35Sstevel #if IOSRAM_STATS
10003831d35Sstevel static struct	iosram_stat iosram_stats;	/* IOSRAM statistics */
10103831d35Sstevel static void	iosram_print_stats();		/* forward declaration */
10203831d35Sstevel #endif /* IOSRAM_STATS */
10303831d35Sstevel 
10403831d35Sstevel 
10503831d35Sstevel #if IOSRAM_LOG
10603831d35Sstevel kmutex_t 	iosram_log_mutex;
10703831d35Sstevel int		iosram_log_level = 1;
10803831d35Sstevel int		iosram_log_print = 0;		/* print log when recorded */
10903831d35Sstevel uint32_t	iosram_logseq;
11003831d35Sstevel iosram_log_t	iosram_logbuf[IOSRAM_MAXLOG];
11103831d35Sstevel static void	iosram_print_log(int cnt);	/* forward declaration */
11203831d35Sstevel #endif	/* IOSRAM_LOG */
11303831d35Sstevel 
11403831d35Sstevel 
11503831d35Sstevel /* driver entry point fn definitions */
11603831d35Sstevel static int 	iosram_open(dev_t *, int, int, cred_t *);
11703831d35Sstevel static int	iosram_close(dev_t, int, int, cred_t *);
11803831d35Sstevel static int	iosram_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
11903831d35Sstevel 
12003831d35Sstevel /* configuration entry point fn definitions */
12103831d35Sstevel static int 	iosram_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
12203831d35Sstevel static int	iosram_attach(dev_info_t *, ddi_attach_cmd_t);
12303831d35Sstevel static int	iosram_detach(dev_info_t *, ddi_detach_cmd_t);
12403831d35Sstevel 
12503831d35Sstevel 
12603831d35Sstevel /* forward declaractions */
12703831d35Sstevel static iosram_chunk_t	*iosram_find_chunk(uint32_t key);
12803831d35Sstevel static void	iosram_set_master(struct iosramsoft *softp);
12903831d35Sstevel static int	iosram_is_chosen(struct iosramsoft *softp);
13003831d35Sstevel static int	iosram_tunnel_capable(struct iosramsoft *softp);
13103831d35Sstevel static int	iosram_read_toc(struct iosramsoft *softp);
13203831d35Sstevel static void	iosram_init_hashtab(void);
13303831d35Sstevel static void	iosram_update_addrs(struct iosramsoft *softp);
13403831d35Sstevel 
13503831d35Sstevel static int	iosram_setup_map(struct iosramsoft *softp);
13603831d35Sstevel static void	iosram_remove_map(struct iosramsoft *softp);
13703831d35Sstevel static int	iosram_add_intr(iosramsoft_t *);
13803831d35Sstevel static int	iosram_remove_intr(iosramsoft_t *);
13903831d35Sstevel 
14003831d35Sstevel static void	iosram_add_instance(struct iosramsoft *softp);
14103831d35Sstevel static void	iosram_remove_instance(int instance);
14203831d35Sstevel static int	iosram_switch_tunnel(iosramsoft_t *softp);
14303831d35Sstevel static void	iosram_abort_tswitch();
14403831d35Sstevel 
14503831d35Sstevel #if defined(DEBUG)
14603831d35Sstevel /* forward declaractions for debugging */
14703831d35Sstevel static int	iosram_get_keys(iosram_toc_entry_t *buf, uint32_t *len);
14803831d35Sstevel static void	iosram_print_cback();
14903831d35Sstevel static void	iosram_print_state(int);
15003831d35Sstevel static void	iosram_print_flags();
15103831d35Sstevel #endif
15203831d35Sstevel 
15303831d35Sstevel 
15403831d35Sstevel 
15503831d35Sstevel /*
15603831d35Sstevel  * cb_ops
15703831d35Sstevel  */
15803831d35Sstevel static struct cb_ops iosram_cb_ops = {
15903831d35Sstevel 	iosram_open,		/* cb_open */
16003831d35Sstevel 	iosram_close,		/* cb_close */
16103831d35Sstevel 	nodev,			/* cb_strategy */
16203831d35Sstevel 	nodev,			/* cb_print */
16303831d35Sstevel 	nodev,			/* cb_dump */
16403831d35Sstevel 	nodev,			/* cb_read */
16503831d35Sstevel 	nodev,			/* cb_write */
16603831d35Sstevel 	iosram_ioctl,		/* cb_ioctl */
16703831d35Sstevel 	nodev,			/* cb_devmap */
16803831d35Sstevel 	nodev,			/* cb_mmap */
16903831d35Sstevel 	nodev,			/* cb_segmap */
17003831d35Sstevel 	nochpoll,		/* cb_chpoll */
17103831d35Sstevel 	ddi_prop_op,		/* cb_prop_op */
17203831d35Sstevel 	NULL,			/* cb_stream */
17303831d35Sstevel 	(int)(D_NEW | D_MP | D_HOTPLUG)	/* cb_flag */
17403831d35Sstevel };
17503831d35Sstevel 
17603831d35Sstevel /*
17703831d35Sstevel  * Declare ops vectors for auto configuration.
17803831d35Sstevel  */
17903831d35Sstevel struct dev_ops  iosram_ops = {
18003831d35Sstevel 	DEVO_REV,		/* devo_rev */
18103831d35Sstevel 	0,			/* devo_refcnt */
18203831d35Sstevel 	iosram_getinfo,		/* devo_getinfo */
18303831d35Sstevel 	nulldev,		/* devo_identify */
18403831d35Sstevel 	nulldev,		/* devo_probe */
18503831d35Sstevel 	iosram_attach,		/* devo_attach */
18603831d35Sstevel 	iosram_detach,		/* devo_detach */
18703831d35Sstevel 	nodev,			/* devo_reset */
18803831d35Sstevel 	&iosram_cb_ops,		/* devo_cb_ops */
18903831d35Sstevel 	(struct bus_ops *)NULL,	/* devo_bus_ops */
19019397407SSherry Moore 	nulldev,		/* devo_power */
19119397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
19203831d35Sstevel };
19303831d35Sstevel 
19403831d35Sstevel /*
19503831d35Sstevel  * Loadable module support.
19603831d35Sstevel  */
19703831d35Sstevel extern struct mod_ops mod_driverops;
19803831d35Sstevel 
19903831d35Sstevel static struct modldrv iosrammodldrv = {
20003831d35Sstevel 	&mod_driverops,		/* type of module - driver */
20119397407SSherry Moore 	"IOSRAM Leaf driver",
20203831d35Sstevel 	&iosram_ops,
20303831d35Sstevel };
20403831d35Sstevel 
20503831d35Sstevel static struct modlinkage iosrammodlinkage = {
20603831d35Sstevel 	MODREV_1,
20703831d35Sstevel 	&iosrammodldrv,
20803831d35Sstevel 	NULL
20903831d35Sstevel };
21003831d35Sstevel 
21103831d35Sstevel 
21203831d35Sstevel int
21303831d35Sstevel _init(void)
21403831d35Sstevel {
21503831d35Sstevel 	int    error;
21603831d35Sstevel 	int	i;
21703831d35Sstevel 
21803831d35Sstevel 	mutex_init(&iosram_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
21903831d35Sstevel 	cv_init(&iosram_tswitch_wait, NULL, CV_DRIVER, NULL);
22003831d35Sstevel 	cv_init(&iosram_rw_wait, NULL, CV_DRIVER, NULL);
22103831d35Sstevel #if defined(IOSRAM_LOG)
22203831d35Sstevel 	mutex_init(&iosram_log_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
22303831d35Sstevel #endif
22403831d35Sstevel 
22503831d35Sstevel 	DPRINTF(1, ("_init:IOSRAM\n"));
22603831d35Sstevel 
22703831d35Sstevel 	for (i = 0; i < IOSRAM_HASHSZ; i++) {
22803831d35Sstevel 		iosram_hashtab[i] = NULL;
22903831d35Sstevel 	}
23003831d35Sstevel 
23103831d35Sstevel 	if ((error = ddi_soft_state_init(&iosramsoft_statep,
23203831d35Sstevel 	    sizeof (struct iosramsoft), 1)) != 0) {
23303831d35Sstevel 		goto failed;
23403831d35Sstevel 	}
23503831d35Sstevel 	if ((error = mod_install(&iosrammodlinkage)) != 0) {
23603831d35Sstevel 		ddi_soft_state_fini(&iosramsoft_statep);
23703831d35Sstevel 		goto failed;
23803831d35Sstevel 	}
23903831d35Sstevel 
24003831d35Sstevel 	IOSRAMLOG(0, "_init:IOSRAM ... error:%d  statep:%p\n",
24103831d35Sstevel 	    error, iosramsoft_statep, NULL, NULL);
24203831d35Sstevel 
24303831d35Sstevel 	return (error);
24403831d35Sstevel 
24503831d35Sstevel failed:
24603831d35Sstevel 	cv_destroy(&iosram_tswitch_wait);
24703831d35Sstevel 	cv_destroy(&iosram_rw_wait);
24803831d35Sstevel 	mutex_destroy(&iosram_mutex);
24903831d35Sstevel #if defined(IOSRAM_LOG)
25003831d35Sstevel 	mutex_destroy(&iosram_log_mutex);
25103831d35Sstevel #endif
25203831d35Sstevel 	IOSRAMLOG(0, "_init:IOSRAM ... error:%d  statep:%p\n",
25303831d35Sstevel 	    error, iosramsoft_statep, NULL, NULL);
25403831d35Sstevel 
25503831d35Sstevel 	return (error);
25603831d35Sstevel }
25703831d35Sstevel 
25803831d35Sstevel 
25903831d35Sstevel int
26003831d35Sstevel _fini(void)
26103831d35Sstevel {
26203831d35Sstevel #ifndef DEBUG
26303831d35Sstevel 	return (EBUSY);
26403831d35Sstevel #else /* !DEBUG */
26503831d35Sstevel 	int    error;
26603831d35Sstevel 
26703831d35Sstevel 	if ((error = mod_remove(&iosrammodlinkage)) == 0) {
26803831d35Sstevel 		ddi_soft_state_fini(&iosramsoft_statep);
26903831d35Sstevel 
27003831d35Sstevel 		cv_destroy(&iosram_tswitch_wait);
27103831d35Sstevel 		cv_destroy(&iosram_rw_wait);
27203831d35Sstevel 		mutex_destroy(&iosram_mutex);
27303831d35Sstevel #if defined(IOSRAM_LOG)
27403831d35Sstevel 		mutex_destroy(&iosram_log_mutex);
27503831d35Sstevel #endif
27603831d35Sstevel 	}
27703831d35Sstevel 	DPRINTF(1, ("_fini:IOSRAM  error:%d\n", error));
27803831d35Sstevel 
27903831d35Sstevel 	return (error);
28003831d35Sstevel #endif /* !DEBUG */
28103831d35Sstevel }
28203831d35Sstevel 
28303831d35Sstevel 
28403831d35Sstevel int
28503831d35Sstevel _info(struct modinfo *modinfop)
28603831d35Sstevel {
28703831d35Sstevel 	return (mod_info(&iosrammodlinkage, modinfop));
28803831d35Sstevel }
28903831d35Sstevel 
29003831d35Sstevel 
29103831d35Sstevel static int
29203831d35Sstevel iosram_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
29303831d35Sstevel {
29403831d35Sstevel 	int	instance;
29503831d35Sstevel 	int	propval;
29603831d35Sstevel 	int	length;
29703831d35Sstevel 	char	name[32];
29803831d35Sstevel 	struct	iosramsoft *softp;
29903831d35Sstevel 
30003831d35Sstevel 	instance = ddi_get_instance(dip);
30103831d35Sstevel 
302*07d06da5SSurya Prakki 	DPRINTF(1, ("iosram(%d): attach dip:%p\n", instance, (void *)dip));
30303831d35Sstevel 
30403831d35Sstevel 	IOSRAMLOG(1, "ATTACH: dip:%p instance %d ... start\n",
30503831d35Sstevel 	    dip, instance, NULL, NULL);
30603831d35Sstevel 	switch (cmd) {
30703831d35Sstevel 	case DDI_ATTACH:
30803831d35Sstevel 		break;
30903831d35Sstevel 	case DDI_RESUME:
31003831d35Sstevel 		if (!(softp = ddi_get_soft_state(iosramsoft_statep,
31103831d35Sstevel 		    instance))) {
31203831d35Sstevel 			return (DDI_FAILURE);
31303831d35Sstevel 		}
31403831d35Sstevel 		mutex_enter(&iosram_mutex);
31503831d35Sstevel 		mutex_enter(&softp->intr_mutex);
31603831d35Sstevel 		if (!softp->suspended) {
31703831d35Sstevel 			mutex_exit(&softp->intr_mutex);
31803831d35Sstevel 			mutex_exit(&iosram_mutex);
31903831d35Sstevel 			return (DDI_FAILURE);
32003831d35Sstevel 		}
32103831d35Sstevel 		softp->suspended = 0;
32203831d35Sstevel 
32303831d35Sstevel 		/*
32403831d35Sstevel 		 * enable SBBC interrupts if SBBC is mapped in
32503831d35Sstevel 		 * restore the value saved during detach
32603831d35Sstevel 		 */
32703831d35Sstevel 		if (softp->sbbc_region) {
32803831d35Sstevel 			ddi_put32(softp->sbbc_handle,
32903831d35Sstevel 			    &(softp->sbbc_region->int_enable.reg),
33003831d35Sstevel 			    softp->int_enable_sav);
33103831d35Sstevel 		}
33203831d35Sstevel 
33303831d35Sstevel 		/*
33403831d35Sstevel 		 * Trigger soft interrupt handler to process any pending
33503831d35Sstevel 		 * interrupts.
33603831d35Sstevel 		 */
33703831d35Sstevel 		if (softp->intr_pending && !softp->intr_busy &&
33803831d35Sstevel 		    (softp->softintr_id != NULL)) {
33903831d35Sstevel 			ddi_trigger_softintr(softp->softintr_id);
34003831d35Sstevel 		}
34103831d35Sstevel 
34203831d35Sstevel 		mutex_exit(&softp->intr_mutex);
34303831d35Sstevel 		mutex_exit(&iosram_mutex);
34403831d35Sstevel 
34503831d35Sstevel 		return (DDI_SUCCESS);
34603831d35Sstevel 
34703831d35Sstevel 	default:
34803831d35Sstevel 		return (DDI_FAILURE);
34903831d35Sstevel 	}
35003831d35Sstevel 
35103831d35Sstevel 	if (ddi_soft_state_zalloc(iosramsoft_statep, instance) != 0) {
35203831d35Sstevel 		return (DDI_FAILURE);
35303831d35Sstevel 	}
35403831d35Sstevel 
35503831d35Sstevel 	if ((softp = ddi_get_soft_state(iosramsoft_statep, instance)) == NULL) {
35603831d35Sstevel 			return (DDI_FAILURE);
35703831d35Sstevel 	}
35803831d35Sstevel 	softp->dip = dip;
35903831d35Sstevel 	softp->instance = instance;
36003831d35Sstevel 	softp->sbbc_region = NULL;
36103831d35Sstevel 
36203831d35Sstevel 	/*
36303831d35Sstevel 	 * If this instance is not tunnel capable, we don't attach it.
36403831d35Sstevel 	 */
36503831d35Sstevel 	if (iosram_tunnel_capable(softp) == 0) {
36603831d35Sstevel 		DPRINTF(1, ("iosram(%d): not tunnel_capable\n", instance));
36703831d35Sstevel 		IOSRAMLOG(1, "ATTACH(%d): not tunnel_capable\n", instance, NULL,
36803831d35Sstevel 		    NULL, NULL);
36903831d35Sstevel 		goto attach_fail;
37003831d35Sstevel 	}
37103831d35Sstevel 
37203831d35Sstevel 	/*
37303831d35Sstevel 	 * Need to create an "interrupt-priorities" property to define the PIL
37403831d35Sstevel 	 * to be used with the interrupt service routine.
37503831d35Sstevel 	 */
37603831d35Sstevel 	if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
37703831d35Sstevel 	    "interrupt-priorities", &length) == DDI_PROP_NOT_FOUND) {
37803831d35Sstevel 		DPRINTF(1, ("iosram(%d): creating interrupt priority property",
37903831d35Sstevel 		    instance));
38003831d35Sstevel 		propval = IOSRAM_PIL;
38103831d35Sstevel 		if (ddi_prop_create(DDI_DEV_T_NONE, dip, 0,
38203831d35Sstevel 		    "interrupt-priorities", (caddr_t)&propval, sizeof (propval))
38303831d35Sstevel 		    != DDI_PROP_SUCCESS) {
38403831d35Sstevel 			cmn_err(CE_WARN,
38503831d35Sstevel 			    "iosram_attach: failed to create property");
38603831d35Sstevel 			goto attach_fail;
38703831d35Sstevel 		}
38803831d35Sstevel 	}
38903831d35Sstevel 
39003831d35Sstevel 	/*
39103831d35Sstevel 	 * Get interrupts cookies and initialize per-instance mutexes
39203831d35Sstevel 	 */
39303831d35Sstevel 	if (ddi_get_iblock_cookie(softp->dip, 0, &softp->real_iblk)
39403831d35Sstevel 	    != DDI_SUCCESS) {
39503831d35Sstevel 		IOSRAMLOG(1, "ATTACH(%d): cannot get soft intr cookie\n",
39603831d35Sstevel 		    instance, NULL, NULL, NULL);
39703831d35Sstevel 		goto attach_fail;
39803831d35Sstevel 	}
39903831d35Sstevel 	mutex_init(&softp->intr_mutex, NULL, MUTEX_DRIVER,
40003831d35Sstevel 	    (void *)softp->real_iblk);
40103831d35Sstevel 
40203831d35Sstevel 	/*
40303831d35Sstevel 	 * Add this instance to the iosram_instances list so that it can be used
40403831d35Sstevel 	 * for tunnel in future.
40503831d35Sstevel 	 */
40603831d35Sstevel 	mutex_enter(&iosram_mutex);
40703831d35Sstevel 	softp->state = IOSRAM_STATE_INIT;
40803831d35Sstevel 	iosram_add_instance(softp);
40903831d35Sstevel 
41003831d35Sstevel 	/*
41103831d35Sstevel 	 * If this is the chosen IOSRAM and there is no master IOSRAM yet, then
41203831d35Sstevel 	 * let's set this instance as the master.
41303831d35Sstevel 	 */
41403831d35Sstevel 	if (iosram_master == NULL && iosram_is_chosen(softp)) {
415*07d06da5SSurya Prakki 		(void) iosram_switch_tunnel(softp);
41603831d35Sstevel 
41703831d35Sstevel 		/*
41803831d35Sstevel 		 * XXX Do we need to panic if unable to setup master IOSRAM?
41903831d35Sstevel 		 */
42003831d35Sstevel 		if (iosram_master == NULL) {
42103831d35Sstevel 			cmn_err(CE_WARN,
42203831d35Sstevel 			    "iosram(%d): can't setup master tunnel\n",
42303831d35Sstevel 			    instance);
42403831d35Sstevel 			softp->state = 0;
42503831d35Sstevel 			iosram_remove_instance(softp->instance);
42603831d35Sstevel 			mutex_exit(&iosram_mutex);
42703831d35Sstevel 			mutex_destroy(&softp->intr_mutex);
42803831d35Sstevel 			goto attach_fail;
42903831d35Sstevel 		}
43003831d35Sstevel 	}
43103831d35Sstevel 
43203831d35Sstevel 	mutex_exit(&iosram_mutex);
43303831d35Sstevel 
43403831d35Sstevel 	/*
43503831d35Sstevel 	 * Create minor node
43603831d35Sstevel 	 */
43703831d35Sstevel 	(void) sprintf(name, "iosram%d", instance);
43803831d35Sstevel 	if (ddi_create_minor_node(dip, name, S_IFCHR, instance, NULL, NULL) ==
43903831d35Sstevel 	    DDI_FAILURE) {
44003831d35Sstevel 		/*
44103831d35Sstevel 		 * Minor node seems to be needed only for debugging purposes.
44203831d35Sstevel 		 * Therefore, there is no need to fail this attach request.
44303831d35Sstevel 		 * Simply print a message out.
44403831d35Sstevel 		 */
44503831d35Sstevel 		cmn_err(CE_NOTE, "!iosram(%d): can't create minor node\n",
44603831d35Sstevel 		    instance);
44703831d35Sstevel 	}
44803831d35Sstevel 	ddi_report_dev(dip);
44903831d35Sstevel 
45003831d35Sstevel 	DPRINTF(1, ("iosram_attach(%d): success.\n", instance));
45103831d35Sstevel 	IOSRAMLOG(1, "ATTACH: dip:%p instance:%d ... success  softp:%p\n",
45203831d35Sstevel 	    dip, instance, softp, NULL);
45303831d35Sstevel 
45403831d35Sstevel 	return (DDI_SUCCESS);
45503831d35Sstevel 
45603831d35Sstevel attach_fail:
45703831d35Sstevel 	DPRINTF(1, ("iosram_attach(%d):failed.\n", instance));
45803831d35Sstevel 	IOSRAMLOG(1, "ATTACH: dip:%p instance:%d ... failed.\n",
45903831d35Sstevel 	    dip, instance, NULL, NULL);
46003831d35Sstevel 
46103831d35Sstevel 	ddi_soft_state_free(iosramsoft_statep, instance);
46203831d35Sstevel 	return (DDI_FAILURE);
46303831d35Sstevel }
46403831d35Sstevel 
46503831d35Sstevel 
46603831d35Sstevel static int
46703831d35Sstevel iosram_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
46803831d35Sstevel {
46903831d35Sstevel 	int			instance;
47003831d35Sstevel 	struct iosramsoft	*softp;
47103831d35Sstevel 
47203831d35Sstevel 	instance = ddi_get_instance(dip);
47303831d35Sstevel 	if (!(softp = ddi_get_soft_state(iosramsoft_statep, instance))) {
47403831d35Sstevel 		return (DDI_FAILURE);
47503831d35Sstevel 	}
47603831d35Sstevel 
47703831d35Sstevel 	IOSRAMLOG(1, "DETACH: dip:%p instance %d softp:%p\n",
47803831d35Sstevel 	    dip, instance, softp, NULL);
47903831d35Sstevel 
48003831d35Sstevel 	switch (cmd) {
48103831d35Sstevel 	case DDI_DETACH:
48203831d35Sstevel 		break;
48303831d35Sstevel 	case DDI_SUSPEND:
48403831d35Sstevel 		mutex_enter(&iosram_mutex);
48503831d35Sstevel 		mutex_enter(&softp->intr_mutex);
48603831d35Sstevel 		if (softp->suspended) {
48703831d35Sstevel 			mutex_exit(&softp->intr_mutex);
48803831d35Sstevel 			mutex_exit(&iosram_mutex);
48903831d35Sstevel 			return (DDI_FAILURE);
49003831d35Sstevel 		}
49103831d35Sstevel 		softp->suspended = 1;
49203831d35Sstevel 		/*
49303831d35Sstevel 		 * Disable SBBC interrupts if SBBC is mapped in
49403831d35Sstevel 		 */
49503831d35Sstevel 		if (softp->sbbc_region) {
49603831d35Sstevel 			/* save current interrupt enable register */
49703831d35Sstevel 			softp->int_enable_sav = ddi_get32(softp->sbbc_handle,
49803831d35Sstevel 			    &(softp->sbbc_region->int_enable.reg));
49903831d35Sstevel 			ddi_put32(softp->sbbc_handle,
50003831d35Sstevel 			    &(softp->sbbc_region->int_enable.reg), 0x0);
50103831d35Sstevel 		}
50203831d35Sstevel 		mutex_exit(&softp->intr_mutex);
50303831d35Sstevel 		mutex_exit(&iosram_mutex);
50403831d35Sstevel 		return (DDI_SUCCESS);
50503831d35Sstevel 
50603831d35Sstevel 	default:
50703831d35Sstevel 		return (DDI_FAILURE);
50803831d35Sstevel 	}
50903831d35Sstevel 
51003831d35Sstevel 
51103831d35Sstevel 	/*
51203831d35Sstevel 	 * Indicate that this instance is being detached so that this instance
51303831d35Sstevel 	 * does not become a target for tunnel switch in future.
51403831d35Sstevel 	 */
51503831d35Sstevel 	mutex_enter(&iosram_mutex);
51603831d35Sstevel 	softp->state |= IOSRAM_STATE_DETACH;
51703831d35Sstevel 
51803831d35Sstevel 	/*
51903831d35Sstevel 	 * If this instance is currently the master or the target of the tunnel
52003831d35Sstevel 	 * switch, then we need to wait and switch tunnel, if necessary.
52103831d35Sstevel 	 */
52203831d35Sstevel 	if (iosram_master == softp || (softp->state & IOSRAM_STATE_TSWITCH)) {
52303831d35Sstevel 		mutex_exit(&iosram_mutex);
524*07d06da5SSurya Prakki 		(void) iosram_switchfrom(instance);
52503831d35Sstevel 		mutex_enter(&iosram_mutex);
52603831d35Sstevel 	}
52703831d35Sstevel 
52803831d35Sstevel 	/*
52903831d35Sstevel 	 * If the tunnel switch is in progress and we are the master or target
53003831d35Sstevel 	 * of tunnel relocation, then we can't detach this instance right now.
53103831d35Sstevel 	 */
53203831d35Sstevel 	if (softp->state & IOSRAM_STATE_TSWITCH) {
53303831d35Sstevel 		softp->state &= ~IOSRAM_STATE_DETACH;
53403831d35Sstevel 		mutex_exit(&iosram_mutex);
53503831d35Sstevel 		return (DDI_FAILURE);
53603831d35Sstevel 	}
53703831d35Sstevel 
53803831d35Sstevel 	/*
53903831d35Sstevel 	 * We can't allow master IOSRAM to be detached as we won't be able to
54003831d35Sstevel 	 * communicate otherwise.
54103831d35Sstevel 	 */
54203831d35Sstevel 	if (iosram_master == softp) {
54303831d35Sstevel 		softp->state &= ~IOSRAM_STATE_DETACH;
54403831d35Sstevel 		mutex_exit(&iosram_mutex);
54503831d35Sstevel 		return (DDI_FAILURE);
54603831d35Sstevel 	}
54703831d35Sstevel 
54803831d35Sstevel 	/*
54903831d35Sstevel 	 * Now remove our instance from the iosram_instances list.
55003831d35Sstevel 	 */
55103831d35Sstevel 	iosram_remove_instance(instance);
55203831d35Sstevel 	mutex_exit(&iosram_mutex);
55303831d35Sstevel 
55403831d35Sstevel 	/*
55503831d35Sstevel 	 * Instances should only ever be mapped if they are the master and/or
55603831d35Sstevel 	 * participating in a tunnel switch.  Neither should be the case here.
55703831d35Sstevel 	 */
55803831d35Sstevel 	ASSERT((softp->state & IOSRAM_STATE_MAPPED) == 0);
55903831d35Sstevel 
56003831d35Sstevel 	/*
56103831d35Sstevel 	 * Destroy per-instance mutexes
56203831d35Sstevel 	 */
56303831d35Sstevel 	mutex_destroy(&softp->intr_mutex);
56403831d35Sstevel 
56503831d35Sstevel 	ddi_remove_minor_node(dip, NULL);
56603831d35Sstevel 
56703831d35Sstevel 	/*
56803831d35Sstevel 	 * Finally remove our soft state structure
56903831d35Sstevel 	 */
57003831d35Sstevel 	ddi_soft_state_free(iosramsoft_statep, instance);
57103831d35Sstevel 
57203831d35Sstevel 	return (DDI_SUCCESS);
57303831d35Sstevel }
57403831d35Sstevel 
57503831d35Sstevel 
57603831d35Sstevel /* ARGSUSED0 */
57703831d35Sstevel static int
57803831d35Sstevel iosram_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
57903831d35Sstevel 		void **result)
58003831d35Sstevel {
58103831d35Sstevel 	dev_t			dev = (dev_t)arg;
58203831d35Sstevel 	struct iosramsoft	*softp;
58303831d35Sstevel 	int			instance, ret;
58403831d35Sstevel 
58503831d35Sstevel 	instance = getminor(dev);
58603831d35Sstevel 
58703831d35Sstevel 	IOSRAMLOG(2, "GETINFO: dip:%x instance %d dev:%x infocmd:%x\n",
58803831d35Sstevel 	    dip, instance, dev, infocmd);
58903831d35Sstevel 
59003831d35Sstevel 	switch (infocmd) {
59103831d35Sstevel 		case DDI_INFO_DEVT2DEVINFO:
59203831d35Sstevel 			softp = ddi_get_soft_state(iosramsoft_statep, instance);
59303831d35Sstevel 			if (softp == NULL) {
59403831d35Sstevel 				*result = NULL;
59503831d35Sstevel 				ret = DDI_FAILURE;
59603831d35Sstevel 			} else {
59703831d35Sstevel 				*result = softp->dip;
59803831d35Sstevel 				ret = DDI_SUCCESS;
59903831d35Sstevel 			}
60003831d35Sstevel 			break;
60103831d35Sstevel 		case DDI_INFO_DEVT2INSTANCE:
60203831d35Sstevel 			*result = (void *)(uintptr_t)instance;
60303831d35Sstevel 			ret = DDI_SUCCESS;
60403831d35Sstevel 			break;
60503831d35Sstevel 		default:
60603831d35Sstevel 			ret = DDI_FAILURE;
60703831d35Sstevel 			break;
60803831d35Sstevel 	}
60903831d35Sstevel 
61003831d35Sstevel 	return (ret);
61103831d35Sstevel }
61203831d35Sstevel 
61303831d35Sstevel 
61403831d35Sstevel /*ARGSUSED1*/
61503831d35Sstevel static int
61603831d35Sstevel iosram_open(dev_t *dev, int flag, int otype, cred_t *credp)
61703831d35Sstevel {
61803831d35Sstevel 	struct iosramsoft	*softp;
61903831d35Sstevel 	int			instance;
62003831d35Sstevel 
62103831d35Sstevel 	instance = getminor(*dev);
62203831d35Sstevel 	softp = ddi_get_soft_state(iosramsoft_statep, instance);
62303831d35Sstevel 
62403831d35Sstevel 	if (softp == NULL) {
62503831d35Sstevel 		return (ENXIO);
62603831d35Sstevel 	}
62703831d35Sstevel 
62803831d35Sstevel 	IOSRAMLOG(1, "OPEN: dev:%p otype:%x ... instance:%d softp:%p\n",
62903831d35Sstevel 	    *dev, otype, softp->instance, softp);
63003831d35Sstevel 
63103831d35Sstevel 	return (0);
63203831d35Sstevel }
63303831d35Sstevel 
63403831d35Sstevel 
63503831d35Sstevel /*ARGSUSED1*/
63603831d35Sstevel static int
63703831d35Sstevel iosram_close(dev_t dev, int flag, int otype, cred_t *credp)
63803831d35Sstevel {
63903831d35Sstevel 	struct iosramsoft	*softp;
64003831d35Sstevel 	int			instance;
64103831d35Sstevel 
64203831d35Sstevel 	instance = getminor(dev);
64303831d35Sstevel 	softp = ddi_get_soft_state(iosramsoft_statep, instance);
64403831d35Sstevel 	if (softp == NULL) {
64503831d35Sstevel 		return (ENXIO);
64603831d35Sstevel 	}
64703831d35Sstevel 
64803831d35Sstevel 	IOSRAMLOG(1, "CLOSE: dev:%p otype:%x ... instance:%d softp:%p\n",
64903831d35Sstevel 	    dev, otype, softp->instance, softp);
65003831d35Sstevel 
65103831d35Sstevel 	return (0);
65203831d35Sstevel }
65303831d35Sstevel 
65403831d35Sstevel 
65503831d35Sstevel int
65603831d35Sstevel iosram_rd(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr)
65703831d35Sstevel {
65803831d35Sstevel 	iosram_chunk_t		*chunkp;
65903831d35Sstevel 	uint32_t		chunk_len;
66003831d35Sstevel 	uint8_t			*iosramp;
66103831d35Sstevel 	ddi_acc_handle_t	handle;
66203831d35Sstevel 	int			boff;
66303831d35Sstevel 	union {
66403831d35Sstevel 		uchar_t	cbuf[UINT32SZ];
66503831d35Sstevel 		uint32_t  data;
66603831d35Sstevel 	} word;
66703831d35Sstevel 
66803831d35Sstevel 	int			error = 0;
66903831d35Sstevel 	uint8_t			*buf = (uint8_t *)dptr;
67003831d35Sstevel 
67103831d35Sstevel 	/*
67203831d35Sstevel 	 * We try to read from the IOSRAM using double word or word access
67303831d35Sstevel 	 * provided both "off" and "buf" are (or can be) double word or word
67403831d35Sstevel 	 * aligned.  Othewise, we try to align the "off" to a word boundary and
67503831d35Sstevel 	 * then try to read data from the IOSRAM using word access, but store it
67603831d35Sstevel 	 * into buf buffer using byte access.
67703831d35Sstevel 	 *
67803831d35Sstevel 	 * If the leading/trailing portion of the IOSRAM data is not word
67903831d35Sstevel 	 * aligned, it will always be copied using byte access.
68003831d35Sstevel 	 */
68103831d35Sstevel 	IOSRAMLOG(1, "RD: key: 0x%x off:%x len:%x buf:%p\n",
68203831d35Sstevel 	    key, off, len, buf);
68303831d35Sstevel 
68403831d35Sstevel 	/*
68503831d35Sstevel 	 * Acquire lock and look for the requested chunk.  If it exists, make
68603831d35Sstevel 	 * sure the requested read is within the chunk's bounds and no tunnel
68703831d35Sstevel 	 * switch is active.
68803831d35Sstevel 	 */
68903831d35Sstevel 	mutex_enter(&iosram_mutex);
69003831d35Sstevel 	chunkp = iosram_find_chunk(key);
69103831d35Sstevel 	chunk_len = (chunkp != NULL) ? chunkp->toc_data.len : 0;
69203831d35Sstevel 
69303831d35Sstevel 	if (iosram_master == NULL) {
69403831d35Sstevel 		error = EIO;
69503831d35Sstevel 	} else if (chunkp == NULL) {
69603831d35Sstevel 		error = EINVAL;
69703831d35Sstevel 	} else if ((off >= chunk_len) || (len > chunk_len) ||
69803831d35Sstevel 	    ((off + len) > chunk_len)) {
69903831d35Sstevel 		error = EMSGSIZE;
70003831d35Sstevel 	} else if (iosram_tswitch_active) {
70103831d35Sstevel 		error = EAGAIN;
70203831d35Sstevel 	}
70303831d35Sstevel 
70403831d35Sstevel 	if (error) {
70503831d35Sstevel 		mutex_exit(&iosram_mutex);
70603831d35Sstevel 		return (error);
70703831d35Sstevel 	}
70803831d35Sstevel 
70903831d35Sstevel 	/*
71003831d35Sstevel 	 * Bump reference count to indicate #thread accessing IOSRAM and release
71103831d35Sstevel 	 * the lock.
71203831d35Sstevel 	 */
71303831d35Sstevel 	iosram_rw_active++;
71403831d35Sstevel #if defined(DEBUG)
71503831d35Sstevel 	if (iosram_rw_active > iosram_rw_active_max) {
71603831d35Sstevel 		iosram_rw_active_max = iosram_rw_active;
71703831d35Sstevel 	}
71803831d35Sstevel #endif
71903831d35Sstevel 	mutex_exit(&iosram_mutex);
72003831d35Sstevel 
72103831d35Sstevel 	IOSRAM_STAT(read);
72203831d35Sstevel 	IOSRAM_STAT_ADD(bread, len);
72303831d35Sstevel 
72403831d35Sstevel 	/* Get starting address and map handle */
72503831d35Sstevel 	iosramp = chunkp->basep + off;
72603831d35Sstevel 	handle = iosram_handle;
72703831d35Sstevel 
72803831d35Sstevel 	/*
72903831d35Sstevel 	 * Align the off to word boundary and then try reading/writing data
73003831d35Sstevel 	 * using double word or word access.
73103831d35Sstevel 	 */
73203831d35Sstevel 	if ((boff = ((uintptr_t)iosramp & (UINT32SZ - 1))) != 0) {
73303831d35Sstevel 		int	cnt = UINT32SZ - boff;
73403831d35Sstevel 
73503831d35Sstevel 		if (cnt > len) {
73603831d35Sstevel 			cnt = len;
73703831d35Sstevel 		}
73803831d35Sstevel 		IOSRAMLOG(2,
73903831d35Sstevel 		    "RD: align rep_get8(buf:%p sramp:%p cnt:%x) len:%x\n",
74003831d35Sstevel 		    buf, iosramp, cnt, len);
74103831d35Sstevel 		ddi_rep_get8(handle, buf, iosramp, cnt, DDI_DEV_AUTOINCR);
74203831d35Sstevel 		buf += cnt;
74303831d35Sstevel 		iosramp += cnt;
74403831d35Sstevel 		len -= cnt;
74503831d35Sstevel 	}
74603831d35Sstevel 
74703831d35Sstevel 	if ((len >= UINT64SZ) &&
74803831d35Sstevel 	    ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT64SZ - 1)) == 0)) {
74903831d35Sstevel 		/*
75003831d35Sstevel 		 * Both source and destination are double word aligned
75103831d35Sstevel 		 */
75203831d35Sstevel 		int cnt = len/UINT64SZ;
75303831d35Sstevel 
75403831d35Sstevel 		IOSRAMLOG(2,
75503831d35Sstevel 		    "RD: rep_get64(buf:%p sramp:%p cnt:%x) len:%x\n",
75603831d35Sstevel 		    buf, iosramp, cnt, len);
75703831d35Sstevel 		ddi_rep_get64(handle, (uint64_t *)buf, (uint64_t *)iosramp,
75803831d35Sstevel 		    cnt, DDI_DEV_AUTOINCR);
75903831d35Sstevel 		iosramp += cnt * UINT64SZ;
76003831d35Sstevel 		buf += cnt * UINT64SZ;
76103831d35Sstevel 		len -= cnt * UINT64SZ;
76203831d35Sstevel 
76303831d35Sstevel 		/*
76403831d35Sstevel 		 * read remaining data using word and byte access
76503831d35Sstevel 		 */
76603831d35Sstevel 		if (len >= UINT32SZ) {
76703831d35Sstevel 			IOSRAMLOG(2,
76803831d35Sstevel 			    "RD: get32(buf:%p sramp:%p) len:%x\n",
76903831d35Sstevel 			    buf, iosramp, len, NULL);
77003831d35Sstevel 			*(uint32_t *)buf = ddi_get32(handle,
77103831d35Sstevel 			    (uint32_t *)iosramp);
77203831d35Sstevel 			iosramp += UINT32SZ;
77303831d35Sstevel 			buf += UINT32SZ;
77403831d35Sstevel 			len -= UINT32SZ;
77503831d35Sstevel 		}
77603831d35Sstevel 
77703831d35Sstevel 		if (len != 0) {
77819397407SSherry Moore 			ddi_rep_get8(handle, buf, iosramp, len,
77919397407SSherry Moore 			    DDI_DEV_AUTOINCR);
78003831d35Sstevel 		}
78103831d35Sstevel 	} else if ((len >= UINT32SZ) &&
78203831d35Sstevel 	    ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT32SZ - 1)) == 0)) {
78303831d35Sstevel 		/*
78403831d35Sstevel 		 * Both source and destination are word aligned
78503831d35Sstevel 		 */
78603831d35Sstevel 		int cnt = len/UINT32SZ;
78703831d35Sstevel 
78803831d35Sstevel 		IOSRAMLOG(2,
78903831d35Sstevel 		    "RD: rep_get32(buf:%p sramp:%p cnt:%x) len:%x\n",
79003831d35Sstevel 		    buf, iosramp, cnt, len);
79103831d35Sstevel 		ddi_rep_get32(handle, (uint32_t *)buf, (uint32_t *)iosramp,
79203831d35Sstevel 		    cnt, DDI_DEV_AUTOINCR);
79303831d35Sstevel 		iosramp += cnt * UINT32SZ;
79403831d35Sstevel 		buf += cnt * UINT32SZ;
79503831d35Sstevel 		len -= cnt * UINT32SZ;
79603831d35Sstevel 
79703831d35Sstevel 		/*
79803831d35Sstevel 		 * copy the remainder using byte access
79903831d35Sstevel 		 */
80003831d35Sstevel 		if (len != 0) {
80119397407SSherry Moore 			ddi_rep_get8(handle, buf, iosramp, len,
80219397407SSherry Moore 			    DDI_DEV_AUTOINCR);
80303831d35Sstevel 		}
80403831d35Sstevel 	} else if (len != 0) {
80503831d35Sstevel 		/*
80603831d35Sstevel 		 * We know that the "off" (i.e. iosramp) is at least word
80703831d35Sstevel 		 * aligned. We need to read IOSRAM word at a time and copy it
80803831d35Sstevel 		 * byte at a time.
80903831d35Sstevel 		 */
81003831d35Sstevel 		ASSERT(((uintptr_t)iosramp & (UINT32SZ - 1)) == 0);
81103831d35Sstevel 
81203831d35Sstevel 		IOSRAMLOG(2,
81303831d35Sstevel 		    "RD: unaligned get32(buf:%p sramp:%p) len:%x\n",
81403831d35Sstevel 		    buf, iosramp, len, NULL);
81503831d35Sstevel 		for (; len >= UINT32SZ; len -= UINT32SZ, iosramp += UINT32SZ) {
81603831d35Sstevel 			word.data =  ddi_get32(handle, (uint32_t *)iosramp);
81703831d35Sstevel 			*buf++ = word.cbuf[0];
81803831d35Sstevel 			*buf++ = word.cbuf[1];
81903831d35Sstevel 			*buf++ = word.cbuf[2];
82003831d35Sstevel 			*buf++ = word.cbuf[3];
82103831d35Sstevel 		}
82203831d35Sstevel 
82303831d35Sstevel 		/*
82403831d35Sstevel 		 * copy the remaining data using byte access
82503831d35Sstevel 		 */
82603831d35Sstevel 		if (len != 0) {
82703831d35Sstevel 			ddi_rep_get8(handle, buf, iosramp, len,
82803831d35Sstevel 			    DDI_DEV_AUTOINCR);
82903831d35Sstevel 		}
83003831d35Sstevel 	}
83103831d35Sstevel 
83203831d35Sstevel 	/*
83303831d35Sstevel 	 * Reacquire mutex lock, decrement refcnt and if refcnt is 0 and any
83403831d35Sstevel 	 * threads are waiting for r/w activity to complete, wake them up.
83503831d35Sstevel 	 */
83603831d35Sstevel 	mutex_enter(&iosram_mutex);
83703831d35Sstevel 	ASSERT(iosram_rw_active > 0);
83803831d35Sstevel 
83903831d35Sstevel 	if ((--iosram_rw_active == 0) && iosram_rw_wakeup) {
84003831d35Sstevel 		iosram_rw_wakeup = 0;
84103831d35Sstevel 		cv_broadcast(&iosram_rw_wait);
84203831d35Sstevel 	}
84303831d35Sstevel 	mutex_exit(&iosram_mutex);
84403831d35Sstevel 
84503831d35Sstevel 	return (error);
84603831d35Sstevel }
84703831d35Sstevel 
84803831d35Sstevel 
84903831d35Sstevel /*
85003831d35Sstevel  * _iosram_write(key, off, len, dptr, force)
85103831d35Sstevel  *	Internal common routine to write to the IOSRAM.
85203831d35Sstevel  */
85303831d35Sstevel static int
85403831d35Sstevel _iosram_write(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr, int force)
85503831d35Sstevel {
85603831d35Sstevel 	iosram_chunk_t		*chunkp;
85703831d35Sstevel 	uint32_t		chunk_len;
85803831d35Sstevel 	uint8_t			*iosramp;
85903831d35Sstevel 	ddi_acc_handle_t	handle;
86003831d35Sstevel 	int			boff;
86103831d35Sstevel 	union {
86203831d35Sstevel 		uint8_t	cbuf[UINT32SZ];
86303831d35Sstevel 		uint32_t data;
86403831d35Sstevel 	} word;
86503831d35Sstevel 
86603831d35Sstevel 	int			error = 0;
86703831d35Sstevel 	uint8_t			*buf = (uint8_t *)dptr;
86803831d35Sstevel 
86903831d35Sstevel 	/*
87003831d35Sstevel 	 * We try to write to the IOSRAM using double word or word access
87103831d35Sstevel 	 * provided both "off" and "buf" are (or can be) double word or word
87203831d35Sstevel 	 * aligned.  Othewise, we try to align the "off" to a word boundary and
87303831d35Sstevel 	 * then try to write data to the IOSRAM using word access, but read data
87403831d35Sstevel 	 * from the buf buffer using byte access.
87503831d35Sstevel 	 *
87603831d35Sstevel 	 * If the leading/trailing portion of the IOSRAM data is not word
87703831d35Sstevel 	 * aligned, it will always be written using byte access.
87803831d35Sstevel 	 */
87903831d35Sstevel 	IOSRAMLOG(1, "WR: key: 0x%x off:%x len:%x buf:%p\n",
88003831d35Sstevel 	    key, off, len, buf);
88103831d35Sstevel 
88203831d35Sstevel 	/*
88303831d35Sstevel 	 * Acquire lock and look for the requested chunk.  If it exists, make
88403831d35Sstevel 	 * sure the requested write is within the chunk's bounds and no tunnel
88503831d35Sstevel 	 * switch is active.
88603831d35Sstevel 	 */
88703831d35Sstevel 	mutex_enter(&iosram_mutex);
88803831d35Sstevel 	chunkp = iosram_find_chunk(key);
88903831d35Sstevel 	chunk_len = (chunkp != NULL) ? chunkp->toc_data.len : 0;
89003831d35Sstevel 
89103831d35Sstevel 	if (iosram_master == NULL) {
89203831d35Sstevel 		error = EIO;
89303831d35Sstevel 	} else if (chunkp == NULL) {
89403831d35Sstevel 		error = EINVAL;
89503831d35Sstevel 	} else if ((off >= chunk_len) || (len > chunk_len) ||
89603831d35Sstevel 	    ((off+len) > chunk_len)) {
89703831d35Sstevel 		error = EMSGSIZE;
89803831d35Sstevel 	} else if (iosram_tswitch_active && !force) {
89903831d35Sstevel 		error = EAGAIN;
90003831d35Sstevel 	}
90103831d35Sstevel 
90203831d35Sstevel 	if (error) {
90303831d35Sstevel 		mutex_exit(&iosram_mutex);
90403831d35Sstevel 		return (error);
90503831d35Sstevel 	}
90603831d35Sstevel 
90703831d35Sstevel 	/*
90803831d35Sstevel 	 * If this is a forced write and there's a tunnel switch in progress,
90903831d35Sstevel 	 * abort the switch.
91003831d35Sstevel 	 */
91103831d35Sstevel 	if (iosram_tswitch_active && force) {
91203831d35Sstevel 		cmn_err(CE_NOTE, "!iosram: Aborting tswitch on force_write");
91303831d35Sstevel 		iosram_abort_tswitch();
91403831d35Sstevel 	}
91503831d35Sstevel 
91603831d35Sstevel 	/*
91703831d35Sstevel 	 * Bump reference count to indicate #thread accessing IOSRAM
91803831d35Sstevel 	 * and release the lock.
91903831d35Sstevel 	 */
92003831d35Sstevel 	iosram_rw_active++;
92103831d35Sstevel #if defined(DEBUG)
92203831d35Sstevel 	if (iosram_rw_active > iosram_rw_active_max) {
92303831d35Sstevel 		iosram_rw_active_max = iosram_rw_active;
92403831d35Sstevel 	}
92503831d35Sstevel #endif
92603831d35Sstevel 	mutex_exit(&iosram_mutex);
92703831d35Sstevel 
92803831d35Sstevel 
92903831d35Sstevel 	IOSRAM_STAT(write);
93003831d35Sstevel 	IOSRAM_STAT_ADD(bwrite, len);
93103831d35Sstevel 
93203831d35Sstevel 	/* Get starting address and map handle */
93303831d35Sstevel 	iosramp = chunkp->basep + off;
93403831d35Sstevel 	handle = iosram_handle;
93503831d35Sstevel 
93603831d35Sstevel 	/*
93703831d35Sstevel 	 * Align the off to word boundary and then try reading/writing
93803831d35Sstevel 	 * data using double word or word access.
93903831d35Sstevel 	 */
94003831d35Sstevel 	if ((boff = ((uintptr_t)iosramp & (UINT32SZ - 1))) != 0) {
94103831d35Sstevel 		int	cnt = UINT32SZ - boff;
94203831d35Sstevel 
94303831d35Sstevel 		if (cnt > len) {
94403831d35Sstevel 			cnt = len;
94503831d35Sstevel 		}
94603831d35Sstevel 		IOSRAMLOG(2,
94703831d35Sstevel 		    "WR: align rep_put8(buf:%p sramp:%p cnt:%x) len:%x\n",
94803831d35Sstevel 		    buf, iosramp, cnt, len);
94903831d35Sstevel 		ddi_rep_put8(handle, buf, iosramp, cnt, DDI_DEV_AUTOINCR);
95003831d35Sstevel 		buf += cnt;
95103831d35Sstevel 		iosramp += cnt;
95203831d35Sstevel 		len -= cnt;
95303831d35Sstevel 	}
95403831d35Sstevel 
95503831d35Sstevel 	if ((len >= UINT64SZ) &&
95603831d35Sstevel 	    ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT64SZ - 1)) == 0)) {
95703831d35Sstevel 		/*
95803831d35Sstevel 		 * Both source and destination are double word aligned
95903831d35Sstevel 		 */
96003831d35Sstevel 		int cnt = len/UINT64SZ;
96103831d35Sstevel 
96203831d35Sstevel 		IOSRAMLOG(2,
96303831d35Sstevel 		    "WR: rep_put64(buf:%p sramp:%p cnt:%x) len:%x\n",
96403831d35Sstevel 		    buf, iosramp, cnt, len);
96503831d35Sstevel 		ddi_rep_put64(handle, (uint64_t *)buf, (uint64_t *)iosramp,
96603831d35Sstevel 		    cnt, DDI_DEV_AUTOINCR);
96703831d35Sstevel 		iosramp += cnt * UINT64SZ;
96803831d35Sstevel 		buf += cnt * UINT64SZ;
96903831d35Sstevel 		len -= cnt * UINT64SZ;
97003831d35Sstevel 
97103831d35Sstevel 		/*
97203831d35Sstevel 		 * Copy the remaining data using word & byte access
97303831d35Sstevel 		 */
97403831d35Sstevel 		if (len >= UINT32SZ) {
97503831d35Sstevel 			IOSRAMLOG(2,
97603831d35Sstevel 			    "WR: put32(buf:%p sramp:%p) len:%x\n", buf, iosramp,
97703831d35Sstevel 			    len, NULL);
97803831d35Sstevel 			ddi_put32(handle, (uint32_t *)iosramp,
97903831d35Sstevel 			    *(uint32_t *)buf);
98003831d35Sstevel 			iosramp += UINT32SZ;
98103831d35Sstevel 			buf += UINT32SZ;
98203831d35Sstevel 			len -= UINT32SZ;
98303831d35Sstevel 		}
98403831d35Sstevel 
98503831d35Sstevel 		if (len != 0) {
98603831d35Sstevel 			ddi_rep_put8(handle, buf, iosramp, len,
98703831d35Sstevel 			    DDI_DEV_AUTOINCR);
98803831d35Sstevel 		}
98903831d35Sstevel 	} else if ((len >= UINT32SZ) &&
99003831d35Sstevel 	    ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT32SZ - 1)) == 0)) {
99103831d35Sstevel 		/*
99203831d35Sstevel 		 * Both source and destination are word aligned
99303831d35Sstevel 		 */
99403831d35Sstevel 		int cnt = len/UINT32SZ;
99503831d35Sstevel 
99603831d35Sstevel 		IOSRAMLOG(2,
99703831d35Sstevel 		    "WR: rep_put32(buf:%p sramp:%p cnt:%x) len:%x\n",
99803831d35Sstevel 		    buf, iosramp, cnt, len);
99903831d35Sstevel 		ddi_rep_put32(handle, (uint32_t *)buf, (uint32_t *)iosramp,
100003831d35Sstevel 		    cnt, DDI_DEV_AUTOINCR);
100103831d35Sstevel 		iosramp += cnt * UINT32SZ;
100203831d35Sstevel 		buf += cnt * UINT32SZ;
100303831d35Sstevel 		len -= cnt * UINT32SZ;
100403831d35Sstevel 
100503831d35Sstevel 		/*
100603831d35Sstevel 		 * copy the remainder using byte access
100703831d35Sstevel 		 */
100803831d35Sstevel 		if (len != 0) {
100903831d35Sstevel 			ddi_rep_put8(handle, buf, iosramp, len,
101003831d35Sstevel 			    DDI_DEV_AUTOINCR);
101103831d35Sstevel 		}
101203831d35Sstevel 	} else if (len != 0) {
101303831d35Sstevel 		/*
101403831d35Sstevel 		 * We know that the "off" is at least word aligned. We
101503831d35Sstevel 		 * need to read data from buf buffer byte at a time, and
101603831d35Sstevel 		 * write it to the IOSRAM word at a time.
101703831d35Sstevel 		 */
101803831d35Sstevel 
101903831d35Sstevel 		ASSERT(((uintptr_t)iosramp & (UINT32SZ - 1)) == 0);
102003831d35Sstevel 
102103831d35Sstevel 		IOSRAMLOG(2,
102203831d35Sstevel 		    "WR: unaligned put32(buf:%p sramp:%p) len:%x\n",
102303831d35Sstevel 		    buf, iosramp, len, NULL);
102403831d35Sstevel 		for (; len >= UINT32SZ; len -= UINT32SZ, iosramp += UINT32SZ) {
102503831d35Sstevel 			word.cbuf[0] = *buf++;
102603831d35Sstevel 			word.cbuf[1] = *buf++;
102703831d35Sstevel 			word.cbuf[2] = *buf++;
102803831d35Sstevel 			word.cbuf[3] = *buf++;
102903831d35Sstevel 			ddi_put32(handle, (uint32_t *)iosramp, word.data);
103003831d35Sstevel 		}
103103831d35Sstevel 
103203831d35Sstevel 		/*
103303831d35Sstevel 		 * copy the remaining data using byte access
103403831d35Sstevel 		 */
103503831d35Sstevel 		if (len != 0) {
103603831d35Sstevel 			ddi_rep_put8(handle, buf, iosramp,
103703831d35Sstevel 			    len, DDI_DEV_AUTOINCR);
103803831d35Sstevel 		}
103903831d35Sstevel 	}
104003831d35Sstevel 
104103831d35Sstevel 	/*
104203831d35Sstevel 	 * Reacquire mutex lock, decrement refcnt and if refcnt is 0 and
104303831d35Sstevel 	 * any threads are waiting for r/w activity to complete, wake them up.
104403831d35Sstevel 	 */
104503831d35Sstevel 	mutex_enter(&iosram_mutex);
104603831d35Sstevel 	ASSERT(iosram_rw_active > 0);
104703831d35Sstevel 
104803831d35Sstevel 	if ((--iosram_rw_active == 0) && iosram_rw_wakeup) {
104903831d35Sstevel 		iosram_rw_wakeup = 0;
105003831d35Sstevel 		cv_broadcast(&iosram_rw_wait);
105103831d35Sstevel 	}
105203831d35Sstevel 	mutex_exit(&iosram_mutex);
105303831d35Sstevel 
105403831d35Sstevel 	return (error);
105503831d35Sstevel }
105603831d35Sstevel 
105703831d35Sstevel 
105803831d35Sstevel int
105903831d35Sstevel iosram_force_write(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr)
106003831d35Sstevel {
106103831d35Sstevel 	return (_iosram_write(key, off, len, dptr, 1 /* force */));
106203831d35Sstevel }
106303831d35Sstevel 
106403831d35Sstevel 
106503831d35Sstevel int
106603831d35Sstevel iosram_wr(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr)
106703831d35Sstevel {
106803831d35Sstevel 	return (_iosram_write(key, off, len, dptr, 0));
106903831d35Sstevel }
107003831d35Sstevel 
107103831d35Sstevel 
107203831d35Sstevel /*
107303831d35Sstevel  * iosram_register(key, handler, arg)
107403831d35Sstevel  *	Register a handler and an arg for the specified chunk.  This handler
107503831d35Sstevel  *	will be invoked when an interrupt is received from the other side and
107603831d35Sstevel  *	the int_pending flag for the corresponding key is marked
107703831d35Sstevel  *	IOSRAM_INT_TO_DOM.
107803831d35Sstevel  */
107903831d35Sstevel /* ARGSUSED */
108003831d35Sstevel int
108103831d35Sstevel iosram_register(uint32_t key, void (*handler)(), void *arg)
108203831d35Sstevel {
108303831d35Sstevel 	struct iosram_chunk	*chunkp;
108403831d35Sstevel 	int			error = 0;
108503831d35Sstevel 
108603831d35Sstevel 	/*
108703831d35Sstevel 	 * Acquire lock and look for the requested chunk.  If it exists, and no
108803831d35Sstevel 	 * other callback is registered, proceed with the registration.
108903831d35Sstevel 	 */
109003831d35Sstevel 	mutex_enter(&iosram_mutex);
109103831d35Sstevel 	chunkp = iosram_find_chunk(key);
109203831d35Sstevel 
109303831d35Sstevel 	if (iosram_master == NULL) {
109403831d35Sstevel 		error = EIO;
109503831d35Sstevel 	} else if (chunkp == NULL) {
109603831d35Sstevel 		error = EINVAL;
109703831d35Sstevel 	} else if (chunkp->cback.handler != NULL) {
109803831d35Sstevel 		error = EBUSY;
109903831d35Sstevel 	} else {
110003831d35Sstevel 		chunkp->cback.busy = 0;
110103831d35Sstevel 		chunkp->cback.unregister = 0;
110203831d35Sstevel 		chunkp->cback.handler = handler;
110303831d35Sstevel 		chunkp->cback.arg = arg;
110403831d35Sstevel 	}
110503831d35Sstevel 	mutex_exit(&iosram_mutex);
110603831d35Sstevel 
110703831d35Sstevel 	IOSRAMLOG(1, "REG: key: 0x%x hdlr:%p arg:%p error:%d\n",
110803831d35Sstevel 	    key, handler, arg, error);
110903831d35Sstevel 
111003831d35Sstevel 	return (error);
111103831d35Sstevel }
111203831d35Sstevel 
111303831d35Sstevel 
111403831d35Sstevel /*
111503831d35Sstevel  * iosram_unregister()
111603831d35Sstevel  *	Unregister handler associated with the specified chunk.
111703831d35Sstevel  */
111803831d35Sstevel int
111903831d35Sstevel iosram_unregister(uint32_t key)
112003831d35Sstevel {
112103831d35Sstevel 	struct iosram_chunk	*chunkp;
112203831d35Sstevel 	int			error = 0;
112303831d35Sstevel 
112403831d35Sstevel 	/*
112503831d35Sstevel 	 * Acquire lock and look for the requested chunk.  If it exists and has
112603831d35Sstevel 	 * a callback registered, unregister it.
112703831d35Sstevel 	 */
112803831d35Sstevel 	mutex_enter(&iosram_mutex);
112903831d35Sstevel 	chunkp = iosram_find_chunk(key);
113003831d35Sstevel 
113103831d35Sstevel 	if (iosram_master == NULL) {
113203831d35Sstevel 		error = EIO;
113303831d35Sstevel 	} else if (chunkp == NULL) {
113403831d35Sstevel 		error = EINVAL;
113503831d35Sstevel 	} else if (chunkp->cback.busy) {
113603831d35Sstevel 		/*
113703831d35Sstevel 		 * If the handler is already busy (being invoked), then we flag
113803831d35Sstevel 		 * it so it will be unregistered after the invocation completes.
113903831d35Sstevel 		 */
114003831d35Sstevel 		DPRINTF(1, ("IOSRAM(%d): unregister: delaying unreg k:0x%08x\n",
114103831d35Sstevel 		    iosram_master->instance, key));
114203831d35Sstevel 		chunkp->cback.unregister = 1;
114303831d35Sstevel 	} else if (chunkp->cback.handler != NULL) {
114403831d35Sstevel 		chunkp->cback.handler = NULL;
114503831d35Sstevel 		chunkp->cback.arg = NULL;
114603831d35Sstevel 	}
114703831d35Sstevel 	mutex_exit(&iosram_mutex);
114803831d35Sstevel 
114903831d35Sstevel 	IOSRAMLOG(1, "UNREG: key:%x error:%d\n", key, error, NULL, NULL);
115003831d35Sstevel 	return (error);
115103831d35Sstevel }
115203831d35Sstevel 
115303831d35Sstevel 
115403831d35Sstevel /*
115503831d35Sstevel  * iosram_get_flag():
115603831d35Sstevel  *	Get data_valid and/or int_pending flags associated with the
115703831d35Sstevel  *	specified key.
115803831d35Sstevel  */
115903831d35Sstevel int
116003831d35Sstevel iosram_get_flag(uint32_t key, uint8_t *data_valid, uint8_t *int_pending)
116103831d35Sstevel {
116203831d35Sstevel 	iosram_chunk_t	*chunkp;
116303831d35Sstevel 	iosram_flags_t	flags;
116403831d35Sstevel 	int		error = 0;
116503831d35Sstevel 
116603831d35Sstevel 	/*
116703831d35Sstevel 	 * Acquire lock and look for the requested chunk.  If it exists, and no
116803831d35Sstevel 	 * tunnel switch is in progress, read the chunk's flags.
116903831d35Sstevel 	 */
117003831d35Sstevel 	mutex_enter(&iosram_mutex);
117103831d35Sstevel 	chunkp = iosram_find_chunk(key);
117203831d35Sstevel 
117303831d35Sstevel 	if (iosram_master == NULL) {
117403831d35Sstevel 		error = EIO;
117503831d35Sstevel 	} else if (chunkp == NULL) {
117603831d35Sstevel 		error = EINVAL;
117703831d35Sstevel 	} else if (iosram_tswitch_active) {
117803831d35Sstevel 		error = EAGAIN;
117903831d35Sstevel 	} else {
118003831d35Sstevel 		IOSRAM_STAT(getflag);
118103831d35Sstevel 
118203831d35Sstevel 		/*
118303831d35Sstevel 		 * Read the flags
118403831d35Sstevel 		 */
118503831d35Sstevel 		ddi_rep_get8(iosram_handle, (uint8_t *)&flags,
118603831d35Sstevel 		    (uint8_t *)(chunkp->flagsp), sizeof (iosram_flags_t),
118703831d35Sstevel 		    DDI_DEV_AUTOINCR);
118803831d35Sstevel 
118903831d35Sstevel 		/*
119003831d35Sstevel 		 * Get each flag value that the caller is interested in.
119103831d35Sstevel 		 */
119203831d35Sstevel 		if (data_valid != NULL) {
119303831d35Sstevel 			*data_valid = flags.data_valid;
119403831d35Sstevel 		}
119503831d35Sstevel 
119603831d35Sstevel 		if (int_pending != NULL) {
119703831d35Sstevel 			*int_pending = flags.int_pending;
119803831d35Sstevel 		}
119903831d35Sstevel 	}
120003831d35Sstevel 	mutex_exit(&iosram_mutex);
120103831d35Sstevel 
120203831d35Sstevel 	IOSRAMLOG(1, "GetFlag key:%x data_valid:%x int_pending:%x error:%d\n",
120303831d35Sstevel 	    key, flags.data_valid, flags.int_pending, error);
120403831d35Sstevel 	return (error);
120503831d35Sstevel }
120603831d35Sstevel 
120703831d35Sstevel 
120803831d35Sstevel /*
120903831d35Sstevel  * iosram_set_flag():
121003831d35Sstevel  *	Set data_valid and int_pending flags associated with the specified key.
121103831d35Sstevel  */
121203831d35Sstevel int
121303831d35Sstevel iosram_set_flag(uint32_t key, uint8_t data_valid, uint8_t int_pending)
121403831d35Sstevel {
121503831d35Sstevel 	iosram_chunk_t	*chunkp;
121603831d35Sstevel 	iosram_flags_t	flags;
121703831d35Sstevel 	int		error = 0;
121803831d35Sstevel 
121903831d35Sstevel 	/*
122003831d35Sstevel 	 * Acquire lock and look for the requested chunk.  If it exists, and no
122103831d35Sstevel 	 * tunnel switch is in progress, write the chunk's flags.
122203831d35Sstevel 	 */
122303831d35Sstevel 	mutex_enter(&iosram_mutex);
122403831d35Sstevel 	chunkp = iosram_find_chunk(key);
122503831d35Sstevel 
122603831d35Sstevel 	if (iosram_master == NULL) {
122703831d35Sstevel 		error = EIO;
122803831d35Sstevel 	} else if ((chunkp == NULL) ||
122903831d35Sstevel 	    ((data_valid != IOSRAM_DATA_INVALID) &&
123003831d35Sstevel 	    (data_valid != IOSRAM_DATA_VALID)) ||
123103831d35Sstevel 	    ((int_pending != IOSRAM_INT_NONE) &&
123203831d35Sstevel 	    (int_pending != IOSRAM_INT_TO_SSC) &&
123303831d35Sstevel 	    (int_pending != IOSRAM_INT_TO_DOM))) {
123403831d35Sstevel 		error = EINVAL;
123503831d35Sstevel 	} else if (iosram_tswitch_active) {
123603831d35Sstevel 		error = EAGAIN;
123703831d35Sstevel 	} else {
123803831d35Sstevel 		IOSRAM_STAT(setflag);
123903831d35Sstevel 		flags.data_valid = data_valid;
124003831d35Sstevel 		flags.int_pending = int_pending;
124103831d35Sstevel 		ddi_rep_put8(iosram_handle, (uint8_t *)&flags,
124203831d35Sstevel 		    (uint8_t *)(chunkp->flagsp), sizeof (iosram_flags_t),
124303831d35Sstevel 		    DDI_DEV_AUTOINCR);
124403831d35Sstevel 	}
124503831d35Sstevel 	mutex_exit(&iosram_mutex);
124603831d35Sstevel 
124703831d35Sstevel 	IOSRAMLOG(1, "SetFlag key:%x data_valid:%x int_pending:%x error:%d\n",
124803831d35Sstevel 	    key, flags.data_valid, flags.int_pending, error);
124903831d35Sstevel 	return (error);
125003831d35Sstevel }
125103831d35Sstevel 
125203831d35Sstevel 
125303831d35Sstevel /*
125403831d35Sstevel  * iosram_ctrl()
125503831d35Sstevel  *	This function provides access to a variety of services not available
125603831d35Sstevel  *	through the basic API.
125703831d35Sstevel  */
125803831d35Sstevel int
125903831d35Sstevel iosram_ctrl(uint32_t key, uint32_t cmd, void *arg)
126003831d35Sstevel {
126103831d35Sstevel 	struct iosram_chunk	*chunkp;
126203831d35Sstevel 	int			error = 0;
126303831d35Sstevel 
126403831d35Sstevel 	/*
126503831d35Sstevel 	 * Acquire lock and do some argument sanity checking.
126603831d35Sstevel 	 */
126703831d35Sstevel 	mutex_enter(&iosram_mutex);
126803831d35Sstevel 	chunkp = iosram_find_chunk(key);
126903831d35Sstevel 
127003831d35Sstevel 	if (iosram_master == NULL) {
127103831d35Sstevel 		error = EIO;
127203831d35Sstevel 	} else if (chunkp == NULL) {
127303831d35Sstevel 		error = EINVAL;
127403831d35Sstevel 	}
127503831d35Sstevel 
127603831d35Sstevel 	if (error != 0) {
127703831d35Sstevel 		mutex_exit(&iosram_mutex);
127803831d35Sstevel 		return (error);
127903831d35Sstevel 	}
128003831d35Sstevel 
128103831d35Sstevel 	/*
128203831d35Sstevel 	 * Arguments seem okay so far, so process the command.
128303831d35Sstevel 	 */
128403831d35Sstevel 	switch (cmd) {
128503831d35Sstevel 		case IOSRAM_CMD_CHUNKLEN:
128603831d35Sstevel 			/*
128703831d35Sstevel 			 * Return the length of the chunk indicated by the key.
128803831d35Sstevel 			 */
128903831d35Sstevel 			if (arg == NULL) {
129003831d35Sstevel 				error = EINVAL;
129103831d35Sstevel 				break;
129203831d35Sstevel 			}
129303831d35Sstevel 
129403831d35Sstevel 			*(uint32_t *)arg = chunkp->toc_data.len;
129503831d35Sstevel 			break;
129603831d35Sstevel 
129703831d35Sstevel 		default:
129803831d35Sstevel 			error = ENOTSUP;
129903831d35Sstevel 			break;
130003831d35Sstevel 	}
130103831d35Sstevel 
130203831d35Sstevel 	mutex_exit(&iosram_mutex);
130303831d35Sstevel 	return (error);
130403831d35Sstevel }
130503831d35Sstevel 
130603831d35Sstevel 
130703831d35Sstevel /*
130803831d35Sstevel  * iosram_hdr_ctrl()
130903831d35Sstevel  *	This function provides an interface for the Mailbox Protocol
131003831d35Sstevel  *	implementation to use when interacting with the IOSRAM header.
131103831d35Sstevel  */
131203831d35Sstevel int
131303831d35Sstevel iosram_hdr_ctrl(uint32_t cmd, void *arg)
131403831d35Sstevel {
131503831d35Sstevel 	int	error = 0;
131603831d35Sstevel 
131703831d35Sstevel 	/*
131803831d35Sstevel 	 * Acquire lock and do some argument sanity checking.
131903831d35Sstevel 	 */
132003831d35Sstevel 	mutex_enter(&iosram_mutex);
132103831d35Sstevel 
132203831d35Sstevel 	if (iosram_master == NULL) {
132303831d35Sstevel 		error = EIO;
132403831d35Sstevel 	}
132503831d35Sstevel 
132603831d35Sstevel 	if (error != 0) {
132703831d35Sstevel 		mutex_exit(&iosram_mutex);
132803831d35Sstevel 		return (error);
132903831d35Sstevel 	}
133003831d35Sstevel 
133103831d35Sstevel 	switch (cmd) {
133203831d35Sstevel 		case IOSRAM_HDRCMD_GET_SMS_MBOX_VER:
133303831d35Sstevel 			/*
133403831d35Sstevel 			 * Return the value of the sms_mbox_version field.
133503831d35Sstevel 			 */
133603831d35Sstevel 			if (arg == NULL) {
133703831d35Sstevel 				error = EINVAL;
133803831d35Sstevel 				break;
133903831d35Sstevel 			}
134003831d35Sstevel 
134103831d35Sstevel 			*(uint32_t *)arg = IOSRAM_GET_HDRFIELD32(iosram_master,
134203831d35Sstevel 			    sms_mbox_version);
134303831d35Sstevel 			break;
134403831d35Sstevel 
134503831d35Sstevel 		case IOSRAM_HDRCMD_SET_OS_MBOX_VER:
134603831d35Sstevel 			/*
134703831d35Sstevel 			 * Set the value of the os_mbox_version field.
134803831d35Sstevel 			 */
134903831d35Sstevel 			IOSRAM_SET_HDRFIELD32(iosram_master, os_mbox_version,
135003831d35Sstevel 			    (uint32_t)(uintptr_t)arg);
135103831d35Sstevel 			IOSRAM_SET_HDRFIELD32(iosram_master, os_change_mask,
135203831d35Sstevel 			    IOSRAM_HDRFIELD_OS_MBOX_VER);
1353*07d06da5SSurya Prakki 			(void) iosram_send_intr();
135403831d35Sstevel 			break;
135503831d35Sstevel 
135603831d35Sstevel 		case IOSRAM_HDRCMD_REG_CALLBACK:
135703831d35Sstevel 			iosram_hdrchange_handler = (void (*)())arg;
135803831d35Sstevel 			break;
135903831d35Sstevel 
136003831d35Sstevel 		default:
136103831d35Sstevel 			error = ENOTSUP;
136203831d35Sstevel 			break;
136303831d35Sstevel 	}
136403831d35Sstevel 
136503831d35Sstevel 	mutex_exit(&iosram_mutex);
136603831d35Sstevel 	return (error);
136703831d35Sstevel }
136803831d35Sstevel 
136903831d35Sstevel 
137003831d35Sstevel /*
137103831d35Sstevel  * iosram_softintr()
137203831d35Sstevel  *	IOSRAM soft interrupt handler
137303831d35Sstevel  */
137403831d35Sstevel static uint_t
137503831d35Sstevel iosram_softintr(caddr_t arg)
137603831d35Sstevel {
137703831d35Sstevel 	uint32_t	hdr_changes;
137803831d35Sstevel 	iosramsoft_t	*softp = (iosramsoft_t *)arg;
137903831d35Sstevel 	iosram_chunk_t	*chunkp;
138003831d35Sstevel 	void		(*handler)();
138103831d35Sstevel 	int		i;
138203831d35Sstevel 	uint8_t		flag;
138303831d35Sstevel 
138403831d35Sstevel 	DPRINTF(1, ("iosram(%d): in iosram_softintr\n", softp->instance));
138503831d35Sstevel 
138603831d35Sstevel 	IOSRAMLOG(2, "SINTR arg/softp:%p  pending:%d busy:%d\n",
138703831d35Sstevel 	    arg, softp->intr_pending, softp->intr_busy, NULL);
138803831d35Sstevel 
138903831d35Sstevel 	mutex_enter(&iosram_mutex);
139003831d35Sstevel 	mutex_enter(&softp->intr_mutex);
139103831d35Sstevel 
139203831d35Sstevel 	/*
139303831d35Sstevel 	 * Do not process interrupt if interrupt handler is already running or
139403831d35Sstevel 	 * no interrupts are pending.
139503831d35Sstevel 	 */
139603831d35Sstevel 	if (softp->intr_busy || !softp->intr_pending) {
139703831d35Sstevel 		mutex_exit(&softp->intr_mutex);
139803831d35Sstevel 		mutex_exit(&iosram_mutex);
139903831d35Sstevel 		DPRINTF(1, ("IOSRAM(%d): softintr: busy=%d pending=%d\n",
140003831d35Sstevel 		    softp->instance, softp->intr_busy, softp->intr_pending));
140103831d35Sstevel 		return (softp->intr_pending ? DDI_INTR_CLAIMED :
140203831d35Sstevel 		    DDI_INTR_UNCLAIMED);
140303831d35Sstevel 	}
140403831d35Sstevel 
140503831d35Sstevel 	/*
140603831d35Sstevel 	 * It's possible for the SC to send an interrupt on the new master
140703831d35Sstevel 	 * before we are able to set our internal state.  If so, we'll retrigger
140803831d35Sstevel 	 * soft interrupt right after tunnel switch completion.
140903831d35Sstevel 	 */
141003831d35Sstevel 	if (softp->state & IOSRAM_STATE_TSWITCH) {
141103831d35Sstevel 		mutex_exit(&softp->intr_mutex);
141203831d35Sstevel 		mutex_exit(&iosram_mutex);
141303831d35Sstevel 		DPRINTF(1, ("IOSRAM(%d): softintr: doing switch "
141403831d35Sstevel 		    "state=0x%x\n", softp->instance, softp->state));
141503831d35Sstevel 		return (DDI_INTR_CLAIMED);
141603831d35Sstevel 	}
141703831d35Sstevel 
141803831d35Sstevel 	/*
141903831d35Sstevel 	 * Do not process interrupt if we are not the master.
142003831d35Sstevel 	 */
142103831d35Sstevel 	if (!(softp->state & IOSRAM_STATE_MASTER)) {
142203831d35Sstevel 		mutex_exit(&softp->intr_mutex);
142303831d35Sstevel 		mutex_exit(&iosram_mutex);
142403831d35Sstevel 		DPRINTF(1, ("IOSRAM(%d): softintr: no master state=0x%x\n ",
142503831d35Sstevel 		    softp->instance, softp->state));
142603831d35Sstevel 		return (DDI_INTR_CLAIMED);
142703831d35Sstevel 	}
142803831d35Sstevel 
142903831d35Sstevel 	IOSRAM_STAT(sintr_recv);
143003831d35Sstevel 
143103831d35Sstevel 	/*
143203831d35Sstevel 	 * If the driver is suspended, then we should not process any
143303831d35Sstevel 	 * interrupts.  Instead, we trigger a soft interrupt when the driver
143403831d35Sstevel 	 * resumes.
143503831d35Sstevel 	 */
143603831d35Sstevel 	if (softp->suspended) {
143703831d35Sstevel 		mutex_exit(&softp->intr_mutex);
143803831d35Sstevel 		mutex_exit(&iosram_mutex);
143903831d35Sstevel 		DPRINTF(1, ("IOSRAM(%d): softintr: suspended\n",
144003831d35Sstevel 		    softp->instance));
144103831d35Sstevel 		return (DDI_INTR_CLAIMED);
144203831d35Sstevel 	}
144303831d35Sstevel 
144403831d35Sstevel 	/*
144503831d35Sstevel 	 * Indicate that the IOSRAM interrupt handler is busy.  Note that this
144603831d35Sstevel 	 * includes incrementing the reader/writer count, since we don't want
144703831d35Sstevel 	 * any tunnel switches to start up while we're processing callbacks.
144803831d35Sstevel 	 */
144903831d35Sstevel 	softp->intr_busy = 1;
145003831d35Sstevel 	iosram_rw_active++;
145103831d35Sstevel #if defined(DEBUG)
145203831d35Sstevel 	if (iosram_rw_active > iosram_rw_active_max) {
145303831d35Sstevel 		iosram_rw_active_max = iosram_rw_active;
145403831d35Sstevel 	}
145503831d35Sstevel #endif
145603831d35Sstevel 
145703831d35Sstevel 	do {
145803831d35Sstevel 		DPRINTF(1, ("IOSRAM(%d): softintr: processing interrupt\n",
145903831d35Sstevel 		    softp->instance));
146003831d35Sstevel 
146103831d35Sstevel 		softp->intr_pending = 0;
146203831d35Sstevel 
146303831d35Sstevel 		mutex_exit(&softp->intr_mutex);
146403831d35Sstevel 
146503831d35Sstevel 		/*
146603831d35Sstevel 		 * Process changes to the IOSRAM header.
146703831d35Sstevel 		 */
146803831d35Sstevel 		hdr_changes = IOSRAM_GET_HDRFIELD32(iosram_master,
146903831d35Sstevel 		    sms_change_mask);
147003831d35Sstevel 		if (hdr_changes != 0) {
147103831d35Sstevel 			int	error;
147203831d35Sstevel 
147303831d35Sstevel 			IOSRAM_SET_HDRFIELD32(iosram_master, sms_change_mask,
147403831d35Sstevel 			    0);
147503831d35Sstevel 			if (hdr_changes & IOSRAM_HDRFIELD_TOC_INDEX) {
147603831d35Sstevel 				/*
147703831d35Sstevel 				 * XXX is it safe to temporarily release the
147803831d35Sstevel 				 * iosram_mutex here?
147903831d35Sstevel 				 */
148003831d35Sstevel 				mutex_exit(&iosram_mutex);
148103831d35Sstevel 				error = iosram_read_toc(iosram_master);
148203831d35Sstevel 				mutex_enter(&iosram_mutex);
148303831d35Sstevel 				if (error) {
148403831d35Sstevel 					cmn_err(CE_WARN, "iosram_read_toc: new"
148503831d35Sstevel 					    " TOC invalid; using old TOC.");
148603831d35Sstevel 				}
148703831d35Sstevel 				iosram_update_addrs(iosram_master);
148803831d35Sstevel 			}
148903831d35Sstevel 
149003831d35Sstevel 			if (iosram_hdrchange_handler != NULL) {
149103831d35Sstevel 				mutex_exit(&iosram_mutex);
149203831d35Sstevel 				iosram_hdrchange_handler();
149303831d35Sstevel 				mutex_enter(&iosram_mutex);
149403831d35Sstevel 			}
149503831d35Sstevel 		}
149603831d35Sstevel 
149703831d35Sstevel 		/*
149803831d35Sstevel 		 * Get data_valid/int_pending flags and generate a callback if
149903831d35Sstevel 		 * applicable.  For now, we read only those flags for which a
150003831d35Sstevel 		 * callback has been registered.  We can optimize reading of
150103831d35Sstevel 		 * flags by reading them all at once and then process them
150203831d35Sstevel 		 * later.
150303831d35Sstevel 		 */
150403831d35Sstevel 		for (i = 0, chunkp = chunks; i < nchunks; i++,
150503831d35Sstevel 		    chunkp++) {
150603831d35Sstevel #if DEBUG
150703831d35Sstevel 			flag =  ddi_get8(iosram_handle,
150803831d35Sstevel 			    &(chunkp->flagsp->int_pending));
150903831d35Sstevel 			DPRINTF(1, ("IOSRAM(%d): softintr chunk #%d "
151003831d35Sstevel 			    "flag=0x%x handler=%p\n",
151103831d35Sstevel 			    softp->instance, i, (int)flag,
1512*07d06da5SSurya Prakki 			    (void *)chunkp->cback.handler));
151303831d35Sstevel #endif
151403831d35Sstevel 			if ((handler = chunkp->cback.handler) == NULL) {
151503831d35Sstevel 				continue;
151603831d35Sstevel 			}
151703831d35Sstevel 			flag = ddi_get8(iosram_handle,
151803831d35Sstevel 			    &(chunkp->flagsp->int_pending));
151903831d35Sstevel 			if (flag == IOSRAM_INT_TO_DOM) {
152003831d35Sstevel 				DPRINTF(1,
152103831d35Sstevel 				    ("IOSRAM(%d): softintr: invoking handler\n",
152203831d35Sstevel 				    softp->instance));
152303831d35Sstevel 				IOSRAMLOG(1,
152403831d35Sstevel 				    "SINTR invoking hdlr:%p arg:%p index:%d\n",
152503831d35Sstevel 				    handler, chunkp->cback.arg, i, NULL);
152603831d35Sstevel 				IOSRAM_STAT(callbacks);
152703831d35Sstevel 
152803831d35Sstevel 				ddi_put8(iosram_handle,
152903831d35Sstevel 				    &(chunkp->flagsp->int_pending),
153003831d35Sstevel 				    IOSRAM_INT_NONE);
153103831d35Sstevel 				chunkp->cback.busy = 1;
153203831d35Sstevel 				mutex_exit(&iosram_mutex);
153303831d35Sstevel 				(*handler)(chunkp->cback.arg);
153403831d35Sstevel 				mutex_enter(&iosram_mutex);
153503831d35Sstevel 				chunkp->cback.busy = 0;
153603831d35Sstevel 
153703831d35Sstevel 				/*
153803831d35Sstevel 				 * If iosram_unregister was called while the
153903831d35Sstevel 				 * callback was being invoked, complete the
154003831d35Sstevel 				 * unregistration here.
154103831d35Sstevel 				 */
154203831d35Sstevel 				if (chunkp->cback.unregister) {
154303831d35Sstevel 					DPRINTF(1, ("IOSRAM(%d): softintr: "
154403831d35Sstevel 					    "delayed unreg k:0x%08x\n",
154503831d35Sstevel 					    softp->instance,
154603831d35Sstevel 					    chunkp->toc_data.key));
154703831d35Sstevel 					chunkp->cback.handler = NULL;
154803831d35Sstevel 					chunkp->cback.arg = NULL;
154903831d35Sstevel 					chunkp->cback.unregister = 0;
155003831d35Sstevel 				}
155103831d35Sstevel 			}
155203831d35Sstevel 
155303831d35Sstevel 			/*
155403831d35Sstevel 			 * If there's a tunnel switch waiting to run, give it
155503831d35Sstevel 			 * higher priority than these callbacks by bailing out.
155603831d35Sstevel 			 * They'll still be invoked on the new master iosram
155703831d35Sstevel 			 * when the tunnel switch is done.
155803831d35Sstevel 			 */
155903831d35Sstevel 			if (iosram_tswitch_active) {
156003831d35Sstevel 				break;
156103831d35Sstevel 			}
156203831d35Sstevel 		}
156303831d35Sstevel 
156403831d35Sstevel 		mutex_enter(&softp->intr_mutex);
156503831d35Sstevel 
156603831d35Sstevel 	} while (softp->intr_pending && !softp->suspended &&
156703831d35Sstevel 	    !iosram_tswitch_active);
156803831d35Sstevel 
156903831d35Sstevel 	/*
157003831d35Sstevel 	 * Indicate IOSRAM interrupt handler is not BUSY any more
157103831d35Sstevel 	 */
157203831d35Sstevel 	softp->intr_busy = 0;
157303831d35Sstevel 
157403831d35Sstevel 	ASSERT(iosram_rw_active > 0);
157503831d35Sstevel 	if ((--iosram_rw_active == 0) && iosram_rw_wakeup) {
157603831d35Sstevel 		iosram_rw_wakeup = 0;
157703831d35Sstevel 		cv_broadcast(&iosram_rw_wait);
157803831d35Sstevel 	}
157903831d35Sstevel 
158003831d35Sstevel 	mutex_exit(&softp->intr_mutex);
158103831d35Sstevel 	mutex_exit(&iosram_mutex);
158203831d35Sstevel 
158303831d35Sstevel 	DPRINTF(1, ("iosram(%d): softintr exit\n", softp->instance));
158403831d35Sstevel 
158503831d35Sstevel 	return (DDI_INTR_CLAIMED);
158603831d35Sstevel }
158703831d35Sstevel 
158803831d35Sstevel 
158903831d35Sstevel /*
159003831d35Sstevel  * iosram_intr()
159103831d35Sstevel  *	IOSRAM real interrupt handler
159203831d35Sstevel  */
159303831d35Sstevel static uint_t
159403831d35Sstevel iosram_intr(caddr_t arg)
159503831d35Sstevel {
159603831d35Sstevel 	iosramsoft_t	*softp = (iosramsoft_t *)arg;
159703831d35Sstevel 	int		result = DDI_INTR_UNCLAIMED;
159803831d35Sstevel 	uint32_t	int_status;
159903831d35Sstevel 
160003831d35Sstevel 	DPRINTF(2, ("iosram(%d): in iosram_intr\n", softp->instance));
160103831d35Sstevel 
160203831d35Sstevel 	mutex_enter(&softp->intr_mutex);
160303831d35Sstevel 
160403831d35Sstevel 	if (softp->sbbc_handle == NULL) {
160503831d35Sstevel 		/*
160603831d35Sstevel 		 * The SBBC registers region is not mapped in.
160703831d35Sstevel 		 * Set the interrupt pending flag here, and process the
160803831d35Sstevel 		 * interrupt after the tunnel switch.
160903831d35Sstevel 		 */
161003831d35Sstevel 		DPRINTF(1, ("IOSRAM(%d): iosram_intr: SBBC not mapped\n",
161103831d35Sstevel 		    softp->instance));
161203831d35Sstevel 		softp->intr_pending = 1;
161303831d35Sstevel 		mutex_exit(&softp->intr_mutex);
161403831d35Sstevel 		return (DDI_INTR_UNCLAIMED);
161503831d35Sstevel 	}
161603831d35Sstevel 
161703831d35Sstevel 	int_status = ddi_get32(softp->sbbc_handle,
161803831d35Sstevel 	    &(softp->sbbc_region->int_status.reg));
161903831d35Sstevel 	DPRINTF(1, ("iosram_intr: int_status = 0x%08x\n", int_status));
162003831d35Sstevel 
162103831d35Sstevel 	if (int_status & IOSRAM_SBBC_INT0) {
162203831d35Sstevel 		result = DDI_INTR_CLAIMED;
162303831d35Sstevel 		DPRINTF(1, ("iosram_intr: int0 detected!\n"));
162403831d35Sstevel 	}
162503831d35Sstevel 
162603831d35Sstevel 	if (int_status & IOSRAM_SBBC_INT1) {
162703831d35Sstevel 		result = DDI_INTR_CLAIMED;
162803831d35Sstevel 		DPRINTF(1, ("iosram_intr: int1 detected!\n"));
162903831d35Sstevel 	}
163003831d35Sstevel 
163103831d35Sstevel 	if (result == DDI_INTR_CLAIMED) {
163203831d35Sstevel 		ddi_put32(softp->sbbc_handle,
163303831d35Sstevel 		    &(softp->sbbc_region->int_status.reg), int_status);
163403831d35Sstevel 		int_status = ddi_get32(softp->sbbc_handle,
163503831d35Sstevel 		    &(softp->sbbc_region->int_status.reg));
163603831d35Sstevel 		DPRINTF(1, ("iosram_intr: int_status = 0x%08x\n",
163703831d35Sstevel 		    int_status));
163803831d35Sstevel 
163903831d35Sstevel 		softp->intr_pending = 1;
164003831d35Sstevel 		/*
164103831d35Sstevel 		 * Trigger soft interrupt if not executing and
164203831d35Sstevel 		 * not suspended.
164303831d35Sstevel 		 */
164403831d35Sstevel 		if (!softp->intr_busy && !softp->suspended &&
164503831d35Sstevel 		    (softp->softintr_id != NULL)) {
164603831d35Sstevel 			DPRINTF(1, ("iosram(%d): trigger softint\n",
164703831d35Sstevel 			    softp->instance));
164803831d35Sstevel 			ddi_trigger_softintr(softp->softintr_id);
164903831d35Sstevel 		}
165003831d35Sstevel 	}
165103831d35Sstevel 
165203831d35Sstevel 	IOSRAM_STAT(intr_recv);
165303831d35Sstevel 
165403831d35Sstevel 	mutex_exit(&softp->intr_mutex);
165503831d35Sstevel 
165603831d35Sstevel 	IOSRAMLOG(2, "INTR arg/softp:%p  pending:%d busy:%d\n",
165703831d35Sstevel 	    arg, softp->intr_pending, softp->intr_busy, NULL);
165803831d35Sstevel 	DPRINTF(1, ("iosram(%d): iosram_intr exit\n", softp->instance));
165903831d35Sstevel 
166003831d35Sstevel 	return (result);
166103831d35Sstevel }
166203831d35Sstevel 
166303831d35Sstevel 
166403831d35Sstevel /*
166503831d35Sstevel  * iosram_send_intr()
166603831d35Sstevel  *	Send an interrupt to the SSP side via AXQ driver
166703831d35Sstevel  */
166803831d35Sstevel int
166903831d35Sstevel iosram_send_intr()
167003831d35Sstevel {
167103831d35Sstevel 	IOSRAMLOG(1, "SendIntr called\n", NULL, NULL, NULL, NULL);
167203831d35Sstevel 	IOSRAM_STAT(intr_send);
167303831d35Sstevel 	DPRINTF(1, ("iosram iosram_send_intr invoked\n"));
167403831d35Sstevel 
167503831d35Sstevel 	return (axq_cpu2ssc_intr(0));
167603831d35Sstevel }
167703831d35Sstevel 
167803831d35Sstevel 
167903831d35Sstevel #if defined(DEBUG)
168003831d35Sstevel static void
168103831d35Sstevel iosram_dummy_cback(void *arg)
168203831d35Sstevel {
168303831d35Sstevel 	DPRINTF(1, ("iosram_dummy_cback invoked arg:%p\n", arg));
168403831d35Sstevel }
168503831d35Sstevel #endif /* DEBUG */
168603831d35Sstevel 
168703831d35Sstevel 
168803831d35Sstevel /*ARGSUSED1*/
168903831d35Sstevel static int
169003831d35Sstevel iosram_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
169103831d35Sstevel 		int *rvalp)
169203831d35Sstevel {
169303831d35Sstevel 	struct iosramsoft	*softp;
169403831d35Sstevel 	int			error = DDI_SUCCESS;
169503831d35Sstevel 
169603831d35Sstevel 	softp = ddi_get_soft_state(iosramsoft_statep, getminor(dev));
169703831d35Sstevel 	if (softp == NULL) {
169803831d35Sstevel 		return (ENXIO);
169903831d35Sstevel 	}
170003831d35Sstevel 	IOSRAMLOG(1, "IOCTL: dev:%p cmd:%x arg:%p ... instance %d\n",
170103831d35Sstevel 	    dev, cmd, arg, softp->instance);
170203831d35Sstevel 
170303831d35Sstevel 	switch (cmd) {
170403831d35Sstevel #if defined(DEBUG)
170503831d35Sstevel 	case IOSRAM_GET_FLAG:
170603831d35Sstevel 		{
170703831d35Sstevel 		iosram_io_t	req;
170803831d35Sstevel 		uint8_t		data_valid, int_pending;
170903831d35Sstevel 
171003831d35Sstevel 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
171103831d35Sstevel 			return (EFAULT);
171203831d35Sstevel 		}
171303831d35Sstevel 
171403831d35Sstevel 		DPRINTF(2, ("IOSRAM_GET_FLAG(key:%x\n", req.key));
171503831d35Sstevel 
171603831d35Sstevel 		req.retval = iosram_get_flag(req.key, &data_valid,
171703831d35Sstevel 		    &int_pending);
171803831d35Sstevel 		req.data_valid = (uint32_t)data_valid;
171903831d35Sstevel 		req.int_pending = (uint32_t)int_pending;
172003831d35Sstevel 
172103831d35Sstevel 		if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
172203831d35Sstevel 			DPRINTF(1,
172303831d35Sstevel 			    ("IOSRAM_GET_FLAG: can't copyout req.retval (%x)",
172403831d35Sstevel 			    req.retval));
172503831d35Sstevel 			error = EFAULT;
172603831d35Sstevel 		}
172703831d35Sstevel 
172803831d35Sstevel 		return (error);
172903831d35Sstevel 		}
173003831d35Sstevel 
173103831d35Sstevel 	case IOSRAM_SET_FLAG:
173203831d35Sstevel 		{
173303831d35Sstevel 		iosram_io_t	req;
173403831d35Sstevel 
173503831d35Sstevel 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
173603831d35Sstevel 			return (EFAULT);
173703831d35Sstevel 		}
173803831d35Sstevel 
173903831d35Sstevel 		DPRINTF(2, ("IOSRAM_SET_FLAG(key:%x data_valid:%x "
174003831d35Sstevel 		    "int_pending:%x\n", req.key, req.data_valid,
174103831d35Sstevel 		    req.int_pending));
174203831d35Sstevel 
174303831d35Sstevel 		req.retval = iosram_set_flag(req.key, req.data_valid,
174403831d35Sstevel 		    req.int_pending);
174503831d35Sstevel 
174603831d35Sstevel 		if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
174703831d35Sstevel 			DPRINTF(1, ("IOSRAM_SET_FLAG: can't copyout req.retval"
174803831d35Sstevel 			    " (%x)\n", req.retval));
174903831d35Sstevel 			error = EFAULT;
175003831d35Sstevel 		}
175103831d35Sstevel 
175203831d35Sstevel 		return (error);
175303831d35Sstevel 		}
175403831d35Sstevel 
175503831d35Sstevel 	case IOSRAM_RD:
175603831d35Sstevel 		{
175703831d35Sstevel 		caddr_t		bufp;
175803831d35Sstevel 		int		len;
175903831d35Sstevel 		iosram_io_t	req;
176003831d35Sstevel 
176103831d35Sstevel 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
176203831d35Sstevel 			return (EFAULT);
176303831d35Sstevel 		}
176403831d35Sstevel 
176503831d35Sstevel 		DPRINTF(2, ("IOSRAM_RD(k:%x o:%x len:%x bufp:%p\n", req.key,
176603831d35Sstevel 		    req.off, req.len, (void *)(uintptr_t)req.bufp));
176703831d35Sstevel 
176803831d35Sstevel 		len = req.len;
176903831d35Sstevel 		bufp = kmem_alloc(len, KM_SLEEP);
177003831d35Sstevel 
177103831d35Sstevel 		req.retval = iosram_rd(req.key, req.off, req.len, bufp);
177203831d35Sstevel 
177303831d35Sstevel 		if (ddi_copyout(bufp, (void *)(uintptr_t)req.bufp, len, mode)) {
177403831d35Sstevel 			DPRINTF(1, ("IOSRAM_RD: copyout(%p, %p,%x,%x) failed\n",
1775*07d06da5SSurya Prakki 			    (void *)bufp, (void *)(uintptr_t)req.bufp, len,
1776*07d06da5SSurya Prakki 			    mode));
177703831d35Sstevel 			error = EFAULT;
177803831d35Sstevel 		} else if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
177903831d35Sstevel 			DPRINTF(1, ("IOSRAM_RD: can't copyout retval (%x)\n",
178003831d35Sstevel 			    req.retval));
178103831d35Sstevel 			error = EFAULT;
178203831d35Sstevel 		}
178303831d35Sstevel 
178403831d35Sstevel 		kmem_free(bufp, len);
178503831d35Sstevel 		return (error);
178603831d35Sstevel 		}
178703831d35Sstevel 
178803831d35Sstevel 	case IOSRAM_WR:
178903831d35Sstevel 		{
179003831d35Sstevel 		caddr_t		bufp;
179103831d35Sstevel 		iosram_io_t	req;
179203831d35Sstevel 		int		len;
179303831d35Sstevel 
179403831d35Sstevel 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
179503831d35Sstevel 			return (EFAULT);
179603831d35Sstevel 		}
179703831d35Sstevel 
179803831d35Sstevel 		DPRINTF(2, ("IOSRAM_WR(k:%x o:%x len:%x bufp:%p\n",
1799*07d06da5SSurya Prakki 		    req.key, req.off, req.len, (void *)(uintptr_t)req.bufp));
180003831d35Sstevel 		len = req.len;
180103831d35Sstevel 		bufp = kmem_alloc(len, KM_SLEEP);
180203831d35Sstevel 		if (ddi_copyin((void *)(uintptr_t)req.bufp, bufp, len, mode)) {
180303831d35Sstevel 			error = EFAULT;
180403831d35Sstevel 		} else {
180503831d35Sstevel 			req.retval = iosram_wr(req.key, req.off, req.len,
180603831d35Sstevel 			    bufp);
180703831d35Sstevel 
180803831d35Sstevel 			if (ddi_copyout(&req, (void *)arg, sizeof (req),
180903831d35Sstevel 			    mode)) {
181003831d35Sstevel 				error = EFAULT;
181103831d35Sstevel 			}
181203831d35Sstevel 		}
181303831d35Sstevel 		kmem_free(bufp, len);
181403831d35Sstevel 		return (error);
181503831d35Sstevel 		}
181603831d35Sstevel 
181703831d35Sstevel 	case IOSRAM_TOC:
181803831d35Sstevel 		{
181903831d35Sstevel 		caddr_t		bufp;
182003831d35Sstevel 		int		len;
182103831d35Sstevel 		iosram_io_t	req;
182203831d35Sstevel 
182303831d35Sstevel 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
182403831d35Sstevel 			return (EFAULT);
182503831d35Sstevel 		}
182603831d35Sstevel 
182703831d35Sstevel 		DPRINTF(2, ("IOSRAM_TOC (req.bufp:%x req.len:%x) \n",
182803831d35Sstevel 		    req.bufp, req.len));
182903831d35Sstevel 
183003831d35Sstevel 		len = req.len;
183103831d35Sstevel 		bufp = kmem_alloc(len, KM_SLEEP);
183203831d35Sstevel 
183303831d35Sstevel 		req.retval = iosram_get_keys((iosram_toc_entry_t *)bufp,
183403831d35Sstevel 		    &req.len);
183503831d35Sstevel 
183603831d35Sstevel 		if (ddi_copyout(bufp, (void *)(uintptr_t)req.bufp, req.len,
183703831d35Sstevel 		    mode)) {
183803831d35Sstevel 			DPRINTF(1,
183903831d35Sstevel 			    ("IOSRAM_TOC: copyout(%p, %p,%x,%x) failed\n",
1840*07d06da5SSurya Prakki 			    (void *)bufp, (void *)(uintptr_t)req.bufp, req.len,
1841*07d06da5SSurya Prakki 			    mode));
184203831d35Sstevel 			error = EFAULT;
184303831d35Sstevel 		} else if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
184403831d35Sstevel 			DPRINTF(1, ("IOSRAM_TOC: can't copyout retval (%x)\n",
184503831d35Sstevel 			    req.retval));
184603831d35Sstevel 			error = EFAULT;
184703831d35Sstevel 		}
184803831d35Sstevel 		kmem_free(bufp, len);
184903831d35Sstevel 		return (error);
185003831d35Sstevel 		}
185103831d35Sstevel 
185203831d35Sstevel 	case IOSRAM_SEND_INTR:
185303831d35Sstevel 		{
185403831d35Sstevel 		DPRINTF(2, ("IOSRAM_SEND_INTR\n"));
185503831d35Sstevel 
185603831d35Sstevel 		switch ((int)arg) {
185703831d35Sstevel 		case 0x11:
185803831d35Sstevel 		case 0x22:
185903831d35Sstevel 		case 0x44:
186003831d35Sstevel 		case 0x88:
186103831d35Sstevel 			ddi_put32(softp->sbbc_handle,
186203831d35Sstevel 			    &(softp->sbbc_region->int_enable.reg), (int)arg);
186303831d35Sstevel 			DPRINTF(1, ("Wrote 0x%x to int_enable.reg\n",
186403831d35Sstevel 			    (int)arg));
186503831d35Sstevel 			break;
186603831d35Sstevel 		case 0xBB:
186703831d35Sstevel 			ddi_put32(softp->sbbc_handle,
186803831d35Sstevel 			    &(softp->sbbc_region->p0_int_gen.reg), 1);
186903831d35Sstevel 			DPRINTF(1, ("Wrote 1 to p0_int_gen.reg\n"));
187003831d35Sstevel 			break;
187103831d35Sstevel 		default:
187203831d35Sstevel 			error = iosram_send_intr();
187303831d35Sstevel 		}
187403831d35Sstevel 
187503831d35Sstevel 		return (error);
187603831d35Sstevel 		}
187703831d35Sstevel 
187803831d35Sstevel 	case IOSRAM_PRINT_CBACK:
187903831d35Sstevel 		iosram_print_cback();
188003831d35Sstevel 		break;
188103831d35Sstevel 
188203831d35Sstevel 	case IOSRAM_PRINT_STATE:
188303831d35Sstevel 		iosram_print_state((int)arg);
188403831d35Sstevel 		break;
188503831d35Sstevel 
188603831d35Sstevel #if IOSRAM_STATS
188703831d35Sstevel 	case IOSRAM_PRINT_STATS:
188803831d35Sstevel 		iosram_print_stats();
188903831d35Sstevel 		break;
189003831d35Sstevel #endif
189103831d35Sstevel 
189203831d35Sstevel #if IOSRAM_LOG
189303831d35Sstevel 	case IOSRAM_PRINT_LOG:
189403831d35Sstevel 		iosram_print_log((int)arg);
189503831d35Sstevel 		break;
189603831d35Sstevel #endif
189703831d35Sstevel 
189803831d35Sstevel 	case IOSRAM_TUNNEL_SWITCH:
189903831d35Sstevel 		error = iosram_switchfrom((int)arg);
190003831d35Sstevel 		break;
190103831d35Sstevel 
190203831d35Sstevel 	case IOSRAM_PRINT_FLAGS:
190303831d35Sstevel 		iosram_print_flags();
190403831d35Sstevel 		break;
190503831d35Sstevel 
190603831d35Sstevel 	case IOSRAM_REG_CBACK:
190703831d35Sstevel 		{
190803831d35Sstevel 		iosram_io_t	req;
190903831d35Sstevel 
191003831d35Sstevel 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
191103831d35Sstevel 			return (EFAULT);
191203831d35Sstevel 		}
191303831d35Sstevel 
191403831d35Sstevel 		DPRINTF(2, ("IOSRAM_REG_CBACK(k:%x)\n", req.key));
191503831d35Sstevel 
191603831d35Sstevel 		req.retval = iosram_register(req.key, iosram_dummy_cback,
191703831d35Sstevel 		    (void *)(uintptr_t)req.key);
191803831d35Sstevel 		if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
191903831d35Sstevel 			error = EFAULT;
192003831d35Sstevel 		}
192103831d35Sstevel 
192203831d35Sstevel 		return (error);
192303831d35Sstevel 		}
192403831d35Sstevel 
192503831d35Sstevel 	case IOSRAM_UNREG_CBACK:
192603831d35Sstevel 		{
192703831d35Sstevel 		iosram_io_t	req;
192803831d35Sstevel 
192903831d35Sstevel 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
193003831d35Sstevel 			return (EFAULT);
193103831d35Sstevel 		}
193203831d35Sstevel 
193303831d35Sstevel 		DPRINTF(2, ("IOSRAM_REG_CBACK(k:%x)\n", req.key));
193403831d35Sstevel 
193503831d35Sstevel 		req.retval = iosram_unregister(req.key);
193603831d35Sstevel 		if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
193703831d35Sstevel 			error = EFAULT;
193803831d35Sstevel 		}
193903831d35Sstevel 
194003831d35Sstevel 		return (error);
194103831d35Sstevel 		}
194203831d35Sstevel 
194303831d35Sstevel 	case IOSRAM_SEMA_ACQUIRE:
194403831d35Sstevel 	{
194503831d35Sstevel 		DPRINTF(1, ("IOSRAM_SEMA_ACQUIRE\n"));
194603831d35Sstevel 		error = iosram_sema_acquire(NULL);
194703831d35Sstevel 		return (error);
194803831d35Sstevel 	}
194903831d35Sstevel 
195003831d35Sstevel 	case IOSRAM_SEMA_RELEASE:
195103831d35Sstevel 	{
195203831d35Sstevel 		DPRINTF(1, ("IOSRAM_SEMA_RELEASE\n"));
195303831d35Sstevel 		error = iosram_sema_release();
195403831d35Sstevel 		return (error);
195503831d35Sstevel 	}
195603831d35Sstevel 
195703831d35Sstevel #endif /* DEBUG */
195803831d35Sstevel 
195903831d35Sstevel 	default:
196003831d35Sstevel 		DPRINTF(1, ("iosram_ioctl: Illegal command %x\n", cmd));
196103831d35Sstevel 		error = ENOTTY;
196203831d35Sstevel 	}
196303831d35Sstevel 
196403831d35Sstevel 	return (error);
196503831d35Sstevel }
196603831d35Sstevel 
196703831d35Sstevel 
196803831d35Sstevel /*
196903831d35Sstevel  * iosram_switch_tunnel(softp)
197003831d35Sstevel  *	Switch master tunnel to the specified instance
197103831d35Sstevel  *	Must be called while holding iosram_mutex
197203831d35Sstevel  */
197303831d35Sstevel /*ARGSUSED*/
197403831d35Sstevel static int
197503831d35Sstevel iosram_switch_tunnel(iosramsoft_t *softp)
197603831d35Sstevel {
197703831d35Sstevel #ifdef DEBUG
197803831d35Sstevel 	int		instance = softp->instance;
197903831d35Sstevel #endif
198003831d35Sstevel 	int		error = 0;
198103831d35Sstevel 	iosramsoft_t	*prev_master;
198203831d35Sstevel 
198303831d35Sstevel 	ASSERT(mutex_owned(&iosram_mutex));
198403831d35Sstevel 
198503831d35Sstevel 	DPRINTF(1, ("tunnel switch new master:%p (%d) current master:%p (%d)\n",
1986*07d06da5SSurya Prakki 	    (void *)softp, instance, (void *)iosram_master,
198703831d35Sstevel 	    ((iosram_master) ? iosram_master->instance : -1)));
198803831d35Sstevel 	IOSRAMLOG(1, "TSWTCH: new_master:%p (%p) iosram_master:%p (%d)\n",
198903831d35Sstevel 	    softp, instance, iosram_master,
199003831d35Sstevel 	    ((iosram_master) ? iosram_master->instance : -1));
199103831d35Sstevel 
199203831d35Sstevel 	if (softp == NULL || (softp->state & IOSRAM_STATE_DETACH)) {
199303831d35Sstevel 		return (ENXIO);
199403831d35Sstevel 	}
199503831d35Sstevel 	if (iosram_master == softp) {
199603831d35Sstevel 		return (0);
199703831d35Sstevel 	}
199803831d35Sstevel 
199903831d35Sstevel 
200003831d35Sstevel 	/*
200103831d35Sstevel 	 * We protect against the softp structure being deallocated by setting
200203831d35Sstevel 	 * the IOSRAM_STATE_TSWITCH state flag. The detach routine will check
200303831d35Sstevel 	 * for this flag and if set, it will wait for this flag to be reset or
200403831d35Sstevel 	 * refuse the detach operation.
200503831d35Sstevel 	 */
200603831d35Sstevel 	iosram_new_master = softp;
200703831d35Sstevel 	softp->state |= IOSRAM_STATE_TSWITCH;
200803831d35Sstevel 	prev_master = iosram_master;
200903831d35Sstevel 	if (prev_master) {
201003831d35Sstevel 		prev_master->state |= IOSRAM_STATE_TSWITCH;
201103831d35Sstevel 	}
201203831d35Sstevel 	mutex_exit(&iosram_mutex);
201303831d35Sstevel 
201403831d35Sstevel 	/*
201503831d35Sstevel 	 * Map the target IOSRAM, read the TOC, and register interrupts if not
201603831d35Sstevel 	 * already done.
201703831d35Sstevel 	 */
201803831d35Sstevel 	DPRINTF(1, ("iosram(%d): mapping IOSRAM and SBBC\n",
201903831d35Sstevel 	    softp->instance));
202003831d35Sstevel 	IOSRAMLOG(1, "TSWTCH: mapping instance:%d  softp:%p\n",
202103831d35Sstevel 	    instance, softp, NULL, NULL);
202203831d35Sstevel 
202303831d35Sstevel 	if (iosram_setup_map(softp) != DDI_SUCCESS) {
202403831d35Sstevel 		error = ENXIO;
202503831d35Sstevel 	} else if ((chunks == NULL) && (iosram_read_toc(softp) != 0)) {
202603831d35Sstevel 		iosram_remove_map(softp);
202703831d35Sstevel 		error = EINVAL;
202803831d35Sstevel 	} else if (iosram_add_intr(softp) != DDI_SUCCESS) {
202903831d35Sstevel 		/*
203003831d35Sstevel 		 * If there was no previous master, purge the TOC data that
203103831d35Sstevel 		 * iosram_read_toc() created.
203203831d35Sstevel 		 */
203303831d35Sstevel 		if ((prev_master == NULL) && (chunks != NULL)) {
203403831d35Sstevel 			kmem_free(chunks, nchunks * sizeof (iosram_chunk_t));
203503831d35Sstevel 			chunks = NULL;
203603831d35Sstevel 			nchunks = 0;
203703831d35Sstevel 			iosram_init_hashtab();
203803831d35Sstevel 		}
203903831d35Sstevel 		iosram_remove_map(softp);
204003831d35Sstevel 		error = ENXIO;
204103831d35Sstevel 	}
204203831d35Sstevel 
204303831d35Sstevel 	/*
204403831d35Sstevel 	 * If we are asked to abort tunnel switch, do so now, before invoking
204503831d35Sstevel 	 * the OBP callback.
204603831d35Sstevel 	 */
204703831d35Sstevel 	if (iosram_tswitch_aborted) {
204803831d35Sstevel 
204903831d35Sstevel 		/*
205003831d35Sstevel 		 * Once the tunnel switch is aborted, this thread should not
205103831d35Sstevel 		 * resume.  If it does, we simply log a message.  We can't unmap
205203831d35Sstevel 		 * the new master IOSRAM as it may be accessed in
205303831d35Sstevel 		 * iosram_abort_tswitch(). It will be unmapped when it is
205403831d35Sstevel 		 * detached.
205503831d35Sstevel 		 */
205603831d35Sstevel 		IOSRAMLOG(1,
205703831d35Sstevel 		    "TSWTCH: aborted (pre OBP cback). Thread resumed.\n",
205803831d35Sstevel 		    NULL, NULL, NULL, NULL);
205903831d35Sstevel 		error = EIO;
206003831d35Sstevel 	}
206103831d35Sstevel 
206203831d35Sstevel 	if (error) {
206303831d35Sstevel 		IOSRAMLOG(1,
206403831d35Sstevel 		    "TSWTCH: map failed instance:%d  softp:%p error:%x\n",
206503831d35Sstevel 		    instance, softp, error, NULL);
206603831d35Sstevel 		goto done;
206703831d35Sstevel 	}
206803831d35Sstevel 
206903831d35Sstevel 	if (prev_master != NULL) {
207003831d35Sstevel 		int	result;
207103831d35Sstevel 
207203831d35Sstevel 		/*
207303831d35Sstevel 		 * Now invoke the OBP interface to do the tunnel switch.
207403831d35Sstevel 		 */
207503831d35Sstevel 		result = prom_starcat_switch_tunnel(softp->portid,
207603831d35Sstevel 		    OBP_TSWITCH_REQREPLY);
207703831d35Sstevel 		if (result != 0) {
207803831d35Sstevel 			error = EIO;
207903831d35Sstevel 		}
208003831d35Sstevel 		IOSRAMLOG(1,
208103831d35Sstevel 		    "TSWTCH: OBP tswitch portid:%x result:%x error:%x\n",
208203831d35Sstevel 		    softp->portid, result, error, NULL);
208303831d35Sstevel 		IOSRAM_STAT(tswitch);
208403831d35Sstevel 		iosram_tswitch_tstamp = ddi_get_lbolt();
208503831d35Sstevel 	}
208603831d35Sstevel 
208703831d35Sstevel 	mutex_enter(&iosram_mutex);
208803831d35Sstevel 	if (iosram_tswitch_aborted) {
208903831d35Sstevel 		/*
209003831d35Sstevel 		 * Tunnel switch aborted.  This thread should not resume.
209103831d35Sstevel 		 * For now, we simply log a message, but don't unmap any
209203831d35Sstevel 		 * IOSRAM at this stage as it may be accessed within the
209303831d35Sstevel 		 * isoram_abort_tswitch(). The IOSRAM will be unmapped
209403831d35Sstevel 		 * when that instance is detached.
209503831d35Sstevel 		 */
209603831d35Sstevel 		if (iosram_tswitch_aborted) {
209703831d35Sstevel 			IOSRAMLOG(1,
209803831d35Sstevel 			    "TSWTCH: aborted (post OBP cback). Thread"
209903831d35Sstevel 			    " resumed.\n", NULL, NULL, NULL, NULL);
210003831d35Sstevel 			error = EIO;
210103831d35Sstevel 			mutex_exit(&iosram_mutex);
210203831d35Sstevel 		}
210303831d35Sstevel 	} else if (error) {
210403831d35Sstevel 		/*
210503831d35Sstevel 		 * Tunnel switch failed.  Continue using previous tunnel.
210603831d35Sstevel 		 * However, unmap new (target) IOSRAM.
210703831d35Sstevel 		 */
210803831d35Sstevel 		iosram_new_master = NULL;
210903831d35Sstevel 		mutex_exit(&iosram_mutex);
2110*07d06da5SSurya Prakki 		(void) iosram_remove_intr(softp);
211103831d35Sstevel 		iosram_remove_map(softp);
211203831d35Sstevel 	} else {
211303831d35Sstevel 		/*
211403831d35Sstevel 		 * Tunnel switch was successful.  Set the new master.
211503831d35Sstevel 		 * Also unmap old master IOSRAM and remove any interrupts
211603831d35Sstevel 		 * associated with that.
211703831d35Sstevel 		 *
211803831d35Sstevel 		 * Note that a call to iosram_force_write() allows access
211903831d35Sstevel 		 * to the IOSRAM while tunnel switch is in progress.  That
212003831d35Sstevel 		 * means we need to set the new master before unmapping
212103831d35Sstevel 		 * the old master.
212203831d35Sstevel 		 */
212303831d35Sstevel 		iosram_set_master(softp);
212403831d35Sstevel 		iosram_new_master = NULL;
212503831d35Sstevel 		mutex_exit(&iosram_mutex);
212603831d35Sstevel 
212703831d35Sstevel 		if (prev_master) {
212803831d35Sstevel 			IOSRAMLOG(1, "TSWTCH: unmapping prev_master:%p (%d)\n",
212903831d35Sstevel 			    prev_master, prev_master->instance, NULL, NULL);
2130*07d06da5SSurya Prakki 			(void) iosram_remove_intr(prev_master);
213103831d35Sstevel 			iosram_remove_map(prev_master);
213203831d35Sstevel 		}
213303831d35Sstevel 	}
213403831d35Sstevel 
213503831d35Sstevel done:
213603831d35Sstevel 	mutex_enter(&iosram_mutex);
213703831d35Sstevel 
213803831d35Sstevel 	/*
213903831d35Sstevel 	 * Clear the tunnel switch flag on the source and destination
214003831d35Sstevel 	 * instances.
214103831d35Sstevel 	 */
214203831d35Sstevel 	if (prev_master) {
214303831d35Sstevel 		prev_master->state &= ~IOSRAM_STATE_TSWITCH;
214403831d35Sstevel 	}
214503831d35Sstevel 	softp->state &= ~IOSRAM_STATE_TSWITCH;
214603831d35Sstevel 
214703831d35Sstevel 	/*
214803831d35Sstevel 	 * Since incoming interrupts could get lost during a tunnel switch,
214903831d35Sstevel 	 * trigger a soft interrupt just in case.  No harm other than a bit
215003831d35Sstevel 	 * of wasted effort will be caused if no interrupts were dropped.
215103831d35Sstevel 	 */
215203831d35Sstevel 	mutex_enter(&softp->intr_mutex);
215303831d35Sstevel 	iosram_master->intr_pending = 1;
215403831d35Sstevel 	if ((iosram_master->softintr_id != NULL) &&
215503831d35Sstevel 	    (iosram_master->intr_busy == 0)) {
215603831d35Sstevel 		ddi_trigger_softintr(iosram_master->softintr_id);
215703831d35Sstevel 	}
215803831d35Sstevel 	mutex_exit(&softp->intr_mutex);
215903831d35Sstevel 
216003831d35Sstevel 	IOSRAMLOG(1, "TSWTCH: done error:%d iosram_master:%p instance:%d\n",
216103831d35Sstevel 	    error, iosram_master,
216203831d35Sstevel 	    (iosram_master) ? iosram_master->instance : -1, NULL);
216303831d35Sstevel 
216403831d35Sstevel 	return (error);
216503831d35Sstevel }
216603831d35Sstevel 
216703831d35Sstevel 
216803831d35Sstevel /*
216903831d35Sstevel  * iosram_abort_tswitch()
217003831d35Sstevel  * Must be called while holding iosram_mutex.
217103831d35Sstevel  */
217203831d35Sstevel static void
217303831d35Sstevel iosram_abort_tswitch()
217403831d35Sstevel {
217503831d35Sstevel 	uint32_t  master_valid, new_master_valid;
217603831d35Sstevel 
217703831d35Sstevel 	ASSERT(mutex_owned(&iosram_mutex));
217803831d35Sstevel 
217903831d35Sstevel 	if ((!iosram_tswitch_active) || iosram_tswitch_aborted) {
218003831d35Sstevel 		return;
218103831d35Sstevel 	}
218203831d35Sstevel 
218303831d35Sstevel 	ASSERT(iosram_master != NULL);
218403831d35Sstevel 
218503831d35Sstevel 	IOSRAMLOG(1, "ABORT: iosram_master:%p (%d) iosram_new_master:%p (%d)\n",
218603831d35Sstevel 	    iosram_master, iosram_master->instance, iosram_new_master,
218703831d35Sstevel 	    (iosram_new_master == NULL) ? -1 : iosram_new_master->instance);
218803831d35Sstevel 
218903831d35Sstevel 	/*
219003831d35Sstevel 	 * The first call to iosram_force_write() in the middle of tunnel switch
219103831d35Sstevel 	 * will get here. We lookup IOSRAM VALID location and setup appropriate
219203831d35Sstevel 	 * master, if one is still valid.  We also set iosram_tswitch_aborted to
219303831d35Sstevel 	 * prevent reentering this code and to catch if the OBP callback thread
219403831d35Sstevel 	 * somehow resumes.
219503831d35Sstevel 	 */
219603831d35Sstevel 	iosram_tswitch_aborted = 1;
219703831d35Sstevel 
219803831d35Sstevel 	if ((iosram_new_master == NULL) ||
219903831d35Sstevel 	    (iosram_new_master = iosram_master)) {
220003831d35Sstevel 		/*
220103831d35Sstevel 		 * New master hasn't been selected yet, or OBP callback
220203831d35Sstevel 		 * succeeded and we already selected new IOSRAM as master, but
220303831d35Sstevel 		 * system crashed in the middle of unmapping previous master or
220403831d35Sstevel 		 * cleaning up state.  Use the existing master.
220503831d35Sstevel 		 */
220603831d35Sstevel 		ASSERT(iosram_master->iosramp != NULL);
220703831d35Sstevel 		ASSERT(IOSRAM_GET_HDRFIELD32(iosram_master, status) ==
220803831d35Sstevel 		    IOSRAM_VALID);
220903831d35Sstevel 		IOSRAMLOG(1, "ABORT: master (%d) already determined.\n",
221003831d35Sstevel 		    iosram_master->instance, NULL, NULL, NULL);
221103831d35Sstevel 
221203831d35Sstevel 		return;
221303831d35Sstevel 	}
221403831d35Sstevel 
221503831d35Sstevel 	/*
221603831d35Sstevel 	 * System crashed in the middle of tunnel switch and we know that the
221703831d35Sstevel 	 * new target has not been marked master yet.  That means, the old
221803831d35Sstevel 	 * master should still be mapped.  We need to abort the tunnel switch
221903831d35Sstevel 	 * and setup a valid master, if possible, so that we can write to the
222003831d35Sstevel 	 * IOSRAM.
222103831d35Sstevel 	 *
222203831d35Sstevel 	 * We select a new master based upon the IOSRAM header status fields in
222303831d35Sstevel 	 * the previous master IOSRAM and the target IOSRAM as follows:
222403831d35Sstevel 	 *
222503831d35Sstevel 	 *	iosram_master	iosram-tswitch
222603831d35Sstevel 	 * 	(Prev Master)	(New Target)	Decision
222703831d35Sstevel 	 *	---------------	---------------	-----------
222803831d35Sstevel 	 *	  VALID		  don't care	prev master
222903831d35Sstevel 	 *	  INTRANSIT	  INVALID	prev master
223003831d35Sstevel 	 *	  INTRANSIT	  INTRANSIT	prev master
223103831d35Sstevel 	 *	  INTRANSIT	  VALID		new target
223203831d35Sstevel 	 *	  INVALID	  INVALID	shouldn't ever happen
223303831d35Sstevel 	 *	  INVALID	  INTRANSIT	shouldn't ever happen
223403831d35Sstevel 	 *	  INVALID	  VALID		new target
223503831d35Sstevel 	 */
223603831d35Sstevel 
223703831d35Sstevel 	master_valid = (iosram_master->iosramp != NULL) ?
223803831d35Sstevel 	    IOSRAM_GET_HDRFIELD32(iosram_master, status) : IOSRAM_INVALID;
223903831d35Sstevel 	new_master_valid = (iosram_new_master->iosramp != NULL) ?
224003831d35Sstevel 	    IOSRAM_GET_HDRFIELD32(iosram_new_master, status) : IOSRAM_INVALID;
224103831d35Sstevel 
224203831d35Sstevel 	if (master_valid == IOSRAM_VALID) {
224303831d35Sstevel 		/* EMPTY */
224403831d35Sstevel 		/*
224503831d35Sstevel 		 * OBP hasn't been called yet or, if it has, it hasn't started
224603831d35Sstevel 		 * copying yet.  Use the existing master.  Note that the new
224703831d35Sstevel 		 * master may not be mapped yet.
224803831d35Sstevel 		 */
224903831d35Sstevel 		IOSRAMLOG(1, "ABORT: prev master(%d) is VALID\n",
225003831d35Sstevel 		    iosram_master->instance, NULL, NULL, NULL);
225103831d35Sstevel 	} else if (master_valid == IOSRAM_INTRANSIT) {
225203831d35Sstevel 		/*
225303831d35Sstevel 		 * The system crashed after OBP started processing the tunnel
225403831d35Sstevel 		 * switch but before the iosram driver determined that it was
225503831d35Sstevel 		 * complete.  Use the new master if it has been marked valid,
225603831d35Sstevel 		 * meaning that OBP finished copying data to it, or the old
225703831d35Sstevel 		 * master otherwise.
225803831d35Sstevel 		 */
225903831d35Sstevel 		IOSRAMLOG(1, "ABORT: prev master(%d) is INTRANSIT\n",
226003831d35Sstevel 		    iosram_master->instance, NULL, NULL, NULL);
226103831d35Sstevel 
226203831d35Sstevel 		if (new_master_valid == IOSRAM_VALID) {
226303831d35Sstevel 			iosram_set_master(iosram_new_master);
226403831d35Sstevel 			IOSRAMLOG(1, "ABORT: new master(%d) is VALID\n",
226503831d35Sstevel 			    iosram_new_master->instance, NULL, NULL,
226603831d35Sstevel 			    NULL);
226703831d35Sstevel 		} else {
2268*07d06da5SSurya Prakki 			(void) prom_starcat_switch_tunnel(iosram_master->portid,
226903831d35Sstevel 			    OBP_TSWITCH_NOREPLY);
227003831d35Sstevel 
227103831d35Sstevel 			IOSRAMLOG(1, "ABORT: new master(%d) is INVALID\n",
227203831d35Sstevel 			    iosram_new_master->instance, NULL, NULL,
227303831d35Sstevel 			    NULL);
227403831d35Sstevel 		}
227503831d35Sstevel 	} else {
227603831d35Sstevel 		/*
227703831d35Sstevel 		 * The system crashed after OBP marked the old master INVALID,
227803831d35Sstevel 		 * which means the new master is the way to go.
227903831d35Sstevel 		 */
228003831d35Sstevel 		IOSRAMLOG(1, "ABORT: prev master(%d) is INVALID\n",
228103831d35Sstevel 		    iosram_master->instance, NULL, NULL, NULL);
228203831d35Sstevel 
228303831d35Sstevel 		ASSERT(new_master_valid == IOSRAM_VALID);
228403831d35Sstevel 
228503831d35Sstevel 		iosram_set_master(iosram_new_master);
228603831d35Sstevel 	}
228703831d35Sstevel 
228803831d35Sstevel 	IOSRAMLOG(1, "ABORT: Instance %d selected as master\n",
228903831d35Sstevel 	    iosram_master->instance, NULL, NULL, NULL);
229003831d35Sstevel }
229103831d35Sstevel 
229203831d35Sstevel 
229303831d35Sstevel /*
229403831d35Sstevel  * iosram_switchfrom(instance)
229503831d35Sstevel  *	Switch master tunnel away from the specified instance
229603831d35Sstevel  */
229703831d35Sstevel /*ARGSUSED*/
229803831d35Sstevel int
229903831d35Sstevel iosram_switchfrom(int instance)
230003831d35Sstevel {
230103831d35Sstevel 	struct iosramsoft	*softp;
230203831d35Sstevel 	int			error = 0;
230303831d35Sstevel 	int			count;
230403831d35Sstevel 	clock_t			current_tstamp;
230503831d35Sstevel 	clock_t			tstamp_interval;
230603831d35Sstevel 	struct iosramsoft	*last_master = NULL;
230703831d35Sstevel 	static int		last_master_instance = -1;
230803831d35Sstevel 
230903831d35Sstevel 	IOSRAMLOG(1, "SwtchFrom: instance:%d  iosram_master:%p (%d)\n",
231003831d35Sstevel 	    instance, iosram_master,
231103831d35Sstevel 	    ((iosram_master) ? iosram_master->instance : -1), NULL);
231203831d35Sstevel 
231303831d35Sstevel 	mutex_enter(&iosram_mutex);
231403831d35Sstevel 
231503831d35Sstevel 	/*
231603831d35Sstevel 	 * Wait if another tunnel switch is in progress
231703831d35Sstevel 	 */
231803831d35Sstevel 	for (count = 0; iosram_tswitch_active && count < IOSRAM_TSWITCH_RETRY;
231903831d35Sstevel 	    count++) {
232003831d35Sstevel 		iosram_tswitch_wakeup = 1;
232103831d35Sstevel 		cv_wait(&iosram_tswitch_wait, &iosram_mutex);
232203831d35Sstevel 	}
232303831d35Sstevel 
232403831d35Sstevel 	if (iosram_tswitch_active) {
232503831d35Sstevel 		mutex_exit(&iosram_mutex);
232603831d35Sstevel 		return (EAGAIN);
232703831d35Sstevel 	}
232803831d35Sstevel 
232903831d35Sstevel 	/*
233003831d35Sstevel 	 * Check if the specified instance holds the tunnel. If not,
233103831d35Sstevel 	 * then we are done.
233203831d35Sstevel 	 */
233303831d35Sstevel 	if ((iosram_master == NULL) || (iosram_master->instance != instance)) {
233403831d35Sstevel 		mutex_exit(&iosram_mutex);
233503831d35Sstevel 		return (0);
233603831d35Sstevel 	}
233703831d35Sstevel 
233803831d35Sstevel 	/*
233903831d35Sstevel 	 * Before beginning the tunnel switch process, wait for any outstanding
234003831d35Sstevel 	 * read/write activity to complete.
234103831d35Sstevel 	 */
234203831d35Sstevel 	iosram_tswitch_active = 1;
234303831d35Sstevel 	while (iosram_rw_active) {
234403831d35Sstevel 		iosram_rw_wakeup = 1;
234503831d35Sstevel 		cv_wait(&iosram_rw_wait, &iosram_mutex);
234603831d35Sstevel 	}
234703831d35Sstevel 
234803831d35Sstevel 	/*
234903831d35Sstevel 	 * If a previous tunnel switch just completed, we have to make sure
235003831d35Sstevel 	 * HWAD has enough time to find the new tunnel before we switch
235103831d35Sstevel 	 * away from it.  Otherwise, OBP's mailbox message to OSD will never
235203831d35Sstevel 	 * get through.  Just to be paranoid about synchronization of lbolt
235303831d35Sstevel 	 * across different CPUs, make sure the current attempt isn't noted
235403831d35Sstevel 	 * as starting _before_ the last tunnel switch completed.
235503831d35Sstevel 	 */
235603831d35Sstevel 	current_tstamp = ddi_get_lbolt();
235703831d35Sstevel 	if (current_tstamp > iosram_tswitch_tstamp) {
235803831d35Sstevel 		tstamp_interval = current_tstamp - iosram_tswitch_tstamp;
235903831d35Sstevel 	} else {
236003831d35Sstevel 		tstamp_interval = 0;
236103831d35Sstevel 	}
236203831d35Sstevel 	if (drv_hztousec(tstamp_interval) < IOSRAM_TSWITCH_DELAY_US) {
236303831d35Sstevel 		mutex_exit(&iosram_mutex);
236403831d35Sstevel 		delay(drv_usectohz(IOSRAM_TSWITCH_DELAY_US) - tstamp_interval);
236503831d35Sstevel 		mutex_enter(&iosram_mutex);
236603831d35Sstevel 	}
236703831d35Sstevel 
236803831d35Sstevel 	/*
236903831d35Sstevel 	 * The specified instance holds the tunnel.  We need to move it to some
237003831d35Sstevel 	 * other IOSRAM.  Try out all possible IOSRAMs listed in
237103831d35Sstevel 	 * iosram_instances.  For now, we always search from the first entry.
237203831d35Sstevel 	 * In future, it may be desirable to start where we left off.
237303831d35Sstevel 	 */
237403831d35Sstevel 	for (softp = iosram_instances; softp != NULL; softp = softp->next) {
237503831d35Sstevel 		if (iosram_tswitch_aborted) {
237603831d35Sstevel 			break;
237703831d35Sstevel 		}
237803831d35Sstevel 
237903831d35Sstevel 		/* we can't switch _to_ the instance we're switching _from_ */
238003831d35Sstevel 		if (softp->instance == instance) {
238103831d35Sstevel 			continue;
238203831d35Sstevel 		}
238303831d35Sstevel 
238403831d35Sstevel 		/* skip over instances being detached */
238503831d35Sstevel 		if (softp->state & IOSRAM_STATE_DETACH) {
238603831d35Sstevel 			continue;
238703831d35Sstevel 		}
238803831d35Sstevel 
238903831d35Sstevel 		/*
239003831d35Sstevel 		 * Try to avoid reverting to the last instance we switched away
239103831d35Sstevel 		 * from, as we expect that one to be detached eventually.  Keep
239203831d35Sstevel 		 * track of it, though, so we can go ahead and try switching to
239303831d35Sstevel 		 * it if no other viable candidates are found.
239403831d35Sstevel 		 */
239503831d35Sstevel 		if (softp->instance == last_master_instance) {
239603831d35Sstevel 			last_master = softp;
239703831d35Sstevel 			continue;
239803831d35Sstevel 		}
239903831d35Sstevel 
240003831d35Sstevel 		/*
240103831d35Sstevel 		 * Do the tunnel switch.  If successful, record the instance of
240203831d35Sstevel 		 * the master we just left behind so we can try to avoid
240303831d35Sstevel 		 * reverting to it next time.
240403831d35Sstevel 		 */
240503831d35Sstevel 		if (iosram_switch_tunnel(softp) == 0) {
240603831d35Sstevel 			last_master_instance = instance;
240703831d35Sstevel 			break;
240803831d35Sstevel 		}
240903831d35Sstevel 	}
241003831d35Sstevel 
241103831d35Sstevel 	/*
241203831d35Sstevel 	 * If we failed to switch the tunnel, but we skipped over an instance
241303831d35Sstevel 	 * that had previously been switched out of because we expected it to be
241403831d35Sstevel 	 * detached, go ahead and try it anyway (unless the tswitch was aborted
241503831d35Sstevel 	 * or the instance we skipped is finally being detached).
241603831d35Sstevel 	 */
241703831d35Sstevel 	if ((softp == NULL) && (last_master != NULL) &&
241803831d35Sstevel 	    !iosram_tswitch_aborted &&
241903831d35Sstevel 	    !(last_master->state & IOSRAM_STATE_DETACH)) {
242003831d35Sstevel 		if (iosram_switch_tunnel(last_master) == 0) {
242103831d35Sstevel 			softp = last_master;
242203831d35Sstevel 			last_master_instance = instance;
242303831d35Sstevel 		}
242403831d35Sstevel 	}
242503831d35Sstevel 
242603831d35Sstevel 	if ((softp == NULL) || (iosram_tswitch_aborted)) {
242703831d35Sstevel 		error = EIO;
242803831d35Sstevel 	}
242903831d35Sstevel 
243003831d35Sstevel 	/*
243103831d35Sstevel 	 * If there are additional tunnel switches queued up waiting for this
243203831d35Sstevel 	 * one to complete, wake them up.
243303831d35Sstevel 	 */
243403831d35Sstevel 	if (iosram_tswitch_wakeup) {
243503831d35Sstevel 		iosram_tswitch_wakeup = 0;
243603831d35Sstevel 		cv_broadcast(&iosram_tswitch_wait);
243703831d35Sstevel 	}
243803831d35Sstevel 	iosram_tswitch_active = 0;
243903831d35Sstevel 	mutex_exit(&iosram_mutex);
244003831d35Sstevel 	return (error);
244103831d35Sstevel }
244203831d35Sstevel 
244303831d35Sstevel 
244403831d35Sstevel /*
244503831d35Sstevel  * iosram_tunnel_capable(softp)
244603831d35Sstevel  *	Check if this IOSRAM instance is tunnel-capable by looing at
244703831d35Sstevel  *	"tunnel-capable" property.
244803831d35Sstevel  */
244903831d35Sstevel static int
245003831d35Sstevel iosram_tunnel_capable(struct iosramsoft *softp)
245103831d35Sstevel {
245203831d35Sstevel 	int	proplen;
245303831d35Sstevel 	int	tunnel_capable;
245403831d35Sstevel 
245503831d35Sstevel 	/*
245603831d35Sstevel 	 * Look up IOSRAM_TUNNELOK_PROP property, if any.
245703831d35Sstevel 	 */
245803831d35Sstevel 	proplen = sizeof (tunnel_capable);
245903831d35Sstevel 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, softp->dip,
246003831d35Sstevel 	    DDI_PROP_DONTPASS, IOSRAM_TUNNELOK_PROP, (caddr_t)&tunnel_capable,
246103831d35Sstevel 	    &proplen) != DDI_PROP_SUCCESS) {
246203831d35Sstevel 		tunnel_capable = 0;
246303831d35Sstevel 	}
246403831d35Sstevel 	return (tunnel_capable);
246503831d35Sstevel }
246603831d35Sstevel 
246703831d35Sstevel 
246803831d35Sstevel static int
246903831d35Sstevel iosram_sbbc_setup_map(struct iosramsoft *softp)
247003831d35Sstevel {
247103831d35Sstevel 	int				rv;
247203831d35Sstevel 	struct ddi_device_acc_attr	attr;
247303831d35Sstevel 	dev_info_t			*dip = softp->dip;
247403831d35Sstevel 	uint32_t			sema_val;
247503831d35Sstevel 
247603831d35Sstevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
247703831d35Sstevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
247803831d35Sstevel 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
247903831d35Sstevel 
248003831d35Sstevel 	mutex_enter(&iosram_mutex);
248103831d35Sstevel 	mutex_enter(&softp->intr_mutex);
248203831d35Sstevel 
248303831d35Sstevel 	/*
248403831d35Sstevel 	 * Map SBBC region in
248503831d35Sstevel 	 */
248603831d35Sstevel 	if ((rv = ddi_regs_map_setup(dip, IOSRAM_SBBC_MAP_INDEX,
248703831d35Sstevel 	    (caddr_t *)&softp->sbbc_region,
248803831d35Sstevel 	    IOSRAM_SBBC_MAP_OFFSET, sizeof (iosram_sbbc_region_t),
248903831d35Sstevel 	    &attr, &softp->sbbc_handle)) != DDI_SUCCESS) {
249003831d35Sstevel 		DPRINTF(1, ("Failed to map SBBC region.\n"));
249103831d35Sstevel 		mutex_exit(&softp->intr_mutex);
249203831d35Sstevel 		mutex_exit(&iosram_mutex);
249303831d35Sstevel 		return (rv);
249403831d35Sstevel 	}
249503831d35Sstevel 
249603831d35Sstevel 	/*
249703831d35Sstevel 	 * Disable SBBC interrupts. SBBC interrupts are enabled
249803831d35Sstevel 	 * once the interrupt handler is registered.
249903831d35Sstevel 	 */
250003831d35Sstevel 	ddi_put32(softp->sbbc_handle,
250103831d35Sstevel 	    &(softp->sbbc_region->int_enable.reg), 0x0);
250203831d35Sstevel 
250303831d35Sstevel 	/*
250403831d35Sstevel 	 * Clear hardware semaphore value if appropriate.
250503831d35Sstevel 	 * When the first SBBC is mapped in by the IOSRAM driver,
250603831d35Sstevel 	 * the value of the semaphore should be initialized only
250703831d35Sstevel 	 * if it is not held by SMS. For subsequent SBBC's, the
250803831d35Sstevel 	 * semaphore will be always initialized.
250903831d35Sstevel 	 */
251003831d35Sstevel 	sema_val = IOSRAM_SEMA_RD(softp);
251103831d35Sstevel 
251203831d35Sstevel 	if (!iosram_master) {
251303831d35Sstevel 		/* the first SBBC is being mapped in */
251403831d35Sstevel 		if (!(IOSRAM_SEMA_IS_HELD(sema_val) &&
251503831d35Sstevel 		    IOSRAM_SEMA_GET_IDX(sema_val) == IOSRAM_SEMA_SMS_IDX)) {
251603831d35Sstevel 			/* not held by SMS, we clear the semaphore */
251703831d35Sstevel 			IOSRAM_SEMA_WR(softp, 0);
251803831d35Sstevel 		}
251903831d35Sstevel 	} else {
252003831d35Sstevel 		/* not the first SBBC, we clear the semaphore */
252103831d35Sstevel 		IOSRAM_SEMA_WR(softp, 0);
252203831d35Sstevel 	}
252303831d35Sstevel 
252403831d35Sstevel 	mutex_exit(&softp->intr_mutex);
252503831d35Sstevel 	mutex_exit(&iosram_mutex);
252603831d35Sstevel 	return (0);
252703831d35Sstevel }
252803831d35Sstevel 
252903831d35Sstevel 
253003831d35Sstevel static int
253103831d35Sstevel iosram_setup_map(struct iosramsoft *softp)
253203831d35Sstevel {
253303831d35Sstevel 	int				instance = softp->instance;
253403831d35Sstevel 	dev_info_t			*dip = softp->dip;
253503831d35Sstevel 	int				portid;
253603831d35Sstevel 	int				proplen;
253703831d35Sstevel 	caddr_t				propvalue;
253803831d35Sstevel 	struct ddi_device_acc_attr	attr;
253903831d35Sstevel 
254003831d35Sstevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
254103831d35Sstevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
254203831d35Sstevel 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
254303831d35Sstevel 
254403831d35Sstevel 	/*
254503831d35Sstevel 	 * Lookup IOSRAM_REG_PROP property to find out our IOSRAM length
254603831d35Sstevel 	 */
254703831d35Sstevel 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
254803831d35Sstevel 	    DDI_PROP_DONTPASS, IOSRAM_REG_PROP, (caddr_t)&propvalue,
254903831d35Sstevel 	    &proplen) != DDI_PROP_SUCCESS) {
255003831d35Sstevel 		cmn_err(CE_WARN, "iosram(%d): can't find register property.\n",
255103831d35Sstevel 		    instance);
255203831d35Sstevel 		return (DDI_FAILURE);
255303831d35Sstevel 	} else {
255403831d35Sstevel 		iosram_reg_t	*regprop = (iosram_reg_t *)propvalue;
255503831d35Sstevel 
255603831d35Sstevel 		DPRINTF(1, ("SetupMap(%d): Got reg prop: %x %x %x\n",
255703831d35Sstevel 		    instance, regprop->addr_hi,
255803831d35Sstevel 		    regprop->addr_lo, regprop->size));
255903831d35Sstevel 
256003831d35Sstevel 		softp->iosramlen = regprop->size;
256103831d35Sstevel 
256203831d35Sstevel 		kmem_free(propvalue, proplen);
256303831d35Sstevel 	}
256403831d35Sstevel 	DPRINTF(1, ("SetupMap(%d): IOSRAM length: 0x%x\n", instance,
256503831d35Sstevel 	    softp->iosramlen));
256603831d35Sstevel 	softp->handle = NULL;
256703831d35Sstevel 
256803831d35Sstevel 	/*
256903831d35Sstevel 	 * To minimize boot time, we map the entire IOSRAM as opposed to
257003831d35Sstevel 	 * mapping individual chunk via ddi_regs_map_setup() call.
257103831d35Sstevel 	 */
257203831d35Sstevel 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&softp->iosramp,
257303831d35Sstevel 	    0x0, softp->iosramlen, &attr, &softp->handle) != DDI_SUCCESS) {
257403831d35Sstevel 		cmn_err(CE_WARN, "iosram(%d): failed to map IOSRAM len:%x\n",
257503831d35Sstevel 		    instance, softp->iosramlen);
257603831d35Sstevel 		iosram_remove_map(softp);
257703831d35Sstevel 		return (DDI_FAILURE);
257803831d35Sstevel 	}
257903831d35Sstevel 
258003831d35Sstevel 	/*
258103831d35Sstevel 	 * Lookup PORTID property on my parent hierarchy
258203831d35Sstevel 	 */
258303831d35Sstevel 	proplen = sizeof (portid);
258403831d35Sstevel 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
258503831d35Sstevel 	    0, IOSRAM_PORTID_PROP, (caddr_t)&portid,
258603831d35Sstevel 	    &proplen) != DDI_PROP_SUCCESS) {
258703831d35Sstevel 		cmn_err(CE_WARN, "iosram(%d): can't find portid property.\n",
258803831d35Sstevel 		    instance);
258903831d35Sstevel 		iosram_remove_map(softp);
259003831d35Sstevel 		return (DDI_FAILURE);
259103831d35Sstevel 	}
259203831d35Sstevel 	softp->portid = portid;
259303831d35Sstevel 
259403831d35Sstevel 	if (iosram_sbbc_setup_map(softp) != DDI_SUCCESS) {
259503831d35Sstevel 		cmn_err(CE_WARN, "iosram(%d): can't map SBBC region.\n",
259603831d35Sstevel 		    instance);
259703831d35Sstevel 		iosram_remove_map(softp);
259803831d35Sstevel 		return (DDI_FAILURE);
259903831d35Sstevel 	}
260003831d35Sstevel 
260103831d35Sstevel 	mutex_enter(&iosram_mutex);
260203831d35Sstevel 	softp->state |= IOSRAM_STATE_MAPPED;
260303831d35Sstevel 	mutex_exit(&iosram_mutex);
260403831d35Sstevel 
260503831d35Sstevel 	return (DDI_SUCCESS);
260603831d35Sstevel }
260703831d35Sstevel 
260803831d35Sstevel 
260903831d35Sstevel static void
261003831d35Sstevel iosram_remove_map(struct iosramsoft *softp)
261103831d35Sstevel {
261203831d35Sstevel 	mutex_enter(&iosram_mutex);
261303831d35Sstevel 
261403831d35Sstevel 	ASSERT((softp->state & IOSRAM_STATE_MASTER) == 0);
261503831d35Sstevel 
261603831d35Sstevel 	if (softp->handle) {
261703831d35Sstevel 		ddi_regs_map_free(&softp->handle);
261803831d35Sstevel 		softp->handle = NULL;
261903831d35Sstevel 	}
262003831d35Sstevel 	softp->iosramp = NULL;
262103831d35Sstevel 
262203831d35Sstevel 	/*
262303831d35Sstevel 	 * Umap SBBC registers region. Shared with handler for SBBC
262403831d35Sstevel 	 * interrupts, take intr_mutex.
262503831d35Sstevel 	 */
262603831d35Sstevel 	mutex_enter(&softp->intr_mutex);
262703831d35Sstevel 	if (softp->sbbc_region) {
262803831d35Sstevel 		ddi_regs_map_free(&softp->sbbc_handle);
262903831d35Sstevel 		softp->sbbc_region = NULL;
263003831d35Sstevel 	}
263103831d35Sstevel 	mutex_exit(&softp->intr_mutex);
263203831d35Sstevel 
263303831d35Sstevel 	softp->state &= ~IOSRAM_STATE_MAPPED;
263403831d35Sstevel 
263503831d35Sstevel 	mutex_exit(&iosram_mutex);
263603831d35Sstevel }
263703831d35Sstevel 
263803831d35Sstevel 
263903831d35Sstevel /*
264003831d35Sstevel  * iosram_is_chosen(struct iosramsoft *softp)
264103831d35Sstevel  *
264203831d35Sstevel  *	Looks up "chosen" node property to
264303831d35Sstevel  *	determine if it is the chosen IOSRAM.
264403831d35Sstevel  */
264503831d35Sstevel static int
264603831d35Sstevel iosram_is_chosen(struct iosramsoft *softp)
264703831d35Sstevel {
264803831d35Sstevel 	char		chosen_iosram[MAXNAMELEN];
264903831d35Sstevel 	char		pn[MAXNAMELEN];
265003831d35Sstevel 	int		nodeid;
265103831d35Sstevel 	int		chosen;
265203831d35Sstevel 	pnode_t		dnode;
265303831d35Sstevel 
265403831d35Sstevel 	/*
265503831d35Sstevel 	 * Get /chosen node info. prom interface will handle errors.
265603831d35Sstevel 	 */
265703831d35Sstevel 	dnode = prom_chosennode();
265803831d35Sstevel 
265903831d35Sstevel 	/*
266003831d35Sstevel 	 * Look for the "iosram" property on the chosen node with a prom
266103831d35Sstevel 	 * interface as ddi_find_devinfo() couldn't be used (calls
266203831d35Sstevel 	 * ddi_walk_devs() that creates one extra lock on the device tree).
266303831d35Sstevel 	 */
266403831d35Sstevel 	if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) {
266503831d35Sstevel 		/*
266603831d35Sstevel 		 * Can't find IOSRAM_CHOSEN_PROP property under chosen node
266703831d35Sstevel 		 */
266803831d35Sstevel 		cmn_err(CE_WARN,
266903831d35Sstevel 		    "iosram(%d): can't find chosen iosram property\n",
267003831d35Sstevel 		    softp->instance);
267103831d35Sstevel 		return (0);
267203831d35Sstevel 	}
267303831d35Sstevel 
267403831d35Sstevel 	DPRINTF(1, ("iosram(%d): Got '%x' for chosen '%s' property\n",
267503831d35Sstevel 	    softp->instance, nodeid, IOSRAM_CHOSEN_PROP));
267603831d35Sstevel 
267703831d35Sstevel 	/*
267803831d35Sstevel 	 * get the full OBP pathname of this node
267903831d35Sstevel 	 */
268003831d35Sstevel 	if (prom_phandle_to_path((phandle_t)nodeid, chosen_iosram,
268103831d35Sstevel 	    sizeof (chosen_iosram)) < 0) {
268203831d35Sstevel 		cmn_err(CE_NOTE, "prom_phandle_to_path(%x) failed\n", nodeid);
268303831d35Sstevel 		return (0);
268403831d35Sstevel 	}
268503831d35Sstevel 	DPRINTF(1, ("iosram(%d): prom_phandle_to_path(%x) is '%s'\n",
268603831d35Sstevel 	    softp->instance, nodeid, chosen_iosram));
268703831d35Sstevel 
268803831d35Sstevel 	(void) ddi_pathname(softp->dip, pn);
268903831d35Sstevel 	DPRINTF(1, ("iosram(%d): ddi_pathname(%p) is '%s'\n",
2690*07d06da5SSurya Prakki 	    softp->instance, (void *)softp->dip, pn));
269103831d35Sstevel 
269203831d35Sstevel 	chosen = (strcmp(chosen_iosram, pn) == 0) ? 1 : 0;
269303831d35Sstevel 	DPRINTF(1, ("iosram(%d): ... %s\n", softp->instance,
269403831d35Sstevel 	    chosen ? "MASTER" : "SLAVE"));
269503831d35Sstevel 	IOSRAMLOG(1, "iosram(%d): ... %s\n", softp->instance,
269603831d35Sstevel 	    (chosen ? "MASTER" : "SLAVE"), NULL, NULL);
269703831d35Sstevel 
269803831d35Sstevel 	return (chosen);
269903831d35Sstevel }
270003831d35Sstevel 
270103831d35Sstevel 
270203831d35Sstevel /*
270303831d35Sstevel  * iosram_set_master(struct iosramsoft *softp)
270403831d35Sstevel  *
270503831d35Sstevel  *	Set master tunnel to the specified IOSRAM
270603831d35Sstevel  *	Must be called while holding iosram_mutex.
270703831d35Sstevel  */
270803831d35Sstevel static void
270903831d35Sstevel iosram_set_master(struct iosramsoft *softp)
271003831d35Sstevel {
271103831d35Sstevel 	ASSERT(mutex_owned(&iosram_mutex));
271203831d35Sstevel 	ASSERT(softp != NULL);
271303831d35Sstevel 	ASSERT(softp->state & IOSRAM_STATE_MAPPED);
271403831d35Sstevel 	ASSERT(IOSRAM_GET_HDRFIELD32(softp, status) == IOSRAM_VALID);
271503831d35Sstevel 
271603831d35Sstevel 	/*
271703831d35Sstevel 	 * Clear MASTER flag on any previous IOSRAM master, if any
271803831d35Sstevel 	 */
271903831d35Sstevel 	if (iosram_master && (iosram_master != softp)) {
272003831d35Sstevel 		iosram_master->state &= ~IOSRAM_STATE_MASTER;
272103831d35Sstevel 	}
272203831d35Sstevel 
272303831d35Sstevel 	/*
272403831d35Sstevel 	 * Setup new IOSRAM master
272503831d35Sstevel 	 */
272603831d35Sstevel 	iosram_update_addrs(softp);
272703831d35Sstevel 	iosram_handle = softp->handle;
272803831d35Sstevel 	softp->state |= IOSRAM_STATE_MASTER;
272903831d35Sstevel 	softp->tswitch_ok++;
273003831d35Sstevel 	iosram_master = softp;
273103831d35Sstevel 
273203831d35Sstevel 	IOSRAMLOG(1, "SETMASTER: softp:%p instance:%d\n", softp,
273303831d35Sstevel 	    softp->instance, NULL, NULL);
273403831d35Sstevel }
273503831d35Sstevel 
273603831d35Sstevel 
273703831d35Sstevel /*
273803831d35Sstevel  * iosram_read_toc()
273903831d35Sstevel  *
274003831d35Sstevel  *	Read the TOC from an IOSRAM instance that has been mapped in.
274103831d35Sstevel  *	If the TOC is flawed or the IOSRAM isn't valid, return an error.
274203831d35Sstevel  */
274303831d35Sstevel static int
274403831d35Sstevel iosram_read_toc(struct iosramsoft *softp)
274503831d35Sstevel {
274603831d35Sstevel 	int			i;
274703831d35Sstevel 	int			instance = softp->instance;
274803831d35Sstevel 	uint8_t			*toc_entryp;
274903831d35Sstevel 	iosram_flags_t		*flagsp = NULL;
275003831d35Sstevel 	int			new_nchunks;
275103831d35Sstevel 	iosram_chunk_t		*new_chunks;
275203831d35Sstevel 	iosram_chunk_t		*chunkp;
275303831d35Sstevel 	iosram_chunk_t		*old_chunkp;
275403831d35Sstevel 	iosram_toc_entry_t	index;
275503831d35Sstevel 
275603831d35Sstevel 	/*
275703831d35Sstevel 	 * Never try to read the TOC out of an unmapped IOSRAM.
275803831d35Sstevel 	 */
275903831d35Sstevel 	ASSERT(softp->state & IOSRAM_STATE_MAPPED);
276003831d35Sstevel 
276103831d35Sstevel 	mutex_enter(&iosram_mutex);
276203831d35Sstevel 
276303831d35Sstevel 	/*
276403831d35Sstevel 	 * Check to make sure this IOSRAM is marked valid.  Return
276503831d35Sstevel 	 * an error if it isn't.
276603831d35Sstevel 	 */
276703831d35Sstevel 	if (IOSRAM_GET_HDRFIELD32(softp, status) != IOSRAM_VALID) {
276803831d35Sstevel 		DPRINTF(1, ("iosram_read_toc(%d): IOSRAM not flagged valid\n",
276903831d35Sstevel 		    instance));
277003831d35Sstevel 		mutex_exit(&iosram_mutex);
277103831d35Sstevel 		return (EINVAL);
277203831d35Sstevel 	}
277303831d35Sstevel 
277403831d35Sstevel 	/*
277503831d35Sstevel 	 * Get the location of the TOC.
277603831d35Sstevel 	 */
277703831d35Sstevel 	toc_entryp = softp->iosramp + IOSRAM_GET_HDRFIELD32(softp, toc_offset);
277803831d35Sstevel 
277903831d35Sstevel 	/*
278003831d35Sstevel 	 * Read the index entry from the TOC and make sure it looks correct.
278103831d35Sstevel 	 */
278203831d35Sstevel 	ddi_rep_get8(softp->handle, (uint8_t *)&index, toc_entryp,
278303831d35Sstevel 	    sizeof (iosram_toc_entry_t), DDI_DEV_AUTOINCR);
278403831d35Sstevel 	if ((index.key != IOSRAM_INDEX_KEY) ||
278503831d35Sstevel 	    (index.off != IOSRAM_INDEX_OFF)) {
278603831d35Sstevel 		cmn_err(CE_WARN, "iosram(%d): invalid TOC index.\n", instance);
278703831d35Sstevel 		mutex_exit(&iosram_mutex);
278803831d35Sstevel 		return (EINVAL);
278903831d35Sstevel 	}
279003831d35Sstevel 
279103831d35Sstevel 	/*
279203831d35Sstevel 	 * Allocate storage for the new chunks array and initialize it with data
279303831d35Sstevel 	 * from the TOC and callback data from the corresponding old chunk, if
279403831d35Sstevel 	 * it exists.
279503831d35Sstevel 	 */
279603831d35Sstevel 	new_nchunks = index.len - 1;
279703831d35Sstevel 	new_chunks = (iosram_chunk_t *)kmem_zalloc(new_nchunks *
279803831d35Sstevel 	    sizeof (iosram_chunk_t), KM_SLEEP);
279903831d35Sstevel 	for (i = 0, chunkp = new_chunks; i < new_nchunks; i++, chunkp++) {
280003831d35Sstevel 		toc_entryp += sizeof (iosram_toc_entry_t);
280103831d35Sstevel 		ddi_rep_get8(softp->handle, (uint8_t *)&(chunkp->toc_data),
280203831d35Sstevel 		    toc_entryp, sizeof (iosram_toc_entry_t), DDI_DEV_AUTOINCR);
280303831d35Sstevel 		chunkp->hash = NULL;
280403831d35Sstevel 		if ((chunkp->toc_data.off < softp->iosramlen) &&
280503831d35Sstevel 		    (chunkp->toc_data.len <= softp->iosramlen) &&
280603831d35Sstevel 		    ((chunkp->toc_data.off + chunkp->toc_data.len) <=
280703831d35Sstevel 		    softp->iosramlen)) {
280803831d35Sstevel 			chunkp->basep = softp->iosramp + chunkp->toc_data.off;
280903831d35Sstevel 			DPRINTF(1,
2810*07d06da5SSurya Prakki 			    ("iosram_read_toc(%d): k:%x o:%x l:%x p:%p\n",
281103831d35Sstevel 			    instance, chunkp->toc_data.key,
281203831d35Sstevel 			    chunkp->toc_data.off, chunkp->toc_data.len,
2813*07d06da5SSurya Prakki 			    (void *)chunkp->basep));
281403831d35Sstevel 		} else {
281503831d35Sstevel 			cmn_err(CE_WARN, "iosram(%d): TOC entry %d"
281603831d35Sstevel 			    "out of range... off:%x  len:%x\n",
281703831d35Sstevel 			    instance, i + 1, chunkp->toc_data.off,
281803831d35Sstevel 			    chunkp->toc_data.len);
281903831d35Sstevel 			kmem_free(new_chunks, new_nchunks *
282003831d35Sstevel 			    sizeof (iosram_chunk_t));
282103831d35Sstevel 			mutex_exit(&iosram_mutex);
282203831d35Sstevel 			return (EINVAL);
282303831d35Sstevel 		}
282403831d35Sstevel 
282503831d35Sstevel 		/*
282603831d35Sstevel 		 * Note the existence of the flags chunk, which is required in
282703831d35Sstevel 		 * a correct TOC.
282803831d35Sstevel 		 */
282903831d35Sstevel 		if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) {
283003831d35Sstevel 			flagsp = (iosram_flags_t *)chunkp->basep;
283103831d35Sstevel 		}
283203831d35Sstevel 
283303831d35Sstevel 		/*
283403831d35Sstevel 		 * If there was an entry for this chunk in the old list, copy
283503831d35Sstevel 		 * the callback data from old to new storage.
283603831d35Sstevel 		 */
283703831d35Sstevel 		if ((nchunks > 0) &&
283803831d35Sstevel 		    ((old_chunkp = iosram_find_chunk(chunkp->toc_data.key)) !=
283903831d35Sstevel 		    NULL)) {
284003831d35Sstevel 			bcopy(&(old_chunkp->cback), &(chunkp->cback),
284103831d35Sstevel 			    sizeof (iosram_cback_t));
284203831d35Sstevel 		}
284303831d35Sstevel 	}
284403831d35Sstevel 	/*
284503831d35Sstevel 	 * The TOC is malformed if there is no entry for the flags chunk.
284603831d35Sstevel 	 */
284703831d35Sstevel 	if (flagsp == NULL) {
284803831d35Sstevel 		kmem_free(new_chunks, new_nchunks * sizeof (iosram_chunk_t));
284903831d35Sstevel 		mutex_exit(&iosram_mutex);
285003831d35Sstevel 		return (EINVAL);
285103831d35Sstevel 	}
285203831d35Sstevel 
285303831d35Sstevel 	/*
285403831d35Sstevel 	 * Free any memory that is no longer needed and install the new data
285503831d35Sstevel 	 * as current data.
285603831d35Sstevel 	 */
285703831d35Sstevel 	if (chunks != NULL) {
285803831d35Sstevel 		kmem_free(chunks, nchunks * sizeof (iosram_chunk_t));
285903831d35Sstevel 	}
286003831d35Sstevel 	chunks = new_chunks;
286103831d35Sstevel 	nchunks = new_nchunks;
286203831d35Sstevel 	iosram_init_hashtab();
286303831d35Sstevel 
286403831d35Sstevel 	mutex_exit(&iosram_mutex);
286503831d35Sstevel 	return (0);
286603831d35Sstevel }
286703831d35Sstevel 
286803831d35Sstevel 
286903831d35Sstevel /*
287003831d35Sstevel  * iosram_init_hashtab()
287103831d35Sstevel  *
287203831d35Sstevel  *	Initialize the hash table and populate it with the IOSRAM
287303831d35Sstevel  *	chunks previously read from the TOC.  The caller must hold the
287403831d35Sstevel  *	ioram_mutex lock.
287503831d35Sstevel  */
287603831d35Sstevel static void
287703831d35Sstevel iosram_init_hashtab(void)
287803831d35Sstevel {
287903831d35Sstevel 	int		i, bucket;
288003831d35Sstevel 	iosram_chunk_t	*chunkp;
288103831d35Sstevel 
288203831d35Sstevel 	ASSERT(mutex_owned(&iosram_mutex));
288303831d35Sstevel 
288403831d35Sstevel 	for (i = 0; i < IOSRAM_HASHSZ; i++) {
288503831d35Sstevel 		iosram_hashtab[i] = NULL;
288603831d35Sstevel 	}
288703831d35Sstevel 
288803831d35Sstevel 	if (chunks) {
288903831d35Sstevel 		for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
289003831d35Sstevel 			/*
289103831d35Sstevel 			 * Hide the flags chunk by leaving it out of the hash
289203831d35Sstevel 			 * table.
289303831d35Sstevel 			 */
289403831d35Sstevel 			if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) {
289503831d35Sstevel 				continue;
289603831d35Sstevel 			}
289703831d35Sstevel 
289803831d35Sstevel 			/*
289903831d35Sstevel 			 * Add the current chunk to the hash table.
290003831d35Sstevel 			 */
290103831d35Sstevel 			bucket = IOSRAM_HASH(chunkp->toc_data.key);
290203831d35Sstevel 			chunkp->hash = iosram_hashtab[bucket];
290303831d35Sstevel 			iosram_hashtab[bucket] = chunkp;
290403831d35Sstevel 		}
290503831d35Sstevel 	}
290603831d35Sstevel }
290703831d35Sstevel 
290803831d35Sstevel 
290903831d35Sstevel /*
291003831d35Sstevel  * iosram_update_addrs()
291103831d35Sstevel  *
291203831d35Sstevel  *	Process the chunk list, updating each chunk's basep, which is a pointer
291303831d35Sstevel  *	to the beginning of the chunk's memory in kvaddr space.  Record the
291403831d35Sstevel  *	basep value of the flags chunk to speed up flag access.  The caller
291503831d35Sstevel  *	must hold the iosram_mutex lock.
291603831d35Sstevel  */
291703831d35Sstevel static void
291803831d35Sstevel iosram_update_addrs(struct iosramsoft *softp)
291903831d35Sstevel {
292003831d35Sstevel 	int		i;
292103831d35Sstevel 	iosram_flags_t	*flagsp;
292203831d35Sstevel 	iosram_chunk_t	*chunkp;
292303831d35Sstevel 
292403831d35Sstevel 	ASSERT(mutex_owned(&iosram_mutex));
292503831d35Sstevel 
292603831d35Sstevel 	/*
292703831d35Sstevel 	 * First go through all of the chunks updating their base pointers and
292803831d35Sstevel 	 * looking for the flags chunk.
292903831d35Sstevel 	 */
293003831d35Sstevel 	for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
293103831d35Sstevel 		chunkp->basep = softp->iosramp + chunkp->toc_data.off;
293203831d35Sstevel 		if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) {
293303831d35Sstevel 			flagsp = (iosram_flags_t *)(chunkp->basep);
293403831d35Sstevel 			DPRINTF(1,
293503831d35Sstevel 			    ("iosram_update_addrs flags: o:0x%08x p:%p",
2936*07d06da5SSurya Prakki 			    chunkp->toc_data.off, (void *)flagsp));
293703831d35Sstevel 		}
293803831d35Sstevel 	}
293903831d35Sstevel 
294003831d35Sstevel 	/*
294103831d35Sstevel 	 * Now, go through and update each chunk's flags pointer.  This can't be
294203831d35Sstevel 	 * done in the first loop because we don't have the address of the flags
294303831d35Sstevel 	 * chunk yet.
294403831d35Sstevel 	 */
294503831d35Sstevel 	for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
294603831d35Sstevel 		chunkp->flagsp = flagsp++;
294703831d35Sstevel 		DPRINTF(1, ("iosram_update_addrs: k:0x%x f:%p\n",
2948*07d06da5SSurya Prakki 		    chunkp->toc_data.key, (void *)chunkp->flagsp));
294903831d35Sstevel 	}
295003831d35Sstevel }
295103831d35Sstevel 
295203831d35Sstevel /*
295303831d35Sstevel  * iosram_find_chunk(key)
295403831d35Sstevel  *
295503831d35Sstevel  *	Return a pointer to iosram_chunk structure corresponding to the
295603831d35Sstevel  *	"key" IOSRAM chunk.  The caller must hold the iosram_mutex lock.
295703831d35Sstevel  */
295803831d35Sstevel static iosram_chunk_t *
295903831d35Sstevel iosram_find_chunk(uint32_t key)
296003831d35Sstevel {
296103831d35Sstevel 	iosram_chunk_t	*chunkp;
296203831d35Sstevel 	int		index = IOSRAM_HASH(key);
296303831d35Sstevel 
296403831d35Sstevel 	ASSERT(mutex_owned(&iosram_mutex));
296503831d35Sstevel 
296603831d35Sstevel 	for (chunkp = iosram_hashtab[index]; chunkp; chunkp = chunkp->hash) {
296703831d35Sstevel 		if (chunkp->toc_data.key == key) {
296803831d35Sstevel 			break;
296903831d35Sstevel 		}
297003831d35Sstevel 	}
297103831d35Sstevel 
297203831d35Sstevel 	return (chunkp);
297303831d35Sstevel }
297403831d35Sstevel 
297503831d35Sstevel 
297603831d35Sstevel /*
297703831d35Sstevel  * iosram_add_intr(iosramsoft_t *)
297803831d35Sstevel  */
297903831d35Sstevel static int
298003831d35Sstevel iosram_add_intr(iosramsoft_t *softp)
298103831d35Sstevel {
298203831d35Sstevel 	IOSRAMLOG(2, "ADDINTR: softp:%p  instance:%d\n",
298303831d35Sstevel 	    softp, softp->instance, NULL, NULL);
298403831d35Sstevel 
298503831d35Sstevel 	if (ddi_add_softintr(softp->dip, DDI_SOFTINT_MED,
298603831d35Sstevel 	    &softp->softintr_id, &softp->soft_iblk, NULL,
298703831d35Sstevel 	    iosram_softintr, (caddr_t)softp) != DDI_SUCCESS) {
298803831d35Sstevel 		cmn_err(CE_WARN,
298903831d35Sstevel 		    "iosram(%d): Can't register softintr.\n",
299003831d35Sstevel 		    softp->instance);
299103831d35Sstevel 		return (DDI_FAILURE);
299203831d35Sstevel 	}
299303831d35Sstevel 
299403831d35Sstevel 	if (ddi_add_intr(softp->dip, 0, &softp->real_iblk, NULL,
299503831d35Sstevel 	    iosram_intr, (caddr_t)softp) != DDI_SUCCESS) {
299603831d35Sstevel 		cmn_err(CE_WARN,
299703831d35Sstevel 		    "iosram(%d): Can't register intr"
299803831d35Sstevel 		    " handler.\n", softp->instance);
299903831d35Sstevel 		ddi_remove_softintr(softp->softintr_id);
300003831d35Sstevel 		return (DDI_FAILURE);
300103831d35Sstevel 	}
300203831d35Sstevel 
300303831d35Sstevel 	/*
300403831d35Sstevel 	 * Enable SBBC interrupts
300503831d35Sstevel 	 */
300603831d35Sstevel 	ddi_put32(softp->sbbc_handle, &(softp->sbbc_region->int_enable.reg),
300703831d35Sstevel 	    IOSRAM_SBBC_INT0|IOSRAM_SBBC_INT1);
300803831d35Sstevel 
300903831d35Sstevel 	return (DDI_SUCCESS);
301003831d35Sstevel }
301103831d35Sstevel 
301203831d35Sstevel 
301303831d35Sstevel /*
301403831d35Sstevel  * iosram_remove_intr(iosramsoft_t *)
301503831d35Sstevel  */
301603831d35Sstevel static int
301703831d35Sstevel iosram_remove_intr(iosramsoft_t *softp)
301803831d35Sstevel {
301903831d35Sstevel 	IOSRAMLOG(2, "REMINTR: softp:%p  instance:%d\n",
302003831d35Sstevel 	    softp, softp->instance, NULL, NULL);
302103831d35Sstevel 
302203831d35Sstevel 	/*
302303831d35Sstevel 	 * Disable SBBC interrupts if SBBC is mapped in
302403831d35Sstevel 	 */
302503831d35Sstevel 	if (softp->sbbc_region) {
302603831d35Sstevel 		ddi_put32(softp->sbbc_handle,
302703831d35Sstevel 		    &(softp->sbbc_region->int_enable.reg), 0);
302803831d35Sstevel 	}
302903831d35Sstevel 
303003831d35Sstevel 	/*
303103831d35Sstevel 	 * Remove SBBC interrupt handler
303203831d35Sstevel 	 */
303303831d35Sstevel 	ddi_remove_intr(softp->dip, 0, softp->real_iblk);
303403831d35Sstevel 
303503831d35Sstevel 	/*
303603831d35Sstevel 	 * Remove soft interrupt handler
303703831d35Sstevel 	 */
303803831d35Sstevel 	mutex_enter(&iosram_mutex);
303903831d35Sstevel 	if (softp->softintr_id != NULL) {
304003831d35Sstevel 		ddi_remove_softintr(softp->softintr_id);
304103831d35Sstevel 		softp->softintr_id = NULL;
304203831d35Sstevel 	}
304303831d35Sstevel 	mutex_exit(&iosram_mutex);
304403831d35Sstevel 
304503831d35Sstevel 	return (0);
304603831d35Sstevel }
304703831d35Sstevel 
304803831d35Sstevel 
304903831d35Sstevel /*
305003831d35Sstevel  * iosram_add_instance(iosramsoft_t *)
305103831d35Sstevel  * Must be called while holding iosram_mutex
305203831d35Sstevel  */
305303831d35Sstevel static void
305403831d35Sstevel iosram_add_instance(iosramsoft_t *new_softp)
305503831d35Sstevel {
305603831d35Sstevel #ifdef DEBUG
305703831d35Sstevel 	int		instance = new_softp->instance;
305803831d35Sstevel 	iosramsoft_t	*softp;
305903831d35Sstevel #endif
306003831d35Sstevel 
306103831d35Sstevel 	ASSERT(mutex_owned(&iosram_mutex));
306203831d35Sstevel 
306303831d35Sstevel #if defined(DEBUG)
306403831d35Sstevel 	/* Verify that this instance is not in the list */
306503831d35Sstevel 	for (softp = iosram_instances; softp != NULL; softp = softp->next) {
306603831d35Sstevel 		ASSERT(softp->instance != instance);
306703831d35Sstevel 	}
306803831d35Sstevel #endif
306903831d35Sstevel 
307003831d35Sstevel 	/*
307103831d35Sstevel 	 * Add this instance to the list
307203831d35Sstevel 	 */
307303831d35Sstevel 	if (iosram_instances != NULL) {
307403831d35Sstevel 		iosram_instances->prev = new_softp;
307503831d35Sstevel 	}
307603831d35Sstevel 	new_softp->next = iosram_instances;
307703831d35Sstevel 	new_softp->prev = NULL;
307803831d35Sstevel 	iosram_instances = new_softp;
307903831d35Sstevel }
308003831d35Sstevel 
308103831d35Sstevel 
308203831d35Sstevel /*
308303831d35Sstevel  * iosram_remove_instance(int instance)
308403831d35Sstevel  * Must be called while holding iosram_mutex
308503831d35Sstevel  */
308603831d35Sstevel static void
308703831d35Sstevel iosram_remove_instance(int instance)
308803831d35Sstevel {
308903831d35Sstevel 	iosramsoft_t *softp;
309003831d35Sstevel 
309103831d35Sstevel 	/*
309203831d35Sstevel 	 * Remove specified instance from the iosram_instances list so that
309303831d35Sstevel 	 * it can't be chosen for tunnel in future.
309403831d35Sstevel 	 */
309503831d35Sstevel 	ASSERT(mutex_owned(&iosram_mutex));
309603831d35Sstevel 
309703831d35Sstevel 	for (softp = iosram_instances; softp != NULL; softp = softp->next) {
309803831d35Sstevel 		if (softp->instance == instance) {
309903831d35Sstevel 			if (softp->next != NULL) {
310003831d35Sstevel 				softp->next->prev = softp->prev;
310103831d35Sstevel 			}
310203831d35Sstevel 			if (softp->prev != NULL) {
310303831d35Sstevel 				softp->prev->next = softp->next;
310403831d35Sstevel 			}
310503831d35Sstevel 			if (iosram_instances == softp) {
310603831d35Sstevel 				iosram_instances = softp->next;
310703831d35Sstevel 			}
310803831d35Sstevel 
310903831d35Sstevel 			return;
311003831d35Sstevel 		}
311103831d35Sstevel 	}
311203831d35Sstevel }
311303831d35Sstevel 
311403831d35Sstevel 
311503831d35Sstevel /*
311603831d35Sstevel  * iosram_sema_acquire: Acquire hardware semaphore.
311703831d35Sstevel  * Return 0 if the semaphore could be acquired, or one of the following
311803831d35Sstevel  * possible values:
311903831d35Sstevel  * EAGAIN: there is a tunnel switch in progress
312003831d35Sstevel  * EBUSY: the semaphore was already "held"
312103831d35Sstevel  * ENXIO:  an IO error occured (e.g. SBBC not mapped)
312203831d35Sstevel  * If old_value is not NULL, the location it points to will be updated
312303831d35Sstevel  * with the semaphore value read when attempting to acquire it.
312403831d35Sstevel  */
312503831d35Sstevel int
312603831d35Sstevel iosram_sema_acquire(uint32_t *old_value)
312703831d35Sstevel {
312803831d35Sstevel 	struct iosramsoft	*softp;
312903831d35Sstevel 	int			rv;
313003831d35Sstevel 	uint32_t		sema_val;
313103831d35Sstevel 
313203831d35Sstevel 	DPRINTF(2, ("IOSRAM: in iosram_sema_acquire\n"));
313303831d35Sstevel 
313403831d35Sstevel 	mutex_enter(&iosram_mutex);
313503831d35Sstevel 
313603831d35Sstevel 	/*
313703831d35Sstevel 	 * Disallow access if there is a tunnel switch in progress.
313803831d35Sstevel 	 */
313903831d35Sstevel 	if (iosram_tswitch_active) {
314003831d35Sstevel 		mutex_exit(&iosram_mutex);
314103831d35Sstevel 		return (EAGAIN);
314203831d35Sstevel 	}
314303831d35Sstevel 
314403831d35Sstevel 	/*
314503831d35Sstevel 	 * Use current master IOSRAM for operation, fail if none is
314603831d35Sstevel 	 * currently active.
314703831d35Sstevel 	 */
314803831d35Sstevel 	if ((softp = iosram_master) == NULL) {
314903831d35Sstevel 		mutex_exit(&iosram_mutex);
315003831d35Sstevel 		DPRINTF(1, ("IOSRAM: iosram_sema_acquire: no master\n"));
315103831d35Sstevel 		return (ENXIO);
315203831d35Sstevel 	}
315303831d35Sstevel 
315403831d35Sstevel 	mutex_enter(&softp->intr_mutex);
315503831d35Sstevel 
315603831d35Sstevel 	/*
315703831d35Sstevel 	 * Fail if SBBC region has not been mapped. This shouldn't
315803831d35Sstevel 	 * happen if we have a master IOSRAM, but we double-check.
315903831d35Sstevel 	 */
316003831d35Sstevel 	if (softp->sbbc_region == NULL) {
316103831d35Sstevel 		mutex_exit(&softp->intr_mutex);
316203831d35Sstevel 		mutex_exit(&iosram_mutex);
316303831d35Sstevel 		DPRINTF(1, ("IOSRAM(%d): iosram_sema_acquire: "
316403831d35Sstevel 		    "SBBC not mapped\n", softp->instance));
316503831d35Sstevel 		return (ENXIO);
316603831d35Sstevel 	}
316703831d35Sstevel 
316803831d35Sstevel 	/* read semaphore value */
316903831d35Sstevel 	sema_val = IOSRAM_SEMA_RD(softp);
317003831d35Sstevel 	if (old_value != NULL)
317103831d35Sstevel 		*old_value = sema_val;
317203831d35Sstevel 
317303831d35Sstevel 	if (IOSRAM_SEMA_IS_HELD(sema_val)) {
317403831d35Sstevel 		/* semaphore was held by someone else */
317503831d35Sstevel 		rv = EBUSY;
317603831d35Sstevel 	} else {
317703831d35Sstevel 		/* semaphore was not held, we just acquired it */
317803831d35Sstevel 		rv = 0;
317903831d35Sstevel 	}
318003831d35Sstevel 
318103831d35Sstevel 	mutex_exit(&softp->intr_mutex);
318203831d35Sstevel 	mutex_exit(&iosram_mutex);
318303831d35Sstevel 
318403831d35Sstevel 	DPRINTF(1, ("IOSRAM(%d): iosram_sema_acquire: "
318503831d35Sstevel 	    "old value=0x%x rv=%d\n", softp->instance, sema_val, rv));
318603831d35Sstevel 
318703831d35Sstevel 	return (rv);
318803831d35Sstevel }
318903831d35Sstevel 
319003831d35Sstevel 
319103831d35Sstevel /*
319203831d35Sstevel  * iosram_sema_release: Release hardware semaphore.
319303831d35Sstevel  * This function will "release" the hardware semaphore, and return 0 on
319403831d35Sstevel  * success. If an error occured, one of the following values will be
319503831d35Sstevel  * returned:
319603831d35Sstevel  * EAGAIN: there is a tunnel switch in progress
319703831d35Sstevel  * ENXIO:  an IO error occured (e.g. SBBC not mapped)
319803831d35Sstevel  */
319903831d35Sstevel int
320003831d35Sstevel iosram_sema_release(void)
320103831d35Sstevel {
320203831d35Sstevel 	struct iosramsoft	*softp;
320303831d35Sstevel 
320403831d35Sstevel 	DPRINTF(2, ("IOSRAM: in iosram_sema_release\n"));
320503831d35Sstevel 
320603831d35Sstevel 	mutex_enter(&iosram_mutex);
320703831d35Sstevel 
320803831d35Sstevel 	/*
320903831d35Sstevel 	 * Disallow access if there is a tunnel switch in progress.
321003831d35Sstevel 	 */
321103831d35Sstevel 	if (iosram_tswitch_active) {
321203831d35Sstevel 		mutex_exit(&iosram_mutex);
321303831d35Sstevel 		return (EAGAIN);
321403831d35Sstevel 	}
321503831d35Sstevel 
321603831d35Sstevel 	/*
321703831d35Sstevel 	 * Use current master IOSRAM for operation, fail if none is
321803831d35Sstevel 	 * currently active.
321903831d35Sstevel 	 */
322003831d35Sstevel 	if ((softp = iosram_master) == NULL) {
322103831d35Sstevel 		mutex_exit(&iosram_mutex);
322203831d35Sstevel 		DPRINTF(1, ("IOSRAM: iosram_sema_release: no master\n"));
322303831d35Sstevel 		return (ENXIO);
322403831d35Sstevel 	}
322503831d35Sstevel 
322603831d35Sstevel 	mutex_enter(&softp->intr_mutex);
322703831d35Sstevel 
322803831d35Sstevel 	/*
322903831d35Sstevel 	 * Fail if SBBC region has not been mapped in. This shouldn't
323003831d35Sstevel 	 * happen if we have a master IOSRAM, but we double-check.
323103831d35Sstevel 	 */
323203831d35Sstevel 	if (softp->sbbc_region == NULL) {
323303831d35Sstevel 		mutex_exit(&softp->intr_mutex);
323403831d35Sstevel 		mutex_exit(&iosram_mutex);
323503831d35Sstevel 		DPRINTF(1, ("IOSRAM(%d): iosram_sema_release: "
323603831d35Sstevel 		    "SBBC not mapped\n", softp->instance));
323703831d35Sstevel 		return (ENXIO);
323803831d35Sstevel 	}
323903831d35Sstevel 
324003831d35Sstevel 	/* Release semaphore by clearing our semaphore register */
324103831d35Sstevel 	IOSRAM_SEMA_WR(softp, 0);
324203831d35Sstevel 
324303831d35Sstevel 	mutex_exit(&softp->intr_mutex);
324403831d35Sstevel 	mutex_exit(&iosram_mutex);
324503831d35Sstevel 
324603831d35Sstevel 	DPRINTF(1, ("IOSRAM(%d): iosram_sema_release: success\n",
324703831d35Sstevel 	    softp->instance));
324803831d35Sstevel 
324903831d35Sstevel 	return (0);
325003831d35Sstevel }
325103831d35Sstevel 
325203831d35Sstevel 
325303831d35Sstevel #if defined(IOSRAM_LOG)
325403831d35Sstevel void
325503831d35Sstevel iosram_log(caddr_t fmt, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4)
325603831d35Sstevel {
325703831d35Sstevel 	uint32_t	seq;
325803831d35Sstevel 	iosram_log_t	*logp;
325903831d35Sstevel 
326003831d35Sstevel 	mutex_enter(&iosram_log_mutex);
326103831d35Sstevel 
326203831d35Sstevel 	seq = iosram_logseq++;
326303831d35Sstevel 	logp = &iosram_logbuf[seq % IOSRAM_MAXLOG];
326403831d35Sstevel 	logp->seq = seq;
3265d3d50737SRafael Vanoni 	logp->tstamp = ddi_get_lbolt();
326603831d35Sstevel 	logp->fmt = fmt;
326703831d35Sstevel 	logp->arg1 = a1;
326803831d35Sstevel 	logp->arg2 = a2;
326903831d35Sstevel 	logp->arg3 = a3;
327003831d35Sstevel 	logp->arg4 = a4;
327103831d35Sstevel 
327203831d35Sstevel 	mutex_exit(&iosram_log_mutex);
327303831d35Sstevel 
327403831d35Sstevel 	if (iosram_log_print) {
327503831d35Sstevel 		cmn_err(CE_CONT, "#%x @%lx ", logp->seq, logp->tstamp);
327603831d35Sstevel 		if (logp->fmt) {
327703831d35Sstevel 			cmn_err(CE_CONT, logp->fmt, logp->arg1, logp->arg2,
327803831d35Sstevel 			    logp->arg3, logp->arg4);
327903831d35Sstevel 			if (logp->fmt[strlen(logp->fmt)-1] != '\n') {
328003831d35Sstevel 				cmn_err(CE_CONT, "\n");
328103831d35Sstevel 			}
328203831d35Sstevel 		} else {
328303831d35Sstevel 			cmn_err(CE_CONT, "fmt:%p args: %lx %lx %lx %lx\n",
3284*07d06da5SSurya Prakki 			    (void *)logp->fmt, logp->arg1, logp->arg2,
3285*07d06da5SSurya Prakki 			    logp->arg3, logp->arg4);
328603831d35Sstevel 		}
328703831d35Sstevel 	}
328803831d35Sstevel }
328903831d35Sstevel #endif /* IOSRAM_LOG */
329003831d35Sstevel 
329103831d35Sstevel 
329203831d35Sstevel #if defined(DEBUG)
329303831d35Sstevel /*
329403831d35Sstevel  * iosram_get_keys(buf, len)
329503831d35Sstevel  *	Return IOSRAM TOC in the specified buffer
329603831d35Sstevel  */
329703831d35Sstevel static int
329803831d35Sstevel iosram_get_keys(iosram_toc_entry_t *bufp, uint32_t *len)
329903831d35Sstevel {
330003831d35Sstevel 	struct iosram_chunk	*chunkp;
330103831d35Sstevel 	int			error = 0;
330203831d35Sstevel 	int			i;
330303831d35Sstevel 	int			cnt = (*len) / sizeof (iosram_toc_entry_t);
330403831d35Sstevel 
330503831d35Sstevel 	IOSRAMLOG(2, "iosram_get_keys(bufp:%p *len:%x)\n", bufp, *len, NULL,
330603831d35Sstevel 	    NULL);
330703831d35Sstevel 
330803831d35Sstevel 	/*
330903831d35Sstevel 	 * Copy data while holding the lock to prevent any data
331003831d35Sstevel 	 * corruption or invalid pointer dereferencing.
331103831d35Sstevel 	 */
331203831d35Sstevel 	mutex_enter(&iosram_mutex);
331303831d35Sstevel 
331403831d35Sstevel 	if (iosram_master == NULL) {
331503831d35Sstevel 		error = EIO;
331603831d35Sstevel 	} else {
331703831d35Sstevel 		for (i = 0, chunkp = chunks; i < nchunks && i < cnt;
331803831d35Sstevel 		    i++, chunkp++) {
331903831d35Sstevel 			bufp[i].key = chunkp->toc_data.key;
332003831d35Sstevel 			bufp[i].off = chunkp->toc_data.off;
332103831d35Sstevel 			bufp[i].len = chunkp->toc_data.len;
332203831d35Sstevel 			bufp[i].unused = chunkp->toc_data.unused;
332303831d35Sstevel 		}
332403831d35Sstevel 		*len = i * sizeof (iosram_toc_entry_t);
332503831d35Sstevel 	}
332603831d35Sstevel 
332703831d35Sstevel 	mutex_exit(&iosram_mutex);
332803831d35Sstevel 	return (error);
332903831d35Sstevel }
333003831d35Sstevel 
333103831d35Sstevel 
333203831d35Sstevel /*
333303831d35Sstevel  * iosram_print_state(instance)
333403831d35Sstevel  */
333503831d35Sstevel static void
333603831d35Sstevel iosram_print_state(int instance)
333703831d35Sstevel {
333803831d35Sstevel 	struct iosramsoft	*softp;
333903831d35Sstevel 	char			pn[MAXNAMELEN];
334003831d35Sstevel 
334103831d35Sstevel 	if (instance < 0) {
334203831d35Sstevel 		softp = iosram_master;
334303831d35Sstevel 	} else {
334403831d35Sstevel 		softp = ddi_get_soft_state(iosramsoft_statep, instance);
334503831d35Sstevel 	}
334603831d35Sstevel 
334703831d35Sstevel 	if (softp == NULL) {
334803831d35Sstevel 		cmn_err(CE_CONT, "iosram_print_state: Can't find instance %d\n",
334903831d35Sstevel 		    instance);
335003831d35Sstevel 		return;
335103831d35Sstevel 	}
335203831d35Sstevel 	instance = softp->instance;
335303831d35Sstevel 
335403831d35Sstevel 	mutex_enter(&iosram_mutex);
335503831d35Sstevel 	mutex_enter(&softp->intr_mutex);
335603831d35Sstevel 
335703831d35Sstevel 	cmn_err(CE_CONT, "iosram_print_state(%d): ... %s\n", instance,
335803831d35Sstevel 	    ((softp == iosram_master) ? "MASTER" : "SLAVE"));
335903831d35Sstevel 
336003831d35Sstevel 	(void) ddi_pathname(softp->dip, pn);
336103831d35Sstevel 	cmn_err(CE_CONT, "  pathname:%s\n", pn);
336203831d35Sstevel 	cmn_err(CE_CONT, "  instance:%d  portid:%d iosramlen:0x%x\n",
336303831d35Sstevel 	    softp->instance, softp->portid, softp->iosramlen);
3364*07d06da5SSurya Prakki 	cmn_err(CE_CONT, "  softp:%p  handle:%p  iosramp:%p\n", (void *)softp,
3365*07d06da5SSurya Prakki 	    (void *)softp->handle, (void *)softp->iosramp);
336603831d35Sstevel 	cmn_err(CE_CONT, "  state:0x%x  tswitch_ok:%x  tswitch_fail:%x\n",
336703831d35Sstevel 	    softp->state, softp->tswitch_ok, softp->tswitch_fail);
336803831d35Sstevel 	cmn_err(CE_CONT, "  softintr_id:%p  intr_busy:%x  intr_pending:%x\n",
3369*07d06da5SSurya Prakki 	    (void *)softp->softintr_id, softp->intr_busy, softp->intr_pending);
337003831d35Sstevel 
337103831d35Sstevel 	mutex_exit(&softp->intr_mutex);
337203831d35Sstevel 	mutex_exit(&iosram_mutex);
337303831d35Sstevel }
337403831d35Sstevel 
337503831d35Sstevel 
337603831d35Sstevel /*
337703831d35Sstevel  * iosram_print_stats()
337803831d35Sstevel  */
337903831d35Sstevel static void
338003831d35Sstevel iosram_print_stats()
338103831d35Sstevel {
338203831d35Sstevel 	uint32_t	calls;
338303831d35Sstevel 
338403831d35Sstevel 	cmn_err(CE_CONT, "iosram_stats:\n");
338503831d35Sstevel 	calls = iosram_stats.read;
338603831d35Sstevel 	cmn_err(CE_CONT, " read  ... calls:%x  bytes:%lx  avg_sz:%x\n",
338703831d35Sstevel 	    calls, iosram_stats.bread,
338803831d35Sstevel 	    (uint32_t)((calls != 0) ? (iosram_stats.bread/calls) : 0));
338903831d35Sstevel 
339003831d35Sstevel 	calls = iosram_stats.write;
339103831d35Sstevel 	cmn_err(CE_CONT, " write ... calls:%x  bytes:%lx  avg_sz:%x\n",
339203831d35Sstevel 	    calls, iosram_stats.bwrite,
339303831d35Sstevel 	    (uint32_t)((calls != 0) ? (iosram_stats.bwrite/calls) : 0));
339403831d35Sstevel 
339503831d35Sstevel 	cmn_err(CE_CONT, " intr recv (real:%x  soft:%x)  sent:%x  cback:%x\n",
339603831d35Sstevel 	    iosram_stats.intr_recv, iosram_stats.sintr_recv,
339703831d35Sstevel 	    iosram_stats.intr_send, iosram_stats.callbacks);
339803831d35Sstevel 
339903831d35Sstevel 	cmn_err(CE_CONT, " tswitch: %x  getflag:%x  setflag:%x\n",
340003831d35Sstevel 	    iosram_stats.tswitch, iosram_stats.getflag,
340103831d35Sstevel 	    iosram_stats.setflag);
340203831d35Sstevel 
340303831d35Sstevel 	cmn_err(CE_CONT, " iosram_rw_active_max: %x\n", iosram_rw_active_max);
340403831d35Sstevel }
340503831d35Sstevel 
340603831d35Sstevel 
340703831d35Sstevel static void
340803831d35Sstevel iosram_print_cback()
340903831d35Sstevel {
341003831d35Sstevel 	iosram_chunk_t	*chunkp;
341103831d35Sstevel 	int		i;
341203831d35Sstevel 
341303831d35Sstevel 	/*
341403831d35Sstevel 	 * Print callback handlers
341503831d35Sstevel 	 */
341603831d35Sstevel 	mutex_enter(&iosram_mutex);
341703831d35Sstevel 
341803831d35Sstevel 	cmn_err(CE_CONT, "IOSRAM callbacks:\n");
341903831d35Sstevel 	for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
342003831d35Sstevel 		if (chunkp->cback.handler) {
342103831d35Sstevel 			cmn_err(CE_CONT, "  %2d: key:0x%x  hdlr:%p  arg:%p "
342203831d35Sstevel 			    "busy:%d unreg:%d\n", i, chunkp->toc_data.key,
3423*07d06da5SSurya Prakki 			    (void *)chunkp->cback.handler,
3424*07d06da5SSurya Prakki 			    (void *)chunkp->cback.arg,
342503831d35Sstevel 			    chunkp->cback.busy, chunkp->cback.unregister);
342603831d35Sstevel 		}
342703831d35Sstevel 	}
342803831d35Sstevel 	mutex_exit(&iosram_mutex);
342903831d35Sstevel }
343003831d35Sstevel 
343103831d35Sstevel 
343203831d35Sstevel static void
343303831d35Sstevel iosram_print_flags()
343403831d35Sstevel {
343503831d35Sstevel 	int		i;
343603831d35Sstevel 	uint32_t	*keys;
343703831d35Sstevel 	iosram_flags_t	*flags;
343803831d35Sstevel 
343903831d35Sstevel 	mutex_enter(&iosram_mutex);
344003831d35Sstevel 
344103831d35Sstevel 	if (iosram_master == NULL) {
344203831d35Sstevel 		mutex_exit(&iosram_mutex);
344303831d35Sstevel 		cmn_err(CE_CONT, "IOSRAM Flags: not accessible\n");
344403831d35Sstevel 		return;
344503831d35Sstevel 	}
344603831d35Sstevel 
344703831d35Sstevel 	keys = kmem_alloc(nchunks * sizeof (uint32_t), KM_SLEEP);
344803831d35Sstevel 	flags = kmem_alloc(nchunks * sizeof (iosram_flags_t), KM_SLEEP);
344903831d35Sstevel 
345003831d35Sstevel 	for (i = 0; i < nchunks; i++) {
345103831d35Sstevel 		keys[i] = chunks[i].toc_data.key;
345203831d35Sstevel 		ddi_rep_get8(iosram_handle, (uint8_t *)&(flags[i]),
345303831d35Sstevel 		    (uint8_t *)(chunks[i].flagsp), sizeof (iosram_flags_t),
345403831d35Sstevel 		    DDI_DEV_AUTOINCR);
345503831d35Sstevel 	}
345603831d35Sstevel 
345703831d35Sstevel 	mutex_exit(&iosram_mutex);
345803831d35Sstevel 
345903831d35Sstevel 	cmn_err(CE_CONT, "IOSRAM Flags:\n");
346003831d35Sstevel 	for (i = 0; i < nchunks; i++) {
346103831d35Sstevel 		cmn_err(CE_CONT,
346203831d35Sstevel 		    "  %2d: key: 0x%x  data_valid:%x  int_pending:%x\n",
346303831d35Sstevel 		    i, keys[i], flags[i].data_valid, flags[i].int_pending);
346403831d35Sstevel 	}
346503831d35Sstevel 
346603831d35Sstevel 	kmem_free(keys, nchunks * sizeof (uint32_t));
346703831d35Sstevel 	kmem_free(flags, nchunks * sizeof (iosram_flags_t));
346803831d35Sstevel }
346903831d35Sstevel 
347003831d35Sstevel 
347103831d35Sstevel /*PRINTFLIKE1*/
347203831d35Sstevel static void
347303831d35Sstevel iosram_dprintf(const char *fmt, ...)
347403831d35Sstevel {
347503831d35Sstevel 	char	msg_buf[256];
347603831d35Sstevel 	va_list	adx;
347703831d35Sstevel 
347803831d35Sstevel 	va_start(adx, fmt);
3479*07d06da5SSurya Prakki 	(void) vsprintf(msg_buf, fmt, adx);
348003831d35Sstevel 	va_end(adx);
348103831d35Sstevel 
348203831d35Sstevel 	cmn_err(CE_CONT, "%s", msg_buf);
348303831d35Sstevel }
348403831d35Sstevel #endif /* DEBUG */
348503831d35Sstevel 
348603831d35Sstevel 
348703831d35Sstevel #if IOSRAM_LOG
348803831d35Sstevel /*
348903831d35Sstevel  * iosram_print_log(int cnt)
349003831d35Sstevel  *	Print last few entries of the IOSRAM log in reverse order
349103831d35Sstevel  */
349203831d35Sstevel static void
349303831d35Sstevel iosram_print_log(int cnt)
349403831d35Sstevel {
349503831d35Sstevel 	int	i;
349603831d35Sstevel 
349703831d35Sstevel 	if (cnt <= 0) {
349803831d35Sstevel 		cnt = 20;
349903831d35Sstevel 	} else if (cnt > IOSRAM_MAXLOG) {
350003831d35Sstevel 		cnt = IOSRAM_MAXLOG;
350103831d35Sstevel 	}
350203831d35Sstevel 
350303831d35Sstevel 
350403831d35Sstevel 	cmn_err(CE_CONT,
350503831d35Sstevel 	    "\niosram_logseq: 0x%x  lbolt: %lx  iosram_log_level:%x\n",
3506d3d50737SRafael Vanoni 	    iosram_logseq, ddi_get_lbolt(), iosram_log_level);
350703831d35Sstevel 	cmn_err(CE_CONT, "iosram_logbuf: %p  max entries:0x%x\n",
3508*07d06da5SSurya Prakki 	    (void *)iosram_logbuf, IOSRAM_MAXLOG);
350903831d35Sstevel 	for (i = iosram_logseq;  --i >= 0 && --cnt >= 0; ) {
351003831d35Sstevel 		iosram_log_t	*logp;
351103831d35Sstevel 
351203831d35Sstevel 		mutex_enter(&iosram_log_mutex);
351303831d35Sstevel 
351403831d35Sstevel 		logp = &iosram_logbuf[i %IOSRAM_MAXLOG];
351503831d35Sstevel 		cmn_err(CE_CONT, "#%x @%lx ", logp->seq, logp->tstamp);
351603831d35Sstevel 
351703831d35Sstevel 		if (logp->fmt) {
351803831d35Sstevel 			cmn_err(CE_CONT, logp->fmt, logp->arg1, logp->arg2,
351903831d35Sstevel 			    logp->arg3, logp->arg4);
352003831d35Sstevel 			if (logp->fmt[strlen(logp->fmt)-1] != '\n') {
352103831d35Sstevel 				cmn_err(CE_CONT, "\n");
352203831d35Sstevel 			}
352303831d35Sstevel 		} else {
352403831d35Sstevel 			cmn_err(CE_CONT, "fmt:%p args: %lx %lx %lx %lx\n",
3525*07d06da5SSurya Prakki 			    (void *)logp->fmt, logp->arg1, logp->arg2,
352603831d35Sstevel 			    logp->arg3, logp->arg4);
352703831d35Sstevel 		}
352803831d35Sstevel 
352903831d35Sstevel 		mutex_exit(&iosram_log_mutex);
353003831d35Sstevel 	}
353103831d35Sstevel }
353203831d35Sstevel #endif	/* IOSRAM_LOG */
3533