11708Sstevel /*
21708Sstevel * CDDL HEADER START
31708Sstevel *
41708Sstevel * The contents of this file are subject to the terms of the
51708Sstevel * Common Development and Distribution License (the "License").
61708Sstevel * You may not use this file except in compliance with the License.
71708Sstevel *
81708Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel * or http://www.opensolaris.org/os/licensing.
101708Sstevel * See the License for the specific language governing permissions
111708Sstevel * and limitations under the License.
121708Sstevel *
131708Sstevel * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel *
191708Sstevel * CDDL HEADER END
201708Sstevel */
211708Sstevel
221708Sstevel /*
2311066Srafael.vanoni@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241708Sstevel * Use is subject to license terms.
251708Sstevel */
261708Sstevel
271708Sstevel /*
281708Sstevel * IOSRAM leaf driver to SBBC nexus driver. This driver is used
291708Sstevel * by Starcat Domain SW to read/write from/to the IO sram.
301708Sstevel */
311708Sstevel
321708Sstevel #include <sys/types.h>
331708Sstevel #include <sys/conf.h>
341708Sstevel #include <sys/ddi.h>
351708Sstevel #include <sys/sunddi.h>
361708Sstevel #include <sys/ddi_impldefs.h>
371708Sstevel #include <sys/obpdefs.h>
381708Sstevel #include <sys/promif.h>
391708Sstevel #include <sys/prom_plat.h>
401708Sstevel #include <sys/cmn_err.h>
411708Sstevel #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */
421708Sstevel #include <sys/modctl.h> /* for modldrv */
431708Sstevel #include <sys/stat.h> /* ddi_create_minor_node S_IFCHR */
441708Sstevel #include <sys/errno.h>
451708Sstevel #include <sys/kmem.h>
461708Sstevel #include <sys/kstat.h>
471708Sstevel #include <sys/debug.h>
481708Sstevel
491708Sstevel #include <sys/axq.h>
501708Sstevel #include <sys/iosramreg.h>
511708Sstevel #include <sys/iosramio.h>
521708Sstevel #include <sys/iosramvar.h>
531708Sstevel
541708Sstevel
551708Sstevel #if defined(DEBUG)
561708Sstevel int iosram_debug = 0;
571708Sstevel static void iosram_dprintf(const char *fmt, ...);
581708Sstevel #define DPRINTF(level, arg) \
591708Sstevel { if (iosram_debug >= level) iosram_dprintf arg; }
601708Sstevel #else /* !DEBUG */
611708Sstevel #define DPRINTF(level, arg)
621708Sstevel #endif /* !DEBUG */
631708Sstevel
641708Sstevel
651708Sstevel /*
661708Sstevel * IOSRAM module global state
671708Sstevel */
681708Sstevel static void *iosramsoft_statep; /* IOSRAM state pointer */
691708Sstevel static kmutex_t iosram_mutex; /* mutex lock */
701708Sstevel
711708Sstevel static iosram_chunk_t *chunks = NULL; /* array of TOC entries */
721708Sstevel static int nchunks = 0; /* # of TOC entries */
731708Sstevel static iosram_chunk_t *iosram_hashtab[IOSRAM_HASHSZ]; /* key hash table */
741708Sstevel
751708Sstevel static kcondvar_t iosram_tswitch_wait; /* tunnel switch wait cv */
761708Sstevel static int iosram_tswitch_wakeup = 0; /* flag indicationg one or */
771708Sstevel /* more threads waiting on */
781708Sstevel /* iosram_tswitch_wait cv */
791708Sstevel static int iosram_tswitch_active = 0; /* tunnel switch active flag */
801708Sstevel static int iosram_tswitch_aborted = 0; /* tunnel switch abort flag */
811708Sstevel static clock_t iosram_tswitch_tstamp = 0; /* lbolt of last tswitch end */
821708Sstevel static kcondvar_t iosram_rw_wait; /* read/write wait cv */
831708Sstevel static int iosram_rw_wakeup = 0; /* flag indicationg one or */
841708Sstevel /* more threads waiting on */
851708Sstevel /* iosram_rw_wait cv */
861708Sstevel static int iosram_rw_active = 0; /* # threads accessing IOSRAM */
871708Sstevel #if defined(DEBUG)
881708Sstevel static int iosram_rw_active_max = 0;
891708Sstevel #endif
901708Sstevel
911708Sstevel static struct iosramsoft *iosram_new_master = NULL; /* new tunnel target */
921708Sstevel static struct iosramsoft *iosram_master = NULL; /* master tunnel */
931708Sstevel static struct iosramsoft *iosram_instances = NULL; /* list of softstates */
941708Sstevel
951708Sstevel static ddi_acc_handle_t iosram_handle = NULL; /* master IOSRAM map handle */
961708Sstevel
971708Sstevel static void (*iosram_hdrchange_handler)() = NULL;
981708Sstevel
991708Sstevel #if IOSRAM_STATS
1001708Sstevel static struct iosram_stat iosram_stats; /* IOSRAM statistics */
1011708Sstevel static void iosram_print_stats(); /* forward declaration */
1021708Sstevel #endif /* IOSRAM_STATS */
1031708Sstevel
1041708Sstevel
1051708Sstevel #if IOSRAM_LOG
1061708Sstevel kmutex_t iosram_log_mutex;
1071708Sstevel int iosram_log_level = 1;
1081708Sstevel int iosram_log_print = 0; /* print log when recorded */
1091708Sstevel uint32_t iosram_logseq;
1101708Sstevel iosram_log_t iosram_logbuf[IOSRAM_MAXLOG];
1111708Sstevel static void iosram_print_log(int cnt); /* forward declaration */
1121708Sstevel #endif /* IOSRAM_LOG */
1131708Sstevel
1141708Sstevel
1151708Sstevel /* driver entry point fn definitions */
1161708Sstevel static int iosram_open(dev_t *, int, int, cred_t *);
1171708Sstevel static int iosram_close(dev_t, int, int, cred_t *);
1181708Sstevel static int iosram_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1191708Sstevel
1201708Sstevel /* configuration entry point fn definitions */
1211708Sstevel static int iosram_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
1221708Sstevel static int iosram_attach(dev_info_t *, ddi_attach_cmd_t);
1231708Sstevel static int iosram_detach(dev_info_t *, ddi_detach_cmd_t);
1241708Sstevel
1251708Sstevel
1261708Sstevel /* forward declaractions */
1271708Sstevel static iosram_chunk_t *iosram_find_chunk(uint32_t key);
1281708Sstevel static void iosram_set_master(struct iosramsoft *softp);
1291708Sstevel static int iosram_is_chosen(struct iosramsoft *softp);
1301708Sstevel static int iosram_tunnel_capable(struct iosramsoft *softp);
1311708Sstevel static int iosram_read_toc(struct iosramsoft *softp);
1321708Sstevel static void iosram_init_hashtab(void);
1331708Sstevel static void iosram_update_addrs(struct iosramsoft *softp);
1341708Sstevel
1351708Sstevel static int iosram_setup_map(struct iosramsoft *softp);
1361708Sstevel static void iosram_remove_map(struct iosramsoft *softp);
1371708Sstevel static int iosram_add_intr(iosramsoft_t *);
1381708Sstevel static int iosram_remove_intr(iosramsoft_t *);
1391708Sstevel
1401708Sstevel static void iosram_add_instance(struct iosramsoft *softp);
1411708Sstevel static void iosram_remove_instance(int instance);
1421708Sstevel static int iosram_switch_tunnel(iosramsoft_t *softp);
1431708Sstevel static void iosram_abort_tswitch();
1441708Sstevel
1451708Sstevel #if defined(DEBUG)
1461708Sstevel /* forward declaractions for debugging */
1471708Sstevel static int iosram_get_keys(iosram_toc_entry_t *buf, uint32_t *len);
1481708Sstevel static void iosram_print_cback();
1491708Sstevel static void iosram_print_state(int);
1501708Sstevel static void iosram_print_flags();
1511708Sstevel #endif
1521708Sstevel
1531708Sstevel
1541708Sstevel
1551708Sstevel /*
1561708Sstevel * cb_ops
1571708Sstevel */
1581708Sstevel static struct cb_ops iosram_cb_ops = {
1591708Sstevel iosram_open, /* cb_open */
1601708Sstevel iosram_close, /* cb_close */
1611708Sstevel nodev, /* cb_strategy */
1621708Sstevel nodev, /* cb_print */
1631708Sstevel nodev, /* cb_dump */
1641708Sstevel nodev, /* cb_read */
1651708Sstevel nodev, /* cb_write */
1661708Sstevel iosram_ioctl, /* cb_ioctl */
1671708Sstevel nodev, /* cb_devmap */
1681708Sstevel nodev, /* cb_mmap */
1691708Sstevel nodev, /* cb_segmap */
1701708Sstevel nochpoll, /* cb_chpoll */
1711708Sstevel ddi_prop_op, /* cb_prop_op */
1721708Sstevel NULL, /* cb_stream */
1731708Sstevel (int)(D_NEW | D_MP | D_HOTPLUG) /* cb_flag */
1741708Sstevel };
1751708Sstevel
1761708Sstevel /*
1771708Sstevel * Declare ops vectors for auto configuration.
1781708Sstevel */
1791708Sstevel struct dev_ops iosram_ops = {
1801708Sstevel DEVO_REV, /* devo_rev */
1811708Sstevel 0, /* devo_refcnt */
1821708Sstevel iosram_getinfo, /* devo_getinfo */
1831708Sstevel nulldev, /* devo_identify */
1841708Sstevel nulldev, /* devo_probe */
1851708Sstevel iosram_attach, /* devo_attach */
1861708Sstevel iosram_detach, /* devo_detach */
1871708Sstevel nodev, /* devo_reset */
1881708Sstevel &iosram_cb_ops, /* devo_cb_ops */
1891708Sstevel (struct bus_ops *)NULL, /* devo_bus_ops */
1907656SSherry.Moore@Sun.COM nulldev, /* devo_power */
1917656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */
1921708Sstevel };
1931708Sstevel
1941708Sstevel /*
1951708Sstevel * Loadable module support.
1961708Sstevel */
1971708Sstevel extern struct mod_ops mod_driverops;
1981708Sstevel
1991708Sstevel static struct modldrv iosrammodldrv = {
2001708Sstevel &mod_driverops, /* type of module - driver */
2017656SSherry.Moore@Sun.COM "IOSRAM Leaf driver",
2021708Sstevel &iosram_ops,
2031708Sstevel };
2041708Sstevel
2051708Sstevel static struct modlinkage iosrammodlinkage = {
2061708Sstevel MODREV_1,
2071708Sstevel &iosrammodldrv,
2081708Sstevel NULL
2091708Sstevel };
2101708Sstevel
2111708Sstevel
2121708Sstevel int
_init(void)2131708Sstevel _init(void)
2141708Sstevel {
2151708Sstevel int error;
2161708Sstevel int i;
2171708Sstevel
2181708Sstevel mutex_init(&iosram_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
2191708Sstevel cv_init(&iosram_tswitch_wait, NULL, CV_DRIVER, NULL);
2201708Sstevel cv_init(&iosram_rw_wait, NULL, CV_DRIVER, NULL);
2211708Sstevel #if defined(IOSRAM_LOG)
2221708Sstevel mutex_init(&iosram_log_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
2231708Sstevel #endif
2241708Sstevel
2251708Sstevel DPRINTF(1, ("_init:IOSRAM\n"));
2261708Sstevel
2271708Sstevel for (i = 0; i < IOSRAM_HASHSZ; i++) {
2281708Sstevel iosram_hashtab[i] = NULL;
2291708Sstevel }
2301708Sstevel
2311708Sstevel if ((error = ddi_soft_state_init(&iosramsoft_statep,
2321708Sstevel sizeof (struct iosramsoft), 1)) != 0) {
2331708Sstevel goto failed;
2341708Sstevel }
2351708Sstevel if ((error = mod_install(&iosrammodlinkage)) != 0) {
2361708Sstevel ddi_soft_state_fini(&iosramsoft_statep);
2371708Sstevel goto failed;
2381708Sstevel }
2391708Sstevel
2401708Sstevel IOSRAMLOG(0, "_init:IOSRAM ... error:%d statep:%p\n",
2411708Sstevel error, iosramsoft_statep, NULL, NULL);
2421708Sstevel
2431708Sstevel return (error);
2441708Sstevel
2451708Sstevel failed:
2461708Sstevel cv_destroy(&iosram_tswitch_wait);
2471708Sstevel cv_destroy(&iosram_rw_wait);
2481708Sstevel mutex_destroy(&iosram_mutex);
2491708Sstevel #if defined(IOSRAM_LOG)
2501708Sstevel mutex_destroy(&iosram_log_mutex);
2511708Sstevel #endif
2521708Sstevel IOSRAMLOG(0, "_init:IOSRAM ... error:%d statep:%p\n",
2531708Sstevel error, iosramsoft_statep, NULL, NULL);
2541708Sstevel
2551708Sstevel return (error);
2561708Sstevel }
2571708Sstevel
2581708Sstevel
2591708Sstevel int
_fini(void)2601708Sstevel _fini(void)
2611708Sstevel {
2621708Sstevel #ifndef DEBUG
2631708Sstevel return (EBUSY);
2641708Sstevel #else /* !DEBUG */
2651708Sstevel int error;
2661708Sstevel
2671708Sstevel if ((error = mod_remove(&iosrammodlinkage)) == 0) {
2681708Sstevel ddi_soft_state_fini(&iosramsoft_statep);
2691708Sstevel
2701708Sstevel cv_destroy(&iosram_tswitch_wait);
2711708Sstevel cv_destroy(&iosram_rw_wait);
2721708Sstevel mutex_destroy(&iosram_mutex);
2731708Sstevel #if defined(IOSRAM_LOG)
2741708Sstevel mutex_destroy(&iosram_log_mutex);
2751708Sstevel #endif
2761708Sstevel }
2771708Sstevel DPRINTF(1, ("_fini:IOSRAM error:%d\n", error));
2781708Sstevel
2791708Sstevel return (error);
2801708Sstevel #endif /* !DEBUG */
2811708Sstevel }
2821708Sstevel
2831708Sstevel
2841708Sstevel int
_info(struct modinfo * modinfop)2851708Sstevel _info(struct modinfo *modinfop)
2861708Sstevel {
2871708Sstevel return (mod_info(&iosrammodlinkage, modinfop));
2881708Sstevel }
2891708Sstevel
2901708Sstevel
2911708Sstevel static int
iosram_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2921708Sstevel iosram_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2931708Sstevel {
2941708Sstevel int instance;
2951708Sstevel int propval;
2961708Sstevel int length;
2971708Sstevel char name[32];
2981708Sstevel struct iosramsoft *softp;
2991708Sstevel
3001708Sstevel instance = ddi_get_instance(dip);
3011708Sstevel
302*11311SSurya.Prakki@Sun.COM DPRINTF(1, ("iosram(%d): attach dip:%p\n", instance, (void *)dip));
3031708Sstevel
3041708Sstevel IOSRAMLOG(1, "ATTACH: dip:%p instance %d ... start\n",
3051708Sstevel dip, instance, NULL, NULL);
3061708Sstevel switch (cmd) {
3071708Sstevel case DDI_ATTACH:
3081708Sstevel break;
3091708Sstevel case DDI_RESUME:
3101708Sstevel if (!(softp = ddi_get_soft_state(iosramsoft_statep,
3111708Sstevel instance))) {
3121708Sstevel return (DDI_FAILURE);
3131708Sstevel }
3141708Sstevel mutex_enter(&iosram_mutex);
3151708Sstevel mutex_enter(&softp->intr_mutex);
3161708Sstevel if (!softp->suspended) {
3171708Sstevel mutex_exit(&softp->intr_mutex);
3181708Sstevel mutex_exit(&iosram_mutex);
3191708Sstevel return (DDI_FAILURE);
3201708Sstevel }
3211708Sstevel softp->suspended = 0;
3221708Sstevel
3231708Sstevel /*
3241708Sstevel * enable SBBC interrupts if SBBC is mapped in
3251708Sstevel * restore the value saved during detach
3261708Sstevel */
3271708Sstevel if (softp->sbbc_region) {
3281708Sstevel ddi_put32(softp->sbbc_handle,
3291708Sstevel &(softp->sbbc_region->int_enable.reg),
3301708Sstevel softp->int_enable_sav);
3311708Sstevel }
3321708Sstevel
3331708Sstevel /*
3341708Sstevel * Trigger soft interrupt handler to process any pending
3351708Sstevel * interrupts.
3361708Sstevel */
3371708Sstevel if (softp->intr_pending && !softp->intr_busy &&
3381708Sstevel (softp->softintr_id != NULL)) {
3391708Sstevel ddi_trigger_softintr(softp->softintr_id);
3401708Sstevel }
3411708Sstevel
3421708Sstevel mutex_exit(&softp->intr_mutex);
3431708Sstevel mutex_exit(&iosram_mutex);
3441708Sstevel
3451708Sstevel return (DDI_SUCCESS);
3461708Sstevel
3471708Sstevel default:
3481708Sstevel return (DDI_FAILURE);
3491708Sstevel }
3501708Sstevel
3511708Sstevel if (ddi_soft_state_zalloc(iosramsoft_statep, instance) != 0) {
3521708Sstevel return (DDI_FAILURE);
3531708Sstevel }
3541708Sstevel
3551708Sstevel if ((softp = ddi_get_soft_state(iosramsoft_statep, instance)) == NULL) {
3567656SSherry.Moore@Sun.COM return (DDI_FAILURE);
3571708Sstevel }
3581708Sstevel softp->dip = dip;
3591708Sstevel softp->instance = instance;
3601708Sstevel softp->sbbc_region = NULL;
3611708Sstevel
3621708Sstevel /*
3631708Sstevel * If this instance is not tunnel capable, we don't attach it.
3641708Sstevel */
3651708Sstevel if (iosram_tunnel_capable(softp) == 0) {
3661708Sstevel DPRINTF(1, ("iosram(%d): not tunnel_capable\n", instance));
3671708Sstevel IOSRAMLOG(1, "ATTACH(%d): not tunnel_capable\n", instance, NULL,
3681708Sstevel NULL, NULL);
3691708Sstevel goto attach_fail;
3701708Sstevel }
3711708Sstevel
3721708Sstevel /*
3731708Sstevel * Need to create an "interrupt-priorities" property to define the PIL
3741708Sstevel * to be used with the interrupt service routine.
3751708Sstevel */
3761708Sstevel if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3771708Sstevel "interrupt-priorities", &length) == DDI_PROP_NOT_FOUND) {
3781708Sstevel DPRINTF(1, ("iosram(%d): creating interrupt priority property",
3791708Sstevel instance));
3801708Sstevel propval = IOSRAM_PIL;
3811708Sstevel if (ddi_prop_create(DDI_DEV_T_NONE, dip, 0,
3821708Sstevel "interrupt-priorities", (caddr_t)&propval, sizeof (propval))
3831708Sstevel != DDI_PROP_SUCCESS) {
3841708Sstevel cmn_err(CE_WARN,
3851708Sstevel "iosram_attach: failed to create property");
3861708Sstevel goto attach_fail;
3871708Sstevel }
3881708Sstevel }
3891708Sstevel
3901708Sstevel /*
3911708Sstevel * Get interrupts cookies and initialize per-instance mutexes
3921708Sstevel */
3931708Sstevel if (ddi_get_iblock_cookie(softp->dip, 0, &softp->real_iblk)
3941708Sstevel != DDI_SUCCESS) {
3951708Sstevel IOSRAMLOG(1, "ATTACH(%d): cannot get soft intr cookie\n",
3961708Sstevel instance, NULL, NULL, NULL);
3971708Sstevel goto attach_fail;
3981708Sstevel }
3991708Sstevel mutex_init(&softp->intr_mutex, NULL, MUTEX_DRIVER,
4001708Sstevel (void *)softp->real_iblk);
4011708Sstevel
4021708Sstevel /*
4031708Sstevel * Add this instance to the iosram_instances list so that it can be used
4041708Sstevel * for tunnel in future.
4051708Sstevel */
4061708Sstevel mutex_enter(&iosram_mutex);
4071708Sstevel softp->state = IOSRAM_STATE_INIT;
4081708Sstevel iosram_add_instance(softp);
4091708Sstevel
4101708Sstevel /*
4111708Sstevel * If this is the chosen IOSRAM and there is no master IOSRAM yet, then
4121708Sstevel * let's set this instance as the master.
4131708Sstevel */
4141708Sstevel if (iosram_master == NULL && iosram_is_chosen(softp)) {
415*11311SSurya.Prakki@Sun.COM (void) iosram_switch_tunnel(softp);
4161708Sstevel
4171708Sstevel /*
4181708Sstevel * XXX Do we need to panic if unable to setup master IOSRAM?
4191708Sstevel */
4201708Sstevel if (iosram_master == NULL) {
4211708Sstevel cmn_err(CE_WARN,
4221708Sstevel "iosram(%d): can't setup master tunnel\n",
4231708Sstevel instance);
4241708Sstevel softp->state = 0;
4251708Sstevel iosram_remove_instance(softp->instance);
4261708Sstevel mutex_exit(&iosram_mutex);
4271708Sstevel mutex_destroy(&softp->intr_mutex);
4281708Sstevel goto attach_fail;
4291708Sstevel }
4301708Sstevel }
4311708Sstevel
4321708Sstevel mutex_exit(&iosram_mutex);
4331708Sstevel
4341708Sstevel /*
4351708Sstevel * Create minor node
4361708Sstevel */
4371708Sstevel (void) sprintf(name, "iosram%d", instance);
4381708Sstevel if (ddi_create_minor_node(dip, name, S_IFCHR, instance, NULL, NULL) ==
4391708Sstevel DDI_FAILURE) {
4401708Sstevel /*
4411708Sstevel * Minor node seems to be needed only for debugging purposes.
4421708Sstevel * Therefore, there is no need to fail this attach request.
4431708Sstevel * Simply print a message out.
4441708Sstevel */
4451708Sstevel cmn_err(CE_NOTE, "!iosram(%d): can't create minor node\n",
4461708Sstevel instance);
4471708Sstevel }
4481708Sstevel ddi_report_dev(dip);
4491708Sstevel
4501708Sstevel DPRINTF(1, ("iosram_attach(%d): success.\n", instance));
4511708Sstevel IOSRAMLOG(1, "ATTACH: dip:%p instance:%d ... success softp:%p\n",
4521708Sstevel dip, instance, softp, NULL);
4531708Sstevel
4541708Sstevel return (DDI_SUCCESS);
4551708Sstevel
4561708Sstevel attach_fail:
4571708Sstevel DPRINTF(1, ("iosram_attach(%d):failed.\n", instance));
4581708Sstevel IOSRAMLOG(1, "ATTACH: dip:%p instance:%d ... failed.\n",
4591708Sstevel dip, instance, NULL, NULL);
4601708Sstevel
4611708Sstevel ddi_soft_state_free(iosramsoft_statep, instance);
4621708Sstevel return (DDI_FAILURE);
4631708Sstevel }
4641708Sstevel
4651708Sstevel
4661708Sstevel static int
iosram_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4671708Sstevel iosram_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4681708Sstevel {
4691708Sstevel int instance;
4701708Sstevel struct iosramsoft *softp;
4711708Sstevel
4721708Sstevel instance = ddi_get_instance(dip);
4731708Sstevel if (!(softp = ddi_get_soft_state(iosramsoft_statep, instance))) {
4741708Sstevel return (DDI_FAILURE);
4751708Sstevel }
4761708Sstevel
4771708Sstevel IOSRAMLOG(1, "DETACH: dip:%p instance %d softp:%p\n",
4781708Sstevel dip, instance, softp, NULL);
4791708Sstevel
4801708Sstevel switch (cmd) {
4811708Sstevel case DDI_DETACH:
4821708Sstevel break;
4831708Sstevel case DDI_SUSPEND:
4841708Sstevel mutex_enter(&iosram_mutex);
4851708Sstevel mutex_enter(&softp->intr_mutex);
4861708Sstevel if (softp->suspended) {
4871708Sstevel mutex_exit(&softp->intr_mutex);
4881708Sstevel mutex_exit(&iosram_mutex);
4891708Sstevel return (DDI_FAILURE);
4901708Sstevel }
4911708Sstevel softp->suspended = 1;
4921708Sstevel /*
4931708Sstevel * Disable SBBC interrupts if SBBC is mapped in
4941708Sstevel */
4951708Sstevel if (softp->sbbc_region) {
4961708Sstevel /* save current interrupt enable register */
4971708Sstevel softp->int_enable_sav = ddi_get32(softp->sbbc_handle,
4981708Sstevel &(softp->sbbc_region->int_enable.reg));
4991708Sstevel ddi_put32(softp->sbbc_handle,
5001708Sstevel &(softp->sbbc_region->int_enable.reg), 0x0);
5011708Sstevel }
5021708Sstevel mutex_exit(&softp->intr_mutex);
5031708Sstevel mutex_exit(&iosram_mutex);
5041708Sstevel return (DDI_SUCCESS);
5051708Sstevel
5061708Sstevel default:
5071708Sstevel return (DDI_FAILURE);
5081708Sstevel }
5091708Sstevel
5101708Sstevel
5111708Sstevel /*
5121708Sstevel * Indicate that this instance is being detached so that this instance
5131708Sstevel * does not become a target for tunnel switch in future.
5141708Sstevel */
5151708Sstevel mutex_enter(&iosram_mutex);
5161708Sstevel softp->state |= IOSRAM_STATE_DETACH;
5171708Sstevel
5181708Sstevel /*
5191708Sstevel * If this instance is currently the master or the target of the tunnel
5201708Sstevel * switch, then we need to wait and switch tunnel, if necessary.
5211708Sstevel */
5221708Sstevel if (iosram_master == softp || (softp->state & IOSRAM_STATE_TSWITCH)) {
5231708Sstevel mutex_exit(&iosram_mutex);
524*11311SSurya.Prakki@Sun.COM (void) iosram_switchfrom(instance);
5251708Sstevel mutex_enter(&iosram_mutex);
5261708Sstevel }
5271708Sstevel
5281708Sstevel /*
5291708Sstevel * If the tunnel switch is in progress and we are the master or target
5301708Sstevel * of tunnel relocation, then we can't detach this instance right now.
5311708Sstevel */
5321708Sstevel if (softp->state & IOSRAM_STATE_TSWITCH) {
5331708Sstevel softp->state &= ~IOSRAM_STATE_DETACH;
5341708Sstevel mutex_exit(&iosram_mutex);
5351708Sstevel return (DDI_FAILURE);
5361708Sstevel }
5371708Sstevel
5381708Sstevel /*
5391708Sstevel * We can't allow master IOSRAM to be detached as we won't be able to
5401708Sstevel * communicate otherwise.
5411708Sstevel */
5421708Sstevel if (iosram_master == softp) {
5431708Sstevel softp->state &= ~IOSRAM_STATE_DETACH;
5441708Sstevel mutex_exit(&iosram_mutex);
5451708Sstevel return (DDI_FAILURE);
5461708Sstevel }
5471708Sstevel
5481708Sstevel /*
5491708Sstevel * Now remove our instance from the iosram_instances list.
5501708Sstevel */
5511708Sstevel iosram_remove_instance(instance);
5521708Sstevel mutex_exit(&iosram_mutex);
5531708Sstevel
5541708Sstevel /*
5551708Sstevel * Instances should only ever be mapped if they are the master and/or
5561708Sstevel * participating in a tunnel switch. Neither should be the case here.
5571708Sstevel */
5581708Sstevel ASSERT((softp->state & IOSRAM_STATE_MAPPED) == 0);
5591708Sstevel
5601708Sstevel /*
5611708Sstevel * Destroy per-instance mutexes
5621708Sstevel */
5631708Sstevel mutex_destroy(&softp->intr_mutex);
5641708Sstevel
5651708Sstevel ddi_remove_minor_node(dip, NULL);
5661708Sstevel
5671708Sstevel /*
5681708Sstevel * Finally remove our soft state structure
5691708Sstevel */
5701708Sstevel ddi_soft_state_free(iosramsoft_statep, instance);
5711708Sstevel
5721708Sstevel return (DDI_SUCCESS);
5731708Sstevel }
5741708Sstevel
5751708Sstevel
5761708Sstevel /* ARGSUSED0 */
5771708Sstevel static int
iosram_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)5781708Sstevel iosram_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
5791708Sstevel void **result)
5801708Sstevel {
5811708Sstevel dev_t dev = (dev_t)arg;
5821708Sstevel struct iosramsoft *softp;
5831708Sstevel int instance, ret;
5841708Sstevel
5851708Sstevel instance = getminor(dev);
5861708Sstevel
5871708Sstevel IOSRAMLOG(2, "GETINFO: dip:%x instance %d dev:%x infocmd:%x\n",
5881708Sstevel dip, instance, dev, infocmd);
5891708Sstevel
5901708Sstevel switch (infocmd) {
5911708Sstevel case DDI_INFO_DEVT2DEVINFO:
5921708Sstevel softp = ddi_get_soft_state(iosramsoft_statep, instance);
5931708Sstevel if (softp == NULL) {
5941708Sstevel *result = NULL;
5951708Sstevel ret = DDI_FAILURE;
5961708Sstevel } else {
5971708Sstevel *result = softp->dip;
5981708Sstevel ret = DDI_SUCCESS;
5991708Sstevel }
6001708Sstevel break;
6011708Sstevel case DDI_INFO_DEVT2INSTANCE:
6021708Sstevel *result = (void *)(uintptr_t)instance;
6031708Sstevel ret = DDI_SUCCESS;
6041708Sstevel break;
6051708Sstevel default:
6061708Sstevel ret = DDI_FAILURE;
6071708Sstevel break;
6081708Sstevel }
6091708Sstevel
6101708Sstevel return (ret);
6111708Sstevel }
6121708Sstevel
6131708Sstevel
6141708Sstevel /*ARGSUSED1*/
6151708Sstevel static int
iosram_open(dev_t * dev,int flag,int otype,cred_t * credp)6161708Sstevel iosram_open(dev_t *dev, int flag, int otype, cred_t *credp)
6171708Sstevel {
6181708Sstevel struct iosramsoft *softp;
6191708Sstevel int instance;
6201708Sstevel
6211708Sstevel instance = getminor(*dev);
6221708Sstevel softp = ddi_get_soft_state(iosramsoft_statep, instance);
6231708Sstevel
6241708Sstevel if (softp == NULL) {
6251708Sstevel return (ENXIO);
6261708Sstevel }
6271708Sstevel
6281708Sstevel IOSRAMLOG(1, "OPEN: dev:%p otype:%x ... instance:%d softp:%p\n",
6291708Sstevel *dev, otype, softp->instance, softp);
6301708Sstevel
6311708Sstevel return (0);
6321708Sstevel }
6331708Sstevel
6341708Sstevel
6351708Sstevel /*ARGSUSED1*/
6361708Sstevel static int
iosram_close(dev_t dev,int flag,int otype,cred_t * credp)6371708Sstevel iosram_close(dev_t dev, int flag, int otype, cred_t *credp)
6381708Sstevel {
6391708Sstevel struct iosramsoft *softp;
6401708Sstevel int instance;
6411708Sstevel
6421708Sstevel instance = getminor(dev);
6431708Sstevel softp = ddi_get_soft_state(iosramsoft_statep, instance);
6441708Sstevel if (softp == NULL) {
6451708Sstevel return (ENXIO);
6461708Sstevel }
6471708Sstevel
6481708Sstevel IOSRAMLOG(1, "CLOSE: dev:%p otype:%x ... instance:%d softp:%p\n",
6491708Sstevel dev, otype, softp->instance, softp);
6501708Sstevel
6511708Sstevel return (0);
6521708Sstevel }
6531708Sstevel
6541708Sstevel
6551708Sstevel int
iosram_rd(uint32_t key,uint32_t off,uint32_t len,caddr_t dptr)6561708Sstevel iosram_rd(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr)
6571708Sstevel {
6581708Sstevel iosram_chunk_t *chunkp;
6591708Sstevel uint32_t chunk_len;
6601708Sstevel uint8_t *iosramp;
6611708Sstevel ddi_acc_handle_t handle;
6621708Sstevel int boff;
6631708Sstevel union {
6641708Sstevel uchar_t cbuf[UINT32SZ];
6651708Sstevel uint32_t data;
6661708Sstevel } word;
6671708Sstevel
6681708Sstevel int error = 0;
6691708Sstevel uint8_t *buf = (uint8_t *)dptr;
6701708Sstevel
6711708Sstevel /*
6721708Sstevel * We try to read from the IOSRAM using double word or word access
6731708Sstevel * provided both "off" and "buf" are (or can be) double word or word
6741708Sstevel * aligned. Othewise, we try to align the "off" to a word boundary and
6751708Sstevel * then try to read data from the IOSRAM using word access, but store it
6761708Sstevel * into buf buffer using byte access.
6771708Sstevel *
6781708Sstevel * If the leading/trailing portion of the IOSRAM data is not word
6791708Sstevel * aligned, it will always be copied using byte access.
6801708Sstevel */
6811708Sstevel IOSRAMLOG(1, "RD: key: 0x%x off:%x len:%x buf:%p\n",
6821708Sstevel key, off, len, buf);
6831708Sstevel
6841708Sstevel /*
6851708Sstevel * Acquire lock and look for the requested chunk. If it exists, make
6861708Sstevel * sure the requested read is within the chunk's bounds and no tunnel
6871708Sstevel * switch is active.
6881708Sstevel */
6891708Sstevel mutex_enter(&iosram_mutex);
6901708Sstevel chunkp = iosram_find_chunk(key);
6911708Sstevel chunk_len = (chunkp != NULL) ? chunkp->toc_data.len : 0;
6921708Sstevel
6931708Sstevel if (iosram_master == NULL) {
6941708Sstevel error = EIO;
6951708Sstevel } else if (chunkp == NULL) {
6961708Sstevel error = EINVAL;
6971708Sstevel } else if ((off >= chunk_len) || (len > chunk_len) ||
6981708Sstevel ((off + len) > chunk_len)) {
6991708Sstevel error = EMSGSIZE;
7001708Sstevel } else if (iosram_tswitch_active) {
7011708Sstevel error = EAGAIN;
7021708Sstevel }
7031708Sstevel
7041708Sstevel if (error) {
7051708Sstevel mutex_exit(&iosram_mutex);
7061708Sstevel return (error);
7071708Sstevel }
7081708Sstevel
7091708Sstevel /*
7101708Sstevel * Bump reference count to indicate #thread accessing IOSRAM and release
7111708Sstevel * the lock.
7121708Sstevel */
7131708Sstevel iosram_rw_active++;
7141708Sstevel #if defined(DEBUG)
7151708Sstevel if (iosram_rw_active > iosram_rw_active_max) {
7161708Sstevel iosram_rw_active_max = iosram_rw_active;
7171708Sstevel }
7181708Sstevel #endif
7191708Sstevel mutex_exit(&iosram_mutex);
7201708Sstevel
7211708Sstevel IOSRAM_STAT(read);
7221708Sstevel IOSRAM_STAT_ADD(bread, len);
7231708Sstevel
7241708Sstevel /* Get starting address and map handle */
7251708Sstevel iosramp = chunkp->basep + off;
7261708Sstevel handle = iosram_handle;
7271708Sstevel
7281708Sstevel /*
7291708Sstevel * Align the off to word boundary and then try reading/writing data
7301708Sstevel * using double word or word access.
7311708Sstevel */
7321708Sstevel if ((boff = ((uintptr_t)iosramp & (UINT32SZ - 1))) != 0) {
7331708Sstevel int cnt = UINT32SZ - boff;
7341708Sstevel
7351708Sstevel if (cnt > len) {
7361708Sstevel cnt = len;
7371708Sstevel }
7381708Sstevel IOSRAMLOG(2,
7391708Sstevel "RD: align rep_get8(buf:%p sramp:%p cnt:%x) len:%x\n",
7401708Sstevel buf, iosramp, cnt, len);
7411708Sstevel ddi_rep_get8(handle, buf, iosramp, cnt, DDI_DEV_AUTOINCR);
7421708Sstevel buf += cnt;
7431708Sstevel iosramp += cnt;
7441708Sstevel len -= cnt;
7451708Sstevel }
7461708Sstevel
7471708Sstevel if ((len >= UINT64SZ) &&
7481708Sstevel ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT64SZ - 1)) == 0)) {
7491708Sstevel /*
7501708Sstevel * Both source and destination are double word aligned
7511708Sstevel */
7521708Sstevel int cnt = len/UINT64SZ;
7531708Sstevel
7541708Sstevel IOSRAMLOG(2,
7551708Sstevel "RD: rep_get64(buf:%p sramp:%p cnt:%x) len:%x\n",
7561708Sstevel buf, iosramp, cnt, len);
7571708Sstevel ddi_rep_get64(handle, (uint64_t *)buf, (uint64_t *)iosramp,
7581708Sstevel cnt, DDI_DEV_AUTOINCR);
7591708Sstevel iosramp += cnt * UINT64SZ;
7601708Sstevel buf += cnt * UINT64SZ;
7611708Sstevel len -= cnt * UINT64SZ;
7621708Sstevel
7631708Sstevel /*
7641708Sstevel * read remaining data using word and byte access
7651708Sstevel */
7661708Sstevel if (len >= UINT32SZ) {
7671708Sstevel IOSRAMLOG(2,
7681708Sstevel "RD: get32(buf:%p sramp:%p) len:%x\n",
7691708Sstevel buf, iosramp, len, NULL);
7701708Sstevel *(uint32_t *)buf = ddi_get32(handle,
7711708Sstevel (uint32_t *)iosramp);
7721708Sstevel iosramp += UINT32SZ;
7731708Sstevel buf += UINT32SZ;
7741708Sstevel len -= UINT32SZ;
7751708Sstevel }
7761708Sstevel
7771708Sstevel if (len != 0) {
7787656SSherry.Moore@Sun.COM ddi_rep_get8(handle, buf, iosramp, len,
7797656SSherry.Moore@Sun.COM DDI_DEV_AUTOINCR);
7801708Sstevel }
7811708Sstevel } else if ((len >= UINT32SZ) &&
7821708Sstevel ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT32SZ - 1)) == 0)) {
7831708Sstevel /*
7841708Sstevel * Both source and destination are word aligned
7851708Sstevel */
7861708Sstevel int cnt = len/UINT32SZ;
7871708Sstevel
7881708Sstevel IOSRAMLOG(2,
7891708Sstevel "RD: rep_get32(buf:%p sramp:%p cnt:%x) len:%x\n",
7901708Sstevel buf, iosramp, cnt, len);
7911708Sstevel ddi_rep_get32(handle, (uint32_t *)buf, (uint32_t *)iosramp,
7921708Sstevel cnt, DDI_DEV_AUTOINCR);
7931708Sstevel iosramp += cnt * UINT32SZ;
7941708Sstevel buf += cnt * UINT32SZ;
7951708Sstevel len -= cnt * UINT32SZ;
7961708Sstevel
7971708Sstevel /*
7981708Sstevel * copy the remainder using byte access
7991708Sstevel */
8001708Sstevel if (len != 0) {
8017656SSherry.Moore@Sun.COM ddi_rep_get8(handle, buf, iosramp, len,
8027656SSherry.Moore@Sun.COM DDI_DEV_AUTOINCR);
8031708Sstevel }
8041708Sstevel } else if (len != 0) {
8051708Sstevel /*
8061708Sstevel * We know that the "off" (i.e. iosramp) is at least word
8071708Sstevel * aligned. We need to read IOSRAM word at a time and copy it
8081708Sstevel * byte at a time.
8091708Sstevel */
8101708Sstevel ASSERT(((uintptr_t)iosramp & (UINT32SZ - 1)) == 0);
8111708Sstevel
8121708Sstevel IOSRAMLOG(2,
8131708Sstevel "RD: unaligned get32(buf:%p sramp:%p) len:%x\n",
8141708Sstevel buf, iosramp, len, NULL);
8151708Sstevel for (; len >= UINT32SZ; len -= UINT32SZ, iosramp += UINT32SZ) {
8161708Sstevel word.data = ddi_get32(handle, (uint32_t *)iosramp);
8171708Sstevel *buf++ = word.cbuf[0];
8181708Sstevel *buf++ = word.cbuf[1];
8191708Sstevel *buf++ = word.cbuf[2];
8201708Sstevel *buf++ = word.cbuf[3];
8211708Sstevel }
8221708Sstevel
8231708Sstevel /*
8241708Sstevel * copy the remaining data using byte access
8251708Sstevel */
8261708Sstevel if (len != 0) {
8271708Sstevel ddi_rep_get8(handle, buf, iosramp, len,
8281708Sstevel DDI_DEV_AUTOINCR);
8291708Sstevel }
8301708Sstevel }
8311708Sstevel
8321708Sstevel /*
8331708Sstevel * Reacquire mutex lock, decrement refcnt and if refcnt is 0 and any
8341708Sstevel * threads are waiting for r/w activity to complete, wake them up.
8351708Sstevel */
8361708Sstevel mutex_enter(&iosram_mutex);
8371708Sstevel ASSERT(iosram_rw_active > 0);
8381708Sstevel
8391708Sstevel if ((--iosram_rw_active == 0) && iosram_rw_wakeup) {
8401708Sstevel iosram_rw_wakeup = 0;
8411708Sstevel cv_broadcast(&iosram_rw_wait);
8421708Sstevel }
8431708Sstevel mutex_exit(&iosram_mutex);
8441708Sstevel
8451708Sstevel return (error);
8461708Sstevel }
8471708Sstevel
8481708Sstevel
8491708Sstevel /*
8501708Sstevel * _iosram_write(key, off, len, dptr, force)
8511708Sstevel * Internal common routine to write to the IOSRAM.
8521708Sstevel */
8531708Sstevel static int
_iosram_write(uint32_t key,uint32_t off,uint32_t len,caddr_t dptr,int force)8541708Sstevel _iosram_write(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr, int force)
8551708Sstevel {
8561708Sstevel iosram_chunk_t *chunkp;
8571708Sstevel uint32_t chunk_len;
8581708Sstevel uint8_t *iosramp;
8591708Sstevel ddi_acc_handle_t handle;
8601708Sstevel int boff;
8611708Sstevel union {
8621708Sstevel uint8_t cbuf[UINT32SZ];
8631708Sstevel uint32_t data;
8641708Sstevel } word;
8651708Sstevel
8661708Sstevel int error = 0;
8671708Sstevel uint8_t *buf = (uint8_t *)dptr;
8681708Sstevel
8691708Sstevel /*
8701708Sstevel * We try to write to the IOSRAM using double word or word access
8711708Sstevel * provided both "off" and "buf" are (or can be) double word or word
8721708Sstevel * aligned. Othewise, we try to align the "off" to a word boundary and
8731708Sstevel * then try to write data to the IOSRAM using word access, but read data
8741708Sstevel * from the buf buffer using byte access.
8751708Sstevel *
8761708Sstevel * If the leading/trailing portion of the IOSRAM data is not word
8771708Sstevel * aligned, it will always be written using byte access.
8781708Sstevel */
8791708Sstevel IOSRAMLOG(1, "WR: key: 0x%x off:%x len:%x buf:%p\n",
8801708Sstevel key, off, len, buf);
8811708Sstevel
8821708Sstevel /*
8831708Sstevel * Acquire lock and look for the requested chunk. If it exists, make
8841708Sstevel * sure the requested write is within the chunk's bounds and no tunnel
8851708Sstevel * switch is active.
8861708Sstevel */
8871708Sstevel mutex_enter(&iosram_mutex);
8881708Sstevel chunkp = iosram_find_chunk(key);
8891708Sstevel chunk_len = (chunkp != NULL) ? chunkp->toc_data.len : 0;
8901708Sstevel
8911708Sstevel if (iosram_master == NULL) {
8921708Sstevel error = EIO;
8931708Sstevel } else if (chunkp == NULL) {
8941708Sstevel error = EINVAL;
8951708Sstevel } else if ((off >= chunk_len) || (len > chunk_len) ||
8961708Sstevel ((off+len) > chunk_len)) {
8971708Sstevel error = EMSGSIZE;
8981708Sstevel } else if (iosram_tswitch_active && !force) {
8991708Sstevel error = EAGAIN;
9001708Sstevel }
9011708Sstevel
9021708Sstevel if (error) {
9031708Sstevel mutex_exit(&iosram_mutex);
9041708Sstevel return (error);
9051708Sstevel }
9061708Sstevel
9071708Sstevel /*
9081708Sstevel * If this is a forced write and there's a tunnel switch in progress,
9091708Sstevel * abort the switch.
9101708Sstevel */
9111708Sstevel if (iosram_tswitch_active && force) {
9121708Sstevel cmn_err(CE_NOTE, "!iosram: Aborting tswitch on force_write");
9131708Sstevel iosram_abort_tswitch();
9141708Sstevel }
9151708Sstevel
9161708Sstevel /*
9171708Sstevel * Bump reference count to indicate #thread accessing IOSRAM
9181708Sstevel * and release the lock.
9191708Sstevel */
9201708Sstevel iosram_rw_active++;
9211708Sstevel #if defined(DEBUG)
9221708Sstevel if (iosram_rw_active > iosram_rw_active_max) {
9231708Sstevel iosram_rw_active_max = iosram_rw_active;
9241708Sstevel }
9251708Sstevel #endif
9261708Sstevel mutex_exit(&iosram_mutex);
9271708Sstevel
9281708Sstevel
9291708Sstevel IOSRAM_STAT(write);
9301708Sstevel IOSRAM_STAT_ADD(bwrite, len);
9311708Sstevel
9321708Sstevel /* Get starting address and map handle */
9331708Sstevel iosramp = chunkp->basep + off;
9341708Sstevel handle = iosram_handle;
9351708Sstevel
9361708Sstevel /*
9371708Sstevel * Align the off to word boundary and then try reading/writing
9381708Sstevel * data using double word or word access.
9391708Sstevel */
9401708Sstevel if ((boff = ((uintptr_t)iosramp & (UINT32SZ - 1))) != 0) {
9411708Sstevel int cnt = UINT32SZ - boff;
9421708Sstevel
9431708Sstevel if (cnt > len) {
9441708Sstevel cnt = len;
9451708Sstevel }
9461708Sstevel IOSRAMLOG(2,
9471708Sstevel "WR: align rep_put8(buf:%p sramp:%p cnt:%x) len:%x\n",
9481708Sstevel buf, iosramp, cnt, len);
9491708Sstevel ddi_rep_put8(handle, buf, iosramp, cnt, DDI_DEV_AUTOINCR);
9501708Sstevel buf += cnt;
9511708Sstevel iosramp += cnt;
9521708Sstevel len -= cnt;
9531708Sstevel }
9541708Sstevel
9551708Sstevel if ((len >= UINT64SZ) &&
9561708Sstevel ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT64SZ - 1)) == 0)) {
9571708Sstevel /*
9581708Sstevel * Both source and destination are double word aligned
9591708Sstevel */
9601708Sstevel int cnt = len/UINT64SZ;
9611708Sstevel
9621708Sstevel IOSRAMLOG(2,
9631708Sstevel "WR: rep_put64(buf:%p sramp:%p cnt:%x) len:%x\n",
9641708Sstevel buf, iosramp, cnt, len);
9651708Sstevel ddi_rep_put64(handle, (uint64_t *)buf, (uint64_t *)iosramp,
9661708Sstevel cnt, DDI_DEV_AUTOINCR);
9671708Sstevel iosramp += cnt * UINT64SZ;
9681708Sstevel buf += cnt * UINT64SZ;
9691708Sstevel len -= cnt * UINT64SZ;
9701708Sstevel
9711708Sstevel /*
9721708Sstevel * Copy the remaining data using word & byte access
9731708Sstevel */
9741708Sstevel if (len >= UINT32SZ) {
9751708Sstevel IOSRAMLOG(2,
9761708Sstevel "WR: put32(buf:%p sramp:%p) len:%x\n", buf, iosramp,
9771708Sstevel len, NULL);
9781708Sstevel ddi_put32(handle, (uint32_t *)iosramp,
9791708Sstevel *(uint32_t *)buf);
9801708Sstevel iosramp += UINT32SZ;
9811708Sstevel buf += UINT32SZ;
9821708Sstevel len -= UINT32SZ;
9831708Sstevel }
9841708Sstevel
9851708Sstevel if (len != 0) {
9861708Sstevel ddi_rep_put8(handle, buf, iosramp, len,
9871708Sstevel DDI_DEV_AUTOINCR);
9881708Sstevel }
9891708Sstevel } else if ((len >= UINT32SZ) &&
9901708Sstevel ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT32SZ - 1)) == 0)) {
9911708Sstevel /*
9921708Sstevel * Both source and destination are word aligned
9931708Sstevel */
9941708Sstevel int cnt = len/UINT32SZ;
9951708Sstevel
9961708Sstevel IOSRAMLOG(2,
9971708Sstevel "WR: rep_put32(buf:%p sramp:%p cnt:%x) len:%x\n",
9981708Sstevel buf, iosramp, cnt, len);
9991708Sstevel ddi_rep_put32(handle, (uint32_t *)buf, (uint32_t *)iosramp,
10001708Sstevel cnt, DDI_DEV_AUTOINCR);
10011708Sstevel iosramp += cnt * UINT32SZ;
10021708Sstevel buf += cnt * UINT32SZ;
10031708Sstevel len -= cnt * UINT32SZ;
10041708Sstevel
10051708Sstevel /*
10061708Sstevel * copy the remainder using byte access
10071708Sstevel */
10081708Sstevel if (len != 0) {
10091708Sstevel ddi_rep_put8(handle, buf, iosramp, len,
10101708Sstevel DDI_DEV_AUTOINCR);
10111708Sstevel }
10121708Sstevel } else if (len != 0) {
10131708Sstevel /*
10141708Sstevel * We know that the "off" is at least word aligned. We
10151708Sstevel * need to read data from buf buffer byte at a time, and
10161708Sstevel * write it to the IOSRAM word at a time.
10171708Sstevel */
10181708Sstevel
10191708Sstevel ASSERT(((uintptr_t)iosramp & (UINT32SZ - 1)) == 0);
10201708Sstevel
10211708Sstevel IOSRAMLOG(2,
10221708Sstevel "WR: unaligned put32(buf:%p sramp:%p) len:%x\n",
10231708Sstevel buf, iosramp, len, NULL);
10241708Sstevel for (; len >= UINT32SZ; len -= UINT32SZ, iosramp += UINT32SZ) {
10251708Sstevel word.cbuf[0] = *buf++;
10261708Sstevel word.cbuf[1] = *buf++;
10271708Sstevel word.cbuf[2] = *buf++;
10281708Sstevel word.cbuf[3] = *buf++;
10291708Sstevel ddi_put32(handle, (uint32_t *)iosramp, word.data);
10301708Sstevel }
10311708Sstevel
10321708Sstevel /*
10331708Sstevel * copy the remaining data using byte access
10341708Sstevel */
10351708Sstevel if (len != 0) {
10361708Sstevel ddi_rep_put8(handle, buf, iosramp,
10371708Sstevel len, DDI_DEV_AUTOINCR);
10381708Sstevel }
10391708Sstevel }
10401708Sstevel
10411708Sstevel /*
10421708Sstevel * Reacquire mutex lock, decrement refcnt and if refcnt is 0 and
10431708Sstevel * any threads are waiting for r/w activity to complete, wake them up.
10441708Sstevel */
10451708Sstevel mutex_enter(&iosram_mutex);
10461708Sstevel ASSERT(iosram_rw_active > 0);
10471708Sstevel
10481708Sstevel if ((--iosram_rw_active == 0) && iosram_rw_wakeup) {
10491708Sstevel iosram_rw_wakeup = 0;
10501708Sstevel cv_broadcast(&iosram_rw_wait);
10511708Sstevel }
10521708Sstevel mutex_exit(&iosram_mutex);
10531708Sstevel
10541708Sstevel return (error);
10551708Sstevel }
10561708Sstevel
10571708Sstevel
10581708Sstevel int
iosram_force_write(uint32_t key,uint32_t off,uint32_t len,caddr_t dptr)10591708Sstevel iosram_force_write(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr)
10601708Sstevel {
10611708Sstevel return (_iosram_write(key, off, len, dptr, 1 /* force */));
10621708Sstevel }
10631708Sstevel
10641708Sstevel
10651708Sstevel int
iosram_wr(uint32_t key,uint32_t off,uint32_t len,caddr_t dptr)10661708Sstevel iosram_wr(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr)
10671708Sstevel {
10681708Sstevel return (_iosram_write(key, off, len, dptr, 0));
10691708Sstevel }
10701708Sstevel
10711708Sstevel
10721708Sstevel /*
10731708Sstevel * iosram_register(key, handler, arg)
10741708Sstevel * Register a handler and an arg for the specified chunk. This handler
10751708Sstevel * will be invoked when an interrupt is received from the other side and
10761708Sstevel * the int_pending flag for the corresponding key is marked
10771708Sstevel * IOSRAM_INT_TO_DOM.
10781708Sstevel */
10791708Sstevel /* ARGSUSED */
10801708Sstevel int
iosram_register(uint32_t key,void (* handler)(),void * arg)10811708Sstevel iosram_register(uint32_t key, void (*handler)(), void *arg)
10821708Sstevel {
10831708Sstevel struct iosram_chunk *chunkp;
10841708Sstevel int error = 0;
10851708Sstevel
10861708Sstevel /*
10871708Sstevel * Acquire lock and look for the requested chunk. If it exists, and no
10881708Sstevel * other callback is registered, proceed with the registration.
10891708Sstevel */
10901708Sstevel mutex_enter(&iosram_mutex);
10911708Sstevel chunkp = iosram_find_chunk(key);
10921708Sstevel
10931708Sstevel if (iosram_master == NULL) {
10941708Sstevel error = EIO;
10951708Sstevel } else if (chunkp == NULL) {
10961708Sstevel error = EINVAL;
10971708Sstevel } else if (chunkp->cback.handler != NULL) {
10981708Sstevel error = EBUSY;
10991708Sstevel } else {
11001708Sstevel chunkp->cback.busy = 0;
11011708Sstevel chunkp->cback.unregister = 0;
11021708Sstevel chunkp->cback.handler = handler;
11031708Sstevel chunkp->cback.arg = arg;
11041708Sstevel }
11051708Sstevel mutex_exit(&iosram_mutex);
11061708Sstevel
11071708Sstevel IOSRAMLOG(1, "REG: key: 0x%x hdlr:%p arg:%p error:%d\n",
11081708Sstevel key, handler, arg, error);
11091708Sstevel
11101708Sstevel return (error);
11111708Sstevel }
11121708Sstevel
11131708Sstevel
11141708Sstevel /*
11151708Sstevel * iosram_unregister()
11161708Sstevel * Unregister handler associated with the specified chunk.
11171708Sstevel */
11181708Sstevel int
iosram_unregister(uint32_t key)11191708Sstevel iosram_unregister(uint32_t key)
11201708Sstevel {
11211708Sstevel struct iosram_chunk *chunkp;
11221708Sstevel int error = 0;
11231708Sstevel
11241708Sstevel /*
11251708Sstevel * Acquire lock and look for the requested chunk. If it exists and has
11261708Sstevel * a callback registered, unregister it.
11271708Sstevel */
11281708Sstevel mutex_enter(&iosram_mutex);
11291708Sstevel chunkp = iosram_find_chunk(key);
11301708Sstevel
11311708Sstevel if (iosram_master == NULL) {
11321708Sstevel error = EIO;
11331708Sstevel } else if (chunkp == NULL) {
11341708Sstevel error = EINVAL;
11351708Sstevel } else if (chunkp->cback.busy) {
11361708Sstevel /*
11371708Sstevel * If the handler is already busy (being invoked), then we flag
11381708Sstevel * it so it will be unregistered after the invocation completes.
11391708Sstevel */
11401708Sstevel DPRINTF(1, ("IOSRAM(%d): unregister: delaying unreg k:0x%08x\n",
11411708Sstevel iosram_master->instance, key));
11421708Sstevel chunkp->cback.unregister = 1;
11431708Sstevel } else if (chunkp->cback.handler != NULL) {
11441708Sstevel chunkp->cback.handler = NULL;
11451708Sstevel chunkp->cback.arg = NULL;
11461708Sstevel }
11471708Sstevel mutex_exit(&iosram_mutex);
11481708Sstevel
11491708Sstevel IOSRAMLOG(1, "UNREG: key:%x error:%d\n", key, error, NULL, NULL);
11501708Sstevel return (error);
11511708Sstevel }
11521708Sstevel
11531708Sstevel
11541708Sstevel /*
11551708Sstevel * iosram_get_flag():
11561708Sstevel * Get data_valid and/or int_pending flags associated with the
11571708Sstevel * specified key.
11581708Sstevel */
11591708Sstevel int
iosram_get_flag(uint32_t key,uint8_t * data_valid,uint8_t * int_pending)11601708Sstevel iosram_get_flag(uint32_t key, uint8_t *data_valid, uint8_t *int_pending)
11611708Sstevel {
11621708Sstevel iosram_chunk_t *chunkp;
11631708Sstevel iosram_flags_t flags;
11641708Sstevel int error = 0;
11651708Sstevel
11661708Sstevel /*
11671708Sstevel * Acquire lock and look for the requested chunk. If it exists, and no
11681708Sstevel * tunnel switch is in progress, read the chunk's flags.
11691708Sstevel */
11701708Sstevel mutex_enter(&iosram_mutex);
11711708Sstevel chunkp = iosram_find_chunk(key);
11721708Sstevel
11731708Sstevel if (iosram_master == NULL) {
11741708Sstevel error = EIO;
11751708Sstevel } else if (chunkp == NULL) {
11761708Sstevel error = EINVAL;
11771708Sstevel } else if (iosram_tswitch_active) {
11781708Sstevel error = EAGAIN;
11791708Sstevel } else {
11801708Sstevel IOSRAM_STAT(getflag);
11811708Sstevel
11821708Sstevel /*
11831708Sstevel * Read the flags
11841708Sstevel */
11851708Sstevel ddi_rep_get8(iosram_handle, (uint8_t *)&flags,
11861708Sstevel (uint8_t *)(chunkp->flagsp), sizeof (iosram_flags_t),
11871708Sstevel DDI_DEV_AUTOINCR);
11881708Sstevel
11891708Sstevel /*
11901708Sstevel * Get each flag value that the caller is interested in.
11911708Sstevel */
11921708Sstevel if (data_valid != NULL) {
11931708Sstevel *data_valid = flags.data_valid;
11941708Sstevel }
11951708Sstevel
11961708Sstevel if (int_pending != NULL) {
11971708Sstevel *int_pending = flags.int_pending;
11981708Sstevel }
11991708Sstevel }
12001708Sstevel mutex_exit(&iosram_mutex);
12011708Sstevel
12021708Sstevel IOSRAMLOG(1, "GetFlag key:%x data_valid:%x int_pending:%x error:%d\n",
12031708Sstevel key, flags.data_valid, flags.int_pending, error);
12041708Sstevel return (error);
12051708Sstevel }
12061708Sstevel
12071708Sstevel
12081708Sstevel /*
12091708Sstevel * iosram_set_flag():
12101708Sstevel * Set data_valid and int_pending flags associated with the specified key.
12111708Sstevel */
12121708Sstevel int
iosram_set_flag(uint32_t key,uint8_t data_valid,uint8_t int_pending)12131708Sstevel iosram_set_flag(uint32_t key, uint8_t data_valid, uint8_t int_pending)
12141708Sstevel {
12151708Sstevel iosram_chunk_t *chunkp;
12161708Sstevel iosram_flags_t flags;
12171708Sstevel int error = 0;
12181708Sstevel
12191708Sstevel /*
12201708Sstevel * Acquire lock and look for the requested chunk. If it exists, and no
12211708Sstevel * tunnel switch is in progress, write the chunk's flags.
12221708Sstevel */
12231708Sstevel mutex_enter(&iosram_mutex);
12241708Sstevel chunkp = iosram_find_chunk(key);
12251708Sstevel
12261708Sstevel if (iosram_master == NULL) {
12271708Sstevel error = EIO;
12281708Sstevel } else if ((chunkp == NULL) ||
12291708Sstevel ((data_valid != IOSRAM_DATA_INVALID) &&
12301708Sstevel (data_valid != IOSRAM_DATA_VALID)) ||
12311708Sstevel ((int_pending != IOSRAM_INT_NONE) &&
12321708Sstevel (int_pending != IOSRAM_INT_TO_SSC) &&
12331708Sstevel (int_pending != IOSRAM_INT_TO_DOM))) {
12341708Sstevel error = EINVAL;
12351708Sstevel } else if (iosram_tswitch_active) {
12361708Sstevel error = EAGAIN;
12371708Sstevel } else {
12381708Sstevel IOSRAM_STAT(setflag);
12391708Sstevel flags.data_valid = data_valid;
12401708Sstevel flags.int_pending = int_pending;
12411708Sstevel ddi_rep_put8(iosram_handle, (uint8_t *)&flags,
12421708Sstevel (uint8_t *)(chunkp->flagsp), sizeof (iosram_flags_t),
12431708Sstevel DDI_DEV_AUTOINCR);
12441708Sstevel }
12451708Sstevel mutex_exit(&iosram_mutex);
12461708Sstevel
12471708Sstevel IOSRAMLOG(1, "SetFlag key:%x data_valid:%x int_pending:%x error:%d\n",
12481708Sstevel key, flags.data_valid, flags.int_pending, error);
12491708Sstevel return (error);
12501708Sstevel }
12511708Sstevel
12521708Sstevel
12531708Sstevel /*
12541708Sstevel * iosram_ctrl()
12551708Sstevel * This function provides access to a variety of services not available
12561708Sstevel * through the basic API.
12571708Sstevel */
12581708Sstevel int
iosram_ctrl(uint32_t key,uint32_t cmd,void * arg)12591708Sstevel iosram_ctrl(uint32_t key, uint32_t cmd, void *arg)
12601708Sstevel {
12611708Sstevel struct iosram_chunk *chunkp;
12621708Sstevel int error = 0;
12631708Sstevel
12641708Sstevel /*
12651708Sstevel * Acquire lock and do some argument sanity checking.
12661708Sstevel */
12671708Sstevel mutex_enter(&iosram_mutex);
12681708Sstevel chunkp = iosram_find_chunk(key);
12691708Sstevel
12701708Sstevel if (iosram_master == NULL) {
12711708Sstevel error = EIO;
12721708Sstevel } else if (chunkp == NULL) {
12731708Sstevel error = EINVAL;
12741708Sstevel }
12751708Sstevel
12761708Sstevel if (error != 0) {
12771708Sstevel mutex_exit(&iosram_mutex);
12781708Sstevel return (error);
12791708Sstevel }
12801708Sstevel
12811708Sstevel /*
12821708Sstevel * Arguments seem okay so far, so process the command.
12831708Sstevel */
12841708Sstevel switch (cmd) {
12851708Sstevel case IOSRAM_CMD_CHUNKLEN:
12861708Sstevel /*
12871708Sstevel * Return the length of the chunk indicated by the key.
12881708Sstevel */
12891708Sstevel if (arg == NULL) {
12901708Sstevel error = EINVAL;
12911708Sstevel break;
12921708Sstevel }
12931708Sstevel
12941708Sstevel *(uint32_t *)arg = chunkp->toc_data.len;
12951708Sstevel break;
12961708Sstevel
12971708Sstevel default:
12981708Sstevel error = ENOTSUP;
12991708Sstevel break;
13001708Sstevel }
13011708Sstevel
13021708Sstevel mutex_exit(&iosram_mutex);
13031708Sstevel return (error);
13041708Sstevel }
13051708Sstevel
13061708Sstevel
13071708Sstevel /*
13081708Sstevel * iosram_hdr_ctrl()
13091708Sstevel * This function provides an interface for the Mailbox Protocol
13101708Sstevel * implementation to use when interacting with the IOSRAM header.
13111708Sstevel */
13121708Sstevel int
iosram_hdr_ctrl(uint32_t cmd,void * arg)13131708Sstevel iosram_hdr_ctrl(uint32_t cmd, void *arg)
13141708Sstevel {
13151708Sstevel int error = 0;
13161708Sstevel
13171708Sstevel /*
13181708Sstevel * Acquire lock and do some argument sanity checking.
13191708Sstevel */
13201708Sstevel mutex_enter(&iosram_mutex);
13211708Sstevel
13221708Sstevel if (iosram_master == NULL) {
13231708Sstevel error = EIO;
13241708Sstevel }
13251708Sstevel
13261708Sstevel if (error != 0) {
13271708Sstevel mutex_exit(&iosram_mutex);
13281708Sstevel return (error);
13291708Sstevel }
13301708Sstevel
13311708Sstevel switch (cmd) {
13321708Sstevel case IOSRAM_HDRCMD_GET_SMS_MBOX_VER:
13331708Sstevel /*
13341708Sstevel * Return the value of the sms_mbox_version field.
13351708Sstevel */
13361708Sstevel if (arg == NULL) {
13371708Sstevel error = EINVAL;
13381708Sstevel break;
13391708Sstevel }
13401708Sstevel
13411708Sstevel *(uint32_t *)arg = IOSRAM_GET_HDRFIELD32(iosram_master,
13421708Sstevel sms_mbox_version);
13431708Sstevel break;
13441708Sstevel
13451708Sstevel case IOSRAM_HDRCMD_SET_OS_MBOX_VER:
13461708Sstevel /*
13471708Sstevel * Set the value of the os_mbox_version field.
13481708Sstevel */
13491708Sstevel IOSRAM_SET_HDRFIELD32(iosram_master, os_mbox_version,
13501708Sstevel (uint32_t)(uintptr_t)arg);
13511708Sstevel IOSRAM_SET_HDRFIELD32(iosram_master, os_change_mask,
13521708Sstevel IOSRAM_HDRFIELD_OS_MBOX_VER);
1353*11311SSurya.Prakki@Sun.COM (void) iosram_send_intr();
13541708Sstevel break;
13551708Sstevel
13561708Sstevel case IOSRAM_HDRCMD_REG_CALLBACK:
13571708Sstevel iosram_hdrchange_handler = (void (*)())arg;
13581708Sstevel break;
13591708Sstevel
13601708Sstevel default:
13611708Sstevel error = ENOTSUP;
13621708Sstevel break;
13631708Sstevel }
13641708Sstevel
13651708Sstevel mutex_exit(&iosram_mutex);
13661708Sstevel return (error);
13671708Sstevel }
13681708Sstevel
13691708Sstevel
13701708Sstevel /*
13711708Sstevel * iosram_softintr()
13721708Sstevel * IOSRAM soft interrupt handler
13731708Sstevel */
13741708Sstevel static uint_t
iosram_softintr(caddr_t arg)13751708Sstevel iosram_softintr(caddr_t arg)
13761708Sstevel {
13771708Sstevel uint32_t hdr_changes;
13781708Sstevel iosramsoft_t *softp = (iosramsoft_t *)arg;
13791708Sstevel iosram_chunk_t *chunkp;
13801708Sstevel void (*handler)();
13811708Sstevel int i;
13821708Sstevel uint8_t flag;
13831708Sstevel
13841708Sstevel DPRINTF(1, ("iosram(%d): in iosram_softintr\n", softp->instance));
13851708Sstevel
13861708Sstevel IOSRAMLOG(2, "SINTR arg/softp:%p pending:%d busy:%d\n",
13871708Sstevel arg, softp->intr_pending, softp->intr_busy, NULL);
13881708Sstevel
13891708Sstevel mutex_enter(&iosram_mutex);
13901708Sstevel mutex_enter(&softp->intr_mutex);
13911708Sstevel
13921708Sstevel /*
13931708Sstevel * Do not process interrupt if interrupt handler is already running or
13941708Sstevel * no interrupts are pending.
13951708Sstevel */
13961708Sstevel if (softp->intr_busy || !softp->intr_pending) {
13971708Sstevel mutex_exit(&softp->intr_mutex);
13981708Sstevel mutex_exit(&iosram_mutex);
13991708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: busy=%d pending=%d\n",
14001708Sstevel softp->instance, softp->intr_busy, softp->intr_pending));
14011708Sstevel return (softp->intr_pending ? DDI_INTR_CLAIMED :
14021708Sstevel DDI_INTR_UNCLAIMED);
14031708Sstevel }
14041708Sstevel
14051708Sstevel /*
14061708Sstevel * It's possible for the SC to send an interrupt on the new master
14071708Sstevel * before we are able to set our internal state. If so, we'll retrigger
14081708Sstevel * soft interrupt right after tunnel switch completion.
14091708Sstevel */
14101708Sstevel if (softp->state & IOSRAM_STATE_TSWITCH) {
14111708Sstevel mutex_exit(&softp->intr_mutex);
14121708Sstevel mutex_exit(&iosram_mutex);
14131708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: doing switch "
14141708Sstevel "state=0x%x\n", softp->instance, softp->state));
14151708Sstevel return (DDI_INTR_CLAIMED);
14161708Sstevel }
14171708Sstevel
14181708Sstevel /*
14191708Sstevel * Do not process interrupt if we are not the master.
14201708Sstevel */
14211708Sstevel if (!(softp->state & IOSRAM_STATE_MASTER)) {
14221708Sstevel mutex_exit(&softp->intr_mutex);
14231708Sstevel mutex_exit(&iosram_mutex);
14241708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: no master state=0x%x\n ",
14251708Sstevel softp->instance, softp->state));
14261708Sstevel return (DDI_INTR_CLAIMED);
14271708Sstevel }
14281708Sstevel
14291708Sstevel IOSRAM_STAT(sintr_recv);
14301708Sstevel
14311708Sstevel /*
14321708Sstevel * If the driver is suspended, then we should not process any
14331708Sstevel * interrupts. Instead, we trigger a soft interrupt when the driver
14341708Sstevel * resumes.
14351708Sstevel */
14361708Sstevel if (softp->suspended) {
14371708Sstevel mutex_exit(&softp->intr_mutex);
14381708Sstevel mutex_exit(&iosram_mutex);
14391708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: suspended\n",
14401708Sstevel softp->instance));
14411708Sstevel return (DDI_INTR_CLAIMED);
14421708Sstevel }
14431708Sstevel
14441708Sstevel /*
14451708Sstevel * Indicate that the IOSRAM interrupt handler is busy. Note that this
14461708Sstevel * includes incrementing the reader/writer count, since we don't want
14471708Sstevel * any tunnel switches to start up while we're processing callbacks.
14481708Sstevel */
14491708Sstevel softp->intr_busy = 1;
14501708Sstevel iosram_rw_active++;
14511708Sstevel #if defined(DEBUG)
14521708Sstevel if (iosram_rw_active > iosram_rw_active_max) {
14531708Sstevel iosram_rw_active_max = iosram_rw_active;
14541708Sstevel }
14551708Sstevel #endif
14561708Sstevel
14571708Sstevel do {
14581708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: processing interrupt\n",
14591708Sstevel softp->instance));
14601708Sstevel
14611708Sstevel softp->intr_pending = 0;
14621708Sstevel
14631708Sstevel mutex_exit(&softp->intr_mutex);
14641708Sstevel
14651708Sstevel /*
14661708Sstevel * Process changes to the IOSRAM header.
14671708Sstevel */
14681708Sstevel hdr_changes = IOSRAM_GET_HDRFIELD32(iosram_master,
14691708Sstevel sms_change_mask);
14701708Sstevel if (hdr_changes != 0) {
14711708Sstevel int error;
14721708Sstevel
14731708Sstevel IOSRAM_SET_HDRFIELD32(iosram_master, sms_change_mask,
14741708Sstevel 0);
14751708Sstevel if (hdr_changes & IOSRAM_HDRFIELD_TOC_INDEX) {
14761708Sstevel /*
14771708Sstevel * XXX is it safe to temporarily release the
14781708Sstevel * iosram_mutex here?
14791708Sstevel */
14801708Sstevel mutex_exit(&iosram_mutex);
14811708Sstevel error = iosram_read_toc(iosram_master);
14821708Sstevel mutex_enter(&iosram_mutex);
14831708Sstevel if (error) {
14841708Sstevel cmn_err(CE_WARN, "iosram_read_toc: new"
14851708Sstevel " TOC invalid; using old TOC.");
14861708Sstevel }
14871708Sstevel iosram_update_addrs(iosram_master);
14881708Sstevel }
14891708Sstevel
14901708Sstevel if (iosram_hdrchange_handler != NULL) {
14911708Sstevel mutex_exit(&iosram_mutex);
14921708Sstevel iosram_hdrchange_handler();
14931708Sstevel mutex_enter(&iosram_mutex);
14941708Sstevel }
14951708Sstevel }
14961708Sstevel
14971708Sstevel /*
14981708Sstevel * Get data_valid/int_pending flags and generate a callback if
14991708Sstevel * applicable. For now, we read only those flags for which a
15001708Sstevel * callback has been registered. We can optimize reading of
15011708Sstevel * flags by reading them all at once and then process them
15021708Sstevel * later.
15031708Sstevel */
15041708Sstevel for (i = 0, chunkp = chunks; i < nchunks; i++,
15051708Sstevel chunkp++) {
15061708Sstevel #if DEBUG
15071708Sstevel flag = ddi_get8(iosram_handle,
15081708Sstevel &(chunkp->flagsp->int_pending));
15091708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr chunk #%d "
15101708Sstevel "flag=0x%x handler=%p\n",
15111708Sstevel softp->instance, i, (int)flag,
1512*11311SSurya.Prakki@Sun.COM (void *)chunkp->cback.handler));
15131708Sstevel #endif
15141708Sstevel if ((handler = chunkp->cback.handler) == NULL) {
15151708Sstevel continue;
15161708Sstevel }
15171708Sstevel flag = ddi_get8(iosram_handle,
15181708Sstevel &(chunkp->flagsp->int_pending));
15191708Sstevel if (flag == IOSRAM_INT_TO_DOM) {
15201708Sstevel DPRINTF(1,
15211708Sstevel ("IOSRAM(%d): softintr: invoking handler\n",
15221708Sstevel softp->instance));
15231708Sstevel IOSRAMLOG(1,
15241708Sstevel "SINTR invoking hdlr:%p arg:%p index:%d\n",
15251708Sstevel handler, chunkp->cback.arg, i, NULL);
15261708Sstevel IOSRAM_STAT(callbacks);
15271708Sstevel
15281708Sstevel ddi_put8(iosram_handle,
15291708Sstevel &(chunkp->flagsp->int_pending),
15301708Sstevel IOSRAM_INT_NONE);
15311708Sstevel chunkp->cback.busy = 1;
15321708Sstevel mutex_exit(&iosram_mutex);
15331708Sstevel (*handler)(chunkp->cback.arg);
15341708Sstevel mutex_enter(&iosram_mutex);
15351708Sstevel chunkp->cback.busy = 0;
15361708Sstevel
15371708Sstevel /*
15381708Sstevel * If iosram_unregister was called while the
15391708Sstevel * callback was being invoked, complete the
15401708Sstevel * unregistration here.
15411708Sstevel */
15421708Sstevel if (chunkp->cback.unregister) {
15431708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: "
15441708Sstevel "delayed unreg k:0x%08x\n",
15451708Sstevel softp->instance,
15461708Sstevel chunkp->toc_data.key));
15471708Sstevel chunkp->cback.handler = NULL;
15481708Sstevel chunkp->cback.arg = NULL;
15491708Sstevel chunkp->cback.unregister = 0;
15501708Sstevel }
15511708Sstevel }
15521708Sstevel
15531708Sstevel /*
15541708Sstevel * If there's a tunnel switch waiting to run, give it
15551708Sstevel * higher priority than these callbacks by bailing out.
15561708Sstevel * They'll still be invoked on the new master iosram
15571708Sstevel * when the tunnel switch is done.
15581708Sstevel */
15591708Sstevel if (iosram_tswitch_active) {
15601708Sstevel break;
15611708Sstevel }
15621708Sstevel }
15631708Sstevel
15641708Sstevel mutex_enter(&softp->intr_mutex);
15651708Sstevel
15661708Sstevel } while (softp->intr_pending && !softp->suspended &&
15671708Sstevel !iosram_tswitch_active);
15681708Sstevel
15691708Sstevel /*
15701708Sstevel * Indicate IOSRAM interrupt handler is not BUSY any more
15711708Sstevel */
15721708Sstevel softp->intr_busy = 0;
15731708Sstevel
15741708Sstevel ASSERT(iosram_rw_active > 0);
15751708Sstevel if ((--iosram_rw_active == 0) && iosram_rw_wakeup) {
15761708Sstevel iosram_rw_wakeup = 0;
15771708Sstevel cv_broadcast(&iosram_rw_wait);
15781708Sstevel }
15791708Sstevel
15801708Sstevel mutex_exit(&softp->intr_mutex);
15811708Sstevel mutex_exit(&iosram_mutex);
15821708Sstevel
15831708Sstevel DPRINTF(1, ("iosram(%d): softintr exit\n", softp->instance));
15841708Sstevel
15851708Sstevel return (DDI_INTR_CLAIMED);
15861708Sstevel }
15871708Sstevel
15881708Sstevel
15891708Sstevel /*
15901708Sstevel * iosram_intr()
15911708Sstevel * IOSRAM real interrupt handler
15921708Sstevel */
15931708Sstevel static uint_t
iosram_intr(caddr_t arg)15941708Sstevel iosram_intr(caddr_t arg)
15951708Sstevel {
15961708Sstevel iosramsoft_t *softp = (iosramsoft_t *)arg;
15971708Sstevel int result = DDI_INTR_UNCLAIMED;
15981708Sstevel uint32_t int_status;
15991708Sstevel
16001708Sstevel DPRINTF(2, ("iosram(%d): in iosram_intr\n", softp->instance));
16011708Sstevel
16021708Sstevel mutex_enter(&softp->intr_mutex);
16031708Sstevel
16041708Sstevel if (softp->sbbc_handle == NULL) {
16051708Sstevel /*
16061708Sstevel * The SBBC registers region is not mapped in.
16071708Sstevel * Set the interrupt pending flag here, and process the
16081708Sstevel * interrupt after the tunnel switch.
16091708Sstevel */
16101708Sstevel DPRINTF(1, ("IOSRAM(%d): iosram_intr: SBBC not mapped\n",
16111708Sstevel softp->instance));
16121708Sstevel softp->intr_pending = 1;
16131708Sstevel mutex_exit(&softp->intr_mutex);
16141708Sstevel return (DDI_INTR_UNCLAIMED);
16151708Sstevel }
16161708Sstevel
16171708Sstevel int_status = ddi_get32(softp->sbbc_handle,
16181708Sstevel &(softp->sbbc_region->int_status.reg));
16191708Sstevel DPRINTF(1, ("iosram_intr: int_status = 0x%08x\n", int_status));
16201708Sstevel
16211708Sstevel if (int_status & IOSRAM_SBBC_INT0) {
16221708Sstevel result = DDI_INTR_CLAIMED;
16231708Sstevel DPRINTF(1, ("iosram_intr: int0 detected!\n"));
16241708Sstevel }
16251708Sstevel
16261708Sstevel if (int_status & IOSRAM_SBBC_INT1) {
16271708Sstevel result = DDI_INTR_CLAIMED;
16281708Sstevel DPRINTF(1, ("iosram_intr: int1 detected!\n"));
16291708Sstevel }
16301708Sstevel
16311708Sstevel if (result == DDI_INTR_CLAIMED) {
16321708Sstevel ddi_put32(softp->sbbc_handle,
16331708Sstevel &(softp->sbbc_region->int_status.reg), int_status);
16341708Sstevel int_status = ddi_get32(softp->sbbc_handle,
16351708Sstevel &(softp->sbbc_region->int_status.reg));
16361708Sstevel DPRINTF(1, ("iosram_intr: int_status = 0x%08x\n",
16371708Sstevel int_status));
16381708Sstevel
16391708Sstevel softp->intr_pending = 1;
16401708Sstevel /*
16411708Sstevel * Trigger soft interrupt if not executing and
16421708Sstevel * not suspended.
16431708Sstevel */
16441708Sstevel if (!softp->intr_busy && !softp->suspended &&
16451708Sstevel (softp->softintr_id != NULL)) {
16461708Sstevel DPRINTF(1, ("iosram(%d): trigger softint\n",
16471708Sstevel softp->instance));
16481708Sstevel ddi_trigger_softintr(softp->softintr_id);
16491708Sstevel }
16501708Sstevel }
16511708Sstevel
16521708Sstevel IOSRAM_STAT(intr_recv);
16531708Sstevel
16541708Sstevel mutex_exit(&softp->intr_mutex);
16551708Sstevel
16561708Sstevel IOSRAMLOG(2, "INTR arg/softp:%p pending:%d busy:%d\n",
16571708Sstevel arg, softp->intr_pending, softp->intr_busy, NULL);
16581708Sstevel DPRINTF(1, ("iosram(%d): iosram_intr exit\n", softp->instance));
16591708Sstevel
16601708Sstevel return (result);
16611708Sstevel }
16621708Sstevel
16631708Sstevel
16641708Sstevel /*
16651708Sstevel * iosram_send_intr()
16661708Sstevel * Send an interrupt to the SSP side via AXQ driver
16671708Sstevel */
16681708Sstevel int
iosram_send_intr()16691708Sstevel iosram_send_intr()
16701708Sstevel {
16711708Sstevel IOSRAMLOG(1, "SendIntr called\n", NULL, NULL, NULL, NULL);
16721708Sstevel IOSRAM_STAT(intr_send);
16731708Sstevel DPRINTF(1, ("iosram iosram_send_intr invoked\n"));
16741708Sstevel
16751708Sstevel return (axq_cpu2ssc_intr(0));
16761708Sstevel }
16771708Sstevel
16781708Sstevel
16791708Sstevel #if defined(DEBUG)
16801708Sstevel static void
iosram_dummy_cback(void * arg)16811708Sstevel iosram_dummy_cback(void *arg)
16821708Sstevel {
16831708Sstevel DPRINTF(1, ("iosram_dummy_cback invoked arg:%p\n", arg));
16841708Sstevel }
16851708Sstevel #endif /* DEBUG */
16861708Sstevel
16871708Sstevel
16881708Sstevel /*ARGSUSED1*/
16891708Sstevel static int
iosram_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)16901708Sstevel iosram_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
16911708Sstevel int *rvalp)
16921708Sstevel {
16931708Sstevel struct iosramsoft *softp;
16941708Sstevel int error = DDI_SUCCESS;
16951708Sstevel
16961708Sstevel softp = ddi_get_soft_state(iosramsoft_statep, getminor(dev));
16971708Sstevel if (softp == NULL) {
16981708Sstevel return (ENXIO);
16991708Sstevel }
17001708Sstevel IOSRAMLOG(1, "IOCTL: dev:%p cmd:%x arg:%p ... instance %d\n",
17011708Sstevel dev, cmd, arg, softp->instance);
17021708Sstevel
17031708Sstevel switch (cmd) {
17041708Sstevel #if defined(DEBUG)
17051708Sstevel case IOSRAM_GET_FLAG:
17067656SSherry.Moore@Sun.COM {
17071708Sstevel iosram_io_t req;
17081708Sstevel uint8_t data_valid, int_pending;
17091708Sstevel
17101708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
17111708Sstevel return (EFAULT);
17121708Sstevel }
17131708Sstevel
17141708Sstevel DPRINTF(2, ("IOSRAM_GET_FLAG(key:%x\n", req.key));
17151708Sstevel
17161708Sstevel req.retval = iosram_get_flag(req.key, &data_valid,
17171708Sstevel &int_pending);
17181708Sstevel req.data_valid = (uint32_t)data_valid;
17191708Sstevel req.int_pending = (uint32_t)int_pending;
17201708Sstevel
17211708Sstevel if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
17221708Sstevel DPRINTF(1,
17231708Sstevel ("IOSRAM_GET_FLAG: can't copyout req.retval (%x)",
17241708Sstevel req.retval));
17251708Sstevel error = EFAULT;
17261708Sstevel }
17271708Sstevel
17281708Sstevel return (error);
17297656SSherry.Moore@Sun.COM }
17301708Sstevel
17311708Sstevel case IOSRAM_SET_FLAG:
17327656SSherry.Moore@Sun.COM {
17331708Sstevel iosram_io_t req;
17341708Sstevel
17351708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
17361708Sstevel return (EFAULT);
17371708Sstevel }
17381708Sstevel
17391708Sstevel DPRINTF(2, ("IOSRAM_SET_FLAG(key:%x data_valid:%x "
17401708Sstevel "int_pending:%x\n", req.key, req.data_valid,
17411708Sstevel req.int_pending));
17421708Sstevel
17431708Sstevel req.retval = iosram_set_flag(req.key, req.data_valid,
17441708Sstevel req.int_pending);
17451708Sstevel
17461708Sstevel if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
17471708Sstevel DPRINTF(1, ("IOSRAM_SET_FLAG: can't copyout req.retval"
17481708Sstevel " (%x)\n", req.retval));
17491708Sstevel error = EFAULT;
17501708Sstevel }
17511708Sstevel
17521708Sstevel return (error);
17537656SSherry.Moore@Sun.COM }
17541708Sstevel
17551708Sstevel case IOSRAM_RD:
17567656SSherry.Moore@Sun.COM {
17571708Sstevel caddr_t bufp;
17581708Sstevel int len;
17591708Sstevel iosram_io_t req;
17601708Sstevel
17611708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
17621708Sstevel return (EFAULT);
17631708Sstevel }
17641708Sstevel
17651708Sstevel DPRINTF(2, ("IOSRAM_RD(k:%x o:%x len:%x bufp:%p\n", req.key,
17661708Sstevel req.off, req.len, (void *)(uintptr_t)req.bufp));
17671708Sstevel
17681708Sstevel len = req.len;
17691708Sstevel bufp = kmem_alloc(len, KM_SLEEP);
17701708Sstevel
17711708Sstevel req.retval = iosram_rd(req.key, req.off, req.len, bufp);
17721708Sstevel
17731708Sstevel if (ddi_copyout(bufp, (void *)(uintptr_t)req.bufp, len, mode)) {
17741708Sstevel DPRINTF(1, ("IOSRAM_RD: copyout(%p, %p,%x,%x) failed\n",
1775*11311SSurya.Prakki@Sun.COM (void *)bufp, (void *)(uintptr_t)req.bufp, len,
1776*11311SSurya.Prakki@Sun.COM mode));
17771708Sstevel error = EFAULT;
17781708Sstevel } else if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
17791708Sstevel DPRINTF(1, ("IOSRAM_RD: can't copyout retval (%x)\n",
17801708Sstevel req.retval));
17811708Sstevel error = EFAULT;
17821708Sstevel }
17831708Sstevel
17841708Sstevel kmem_free(bufp, len);
17851708Sstevel return (error);
17867656SSherry.Moore@Sun.COM }
17871708Sstevel
17881708Sstevel case IOSRAM_WR:
17897656SSherry.Moore@Sun.COM {
17901708Sstevel caddr_t bufp;
17911708Sstevel iosram_io_t req;
17921708Sstevel int len;
17931708Sstevel
17941708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
17951708Sstevel return (EFAULT);
17961708Sstevel }
17971708Sstevel
17981708Sstevel DPRINTF(2, ("IOSRAM_WR(k:%x o:%x len:%x bufp:%p\n",
1799*11311SSurya.Prakki@Sun.COM req.key, req.off, req.len, (void *)(uintptr_t)req.bufp));
18001708Sstevel len = req.len;
18011708Sstevel bufp = kmem_alloc(len, KM_SLEEP);
18021708Sstevel if (ddi_copyin((void *)(uintptr_t)req.bufp, bufp, len, mode)) {
18031708Sstevel error = EFAULT;
18041708Sstevel } else {
18051708Sstevel req.retval = iosram_wr(req.key, req.off, req.len,
18061708Sstevel bufp);
18071708Sstevel
18081708Sstevel if (ddi_copyout(&req, (void *)arg, sizeof (req),
18091708Sstevel mode)) {
18101708Sstevel error = EFAULT;
18111708Sstevel }
18121708Sstevel }
18131708Sstevel kmem_free(bufp, len);
18141708Sstevel return (error);
18157656SSherry.Moore@Sun.COM }
18161708Sstevel
18171708Sstevel case IOSRAM_TOC:
18187656SSherry.Moore@Sun.COM {
18191708Sstevel caddr_t bufp;
18201708Sstevel int len;
18211708Sstevel iosram_io_t req;
18221708Sstevel
18231708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
18241708Sstevel return (EFAULT);
18251708Sstevel }
18261708Sstevel
18271708Sstevel DPRINTF(2, ("IOSRAM_TOC (req.bufp:%x req.len:%x) \n",
18281708Sstevel req.bufp, req.len));
18291708Sstevel
18301708Sstevel len = req.len;
18311708Sstevel bufp = kmem_alloc(len, KM_SLEEP);
18321708Sstevel
18331708Sstevel req.retval = iosram_get_keys((iosram_toc_entry_t *)bufp,
18341708Sstevel &req.len);
18351708Sstevel
18361708Sstevel if (ddi_copyout(bufp, (void *)(uintptr_t)req.bufp, req.len,
18371708Sstevel mode)) {
18381708Sstevel DPRINTF(1,
18391708Sstevel ("IOSRAM_TOC: copyout(%p, %p,%x,%x) failed\n",
1840*11311SSurya.Prakki@Sun.COM (void *)bufp, (void *)(uintptr_t)req.bufp, req.len,
1841*11311SSurya.Prakki@Sun.COM mode));
18421708Sstevel error = EFAULT;
18431708Sstevel } else if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
18441708Sstevel DPRINTF(1, ("IOSRAM_TOC: can't copyout retval (%x)\n",
18451708Sstevel req.retval));
18461708Sstevel error = EFAULT;
18471708Sstevel }
18481708Sstevel kmem_free(bufp, len);
18491708Sstevel return (error);
18507656SSherry.Moore@Sun.COM }
18511708Sstevel
18521708Sstevel case IOSRAM_SEND_INTR:
18537656SSherry.Moore@Sun.COM {
18541708Sstevel DPRINTF(2, ("IOSRAM_SEND_INTR\n"));
18551708Sstevel
18561708Sstevel switch ((int)arg) {
18571708Sstevel case 0x11:
18581708Sstevel case 0x22:
18591708Sstevel case 0x44:
18601708Sstevel case 0x88:
18611708Sstevel ddi_put32(softp->sbbc_handle,
18621708Sstevel &(softp->sbbc_region->int_enable.reg), (int)arg);
18631708Sstevel DPRINTF(1, ("Wrote 0x%x to int_enable.reg\n",
18641708Sstevel (int)arg));
18651708Sstevel break;
18661708Sstevel case 0xBB:
18671708Sstevel ddi_put32(softp->sbbc_handle,
18681708Sstevel &(softp->sbbc_region->p0_int_gen.reg), 1);
18691708Sstevel DPRINTF(1, ("Wrote 1 to p0_int_gen.reg\n"));
18701708Sstevel break;
18711708Sstevel default:
18721708Sstevel error = iosram_send_intr();
18731708Sstevel }
18741708Sstevel
18751708Sstevel return (error);
18767656SSherry.Moore@Sun.COM }
18771708Sstevel
18781708Sstevel case IOSRAM_PRINT_CBACK:
18791708Sstevel iosram_print_cback();
18801708Sstevel break;
18811708Sstevel
18821708Sstevel case IOSRAM_PRINT_STATE:
18831708Sstevel iosram_print_state((int)arg);
18841708Sstevel break;
18851708Sstevel
18861708Sstevel #if IOSRAM_STATS
18871708Sstevel case IOSRAM_PRINT_STATS:
18881708Sstevel iosram_print_stats();
18891708Sstevel break;
18901708Sstevel #endif
18911708Sstevel
18921708Sstevel #if IOSRAM_LOG
18931708Sstevel case IOSRAM_PRINT_LOG:
18941708Sstevel iosram_print_log((int)arg);
18951708Sstevel break;
18961708Sstevel #endif
18971708Sstevel
18981708Sstevel case IOSRAM_TUNNEL_SWITCH:
18991708Sstevel error = iosram_switchfrom((int)arg);
19001708Sstevel break;
19011708Sstevel
19021708Sstevel case IOSRAM_PRINT_FLAGS:
19031708Sstevel iosram_print_flags();
19041708Sstevel break;
19051708Sstevel
19061708Sstevel case IOSRAM_REG_CBACK:
19077656SSherry.Moore@Sun.COM {
19081708Sstevel iosram_io_t req;
19091708Sstevel
19101708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
19111708Sstevel return (EFAULT);
19121708Sstevel }
19131708Sstevel
19141708Sstevel DPRINTF(2, ("IOSRAM_REG_CBACK(k:%x)\n", req.key));
19151708Sstevel
19161708Sstevel req.retval = iosram_register(req.key, iosram_dummy_cback,
19171708Sstevel (void *)(uintptr_t)req.key);
19181708Sstevel if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
19191708Sstevel error = EFAULT;
19201708Sstevel }
19211708Sstevel
19221708Sstevel return (error);
19237656SSherry.Moore@Sun.COM }
19241708Sstevel
19251708Sstevel case IOSRAM_UNREG_CBACK:
19267656SSherry.Moore@Sun.COM {
19271708Sstevel iosram_io_t req;
19281708Sstevel
19291708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
19301708Sstevel return (EFAULT);
19311708Sstevel }
19321708Sstevel
19331708Sstevel DPRINTF(2, ("IOSRAM_REG_CBACK(k:%x)\n", req.key));
19341708Sstevel
19351708Sstevel req.retval = iosram_unregister(req.key);
19361708Sstevel if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
19371708Sstevel error = EFAULT;
19381708Sstevel }
19391708Sstevel
19401708Sstevel return (error);
19417656SSherry.Moore@Sun.COM }
19421708Sstevel
19431708Sstevel case IOSRAM_SEMA_ACQUIRE:
19441708Sstevel {
19451708Sstevel DPRINTF(1, ("IOSRAM_SEMA_ACQUIRE\n"));
19461708Sstevel error = iosram_sema_acquire(NULL);
19471708Sstevel return (error);
19481708Sstevel }
19491708Sstevel
19501708Sstevel case IOSRAM_SEMA_RELEASE:
19511708Sstevel {
19521708Sstevel DPRINTF(1, ("IOSRAM_SEMA_RELEASE\n"));
19531708Sstevel error = iosram_sema_release();
19541708Sstevel return (error);
19551708Sstevel }
19561708Sstevel
19571708Sstevel #endif /* DEBUG */
19581708Sstevel
19591708Sstevel default:
19601708Sstevel DPRINTF(1, ("iosram_ioctl: Illegal command %x\n", cmd));
19611708Sstevel error = ENOTTY;
19621708Sstevel }
19631708Sstevel
19641708Sstevel return (error);
19651708Sstevel }
19661708Sstevel
19671708Sstevel
19681708Sstevel /*
19691708Sstevel * iosram_switch_tunnel(softp)
19701708Sstevel * Switch master tunnel to the specified instance
19711708Sstevel * Must be called while holding iosram_mutex
19721708Sstevel */
19731708Sstevel /*ARGSUSED*/
19741708Sstevel static int
iosram_switch_tunnel(iosramsoft_t * softp)19751708Sstevel iosram_switch_tunnel(iosramsoft_t *softp)
19761708Sstevel {
19771708Sstevel #ifdef DEBUG
19781708Sstevel int instance = softp->instance;
19791708Sstevel #endif
19801708Sstevel int error = 0;
19811708Sstevel iosramsoft_t *prev_master;
19821708Sstevel
19831708Sstevel ASSERT(mutex_owned(&iosram_mutex));
19841708Sstevel
19851708Sstevel DPRINTF(1, ("tunnel switch new master:%p (%d) current master:%p (%d)\n",
1986*11311SSurya.Prakki@Sun.COM (void *)softp, instance, (void *)iosram_master,
19871708Sstevel ((iosram_master) ? iosram_master->instance : -1)));
19881708Sstevel IOSRAMLOG(1, "TSWTCH: new_master:%p (%p) iosram_master:%p (%d)\n",
19891708Sstevel softp, instance, iosram_master,
19901708Sstevel ((iosram_master) ? iosram_master->instance : -1));
19911708Sstevel
19921708Sstevel if (softp == NULL || (softp->state & IOSRAM_STATE_DETACH)) {
19931708Sstevel return (ENXIO);
19941708Sstevel }
19951708Sstevel if (iosram_master == softp) {
19961708Sstevel return (0);
19971708Sstevel }
19981708Sstevel
19991708Sstevel
20001708Sstevel /*
20011708Sstevel * We protect against the softp structure being deallocated by setting
20021708Sstevel * the IOSRAM_STATE_TSWITCH state flag. The detach routine will check
20031708Sstevel * for this flag and if set, it will wait for this flag to be reset or
20041708Sstevel * refuse the detach operation.
20051708Sstevel */
20061708Sstevel iosram_new_master = softp;
20071708Sstevel softp->state |= IOSRAM_STATE_TSWITCH;
20081708Sstevel prev_master = iosram_master;
20091708Sstevel if (prev_master) {
20101708Sstevel prev_master->state |= IOSRAM_STATE_TSWITCH;
20111708Sstevel }
20121708Sstevel mutex_exit(&iosram_mutex);
20131708Sstevel
20141708Sstevel /*
20151708Sstevel * Map the target IOSRAM, read the TOC, and register interrupts if not
20161708Sstevel * already done.
20171708Sstevel */
20181708Sstevel DPRINTF(1, ("iosram(%d): mapping IOSRAM and SBBC\n",
20191708Sstevel softp->instance));
20201708Sstevel IOSRAMLOG(1, "TSWTCH: mapping instance:%d softp:%p\n",
20211708Sstevel instance, softp, NULL, NULL);
20221708Sstevel
20231708Sstevel if (iosram_setup_map(softp) != DDI_SUCCESS) {
20241708Sstevel error = ENXIO;
20251708Sstevel } else if ((chunks == NULL) && (iosram_read_toc(softp) != 0)) {
20261708Sstevel iosram_remove_map(softp);
20271708Sstevel error = EINVAL;
20281708Sstevel } else if (iosram_add_intr(softp) != DDI_SUCCESS) {
20291708Sstevel /*
20301708Sstevel * If there was no previous master, purge the TOC data that
20311708Sstevel * iosram_read_toc() created.
20321708Sstevel */
20331708Sstevel if ((prev_master == NULL) && (chunks != NULL)) {
20341708Sstevel kmem_free(chunks, nchunks * sizeof (iosram_chunk_t));
20351708Sstevel chunks = NULL;
20361708Sstevel nchunks = 0;
20371708Sstevel iosram_init_hashtab();
20381708Sstevel }
20391708Sstevel iosram_remove_map(softp);
20401708Sstevel error = ENXIO;
20411708Sstevel }
20421708Sstevel
20431708Sstevel /*
20441708Sstevel * If we are asked to abort tunnel switch, do so now, before invoking
20451708Sstevel * the OBP callback.
20461708Sstevel */
20471708Sstevel if (iosram_tswitch_aborted) {
20481708Sstevel
20491708Sstevel /*
20501708Sstevel * Once the tunnel switch is aborted, this thread should not
20511708Sstevel * resume. If it does, we simply log a message. We can't unmap
20521708Sstevel * the new master IOSRAM as it may be accessed in
20531708Sstevel * iosram_abort_tswitch(). It will be unmapped when it is
20541708Sstevel * detached.
20551708Sstevel */
20561708Sstevel IOSRAMLOG(1,
20571708Sstevel "TSWTCH: aborted (pre OBP cback). Thread resumed.\n",
20581708Sstevel NULL, NULL, NULL, NULL);
20591708Sstevel error = EIO;
20601708Sstevel }
20611708Sstevel
20621708Sstevel if (error) {
20631708Sstevel IOSRAMLOG(1,
20641708Sstevel "TSWTCH: map failed instance:%d softp:%p error:%x\n",
20651708Sstevel instance, softp, error, NULL);
20661708Sstevel goto done;
20671708Sstevel }
20681708Sstevel
20691708Sstevel if (prev_master != NULL) {
20701708Sstevel int result;
20711708Sstevel
20721708Sstevel /*
20731708Sstevel * Now invoke the OBP interface to do the tunnel switch.
20741708Sstevel */
20751708Sstevel result = prom_starcat_switch_tunnel(softp->portid,
20761708Sstevel OBP_TSWITCH_REQREPLY);
20771708Sstevel if (result != 0) {
20781708Sstevel error = EIO;
20791708Sstevel }
20801708Sstevel IOSRAMLOG(1,
20811708Sstevel "TSWTCH: OBP tswitch portid:%x result:%x error:%x\n",
20821708Sstevel softp->portid, result, error, NULL);
20831708Sstevel IOSRAM_STAT(tswitch);
20841708Sstevel iosram_tswitch_tstamp = ddi_get_lbolt();
20851708Sstevel }
20861708Sstevel
20871708Sstevel mutex_enter(&iosram_mutex);
20881708Sstevel if (iosram_tswitch_aborted) {
20891708Sstevel /*
20901708Sstevel * Tunnel switch aborted. This thread should not resume.
20911708Sstevel * For now, we simply log a message, but don't unmap any
20921708Sstevel * IOSRAM at this stage as it may be accessed within the
20931708Sstevel * isoram_abort_tswitch(). The IOSRAM will be unmapped
20941708Sstevel * when that instance is detached.
20951708Sstevel */
20961708Sstevel if (iosram_tswitch_aborted) {
20971708Sstevel IOSRAMLOG(1,
20981708Sstevel "TSWTCH: aborted (post OBP cback). Thread"
20991708Sstevel " resumed.\n", NULL, NULL, NULL, NULL);
21001708Sstevel error = EIO;
21011708Sstevel mutex_exit(&iosram_mutex);
21021708Sstevel }
21031708Sstevel } else if (error) {
21041708Sstevel /*
21051708Sstevel * Tunnel switch failed. Continue using previous tunnel.
21061708Sstevel * However, unmap new (target) IOSRAM.
21071708Sstevel */
21081708Sstevel iosram_new_master = NULL;
21091708Sstevel mutex_exit(&iosram_mutex);
2110*11311SSurya.Prakki@Sun.COM (void) iosram_remove_intr(softp);
21111708Sstevel iosram_remove_map(softp);
21121708Sstevel } else {
21131708Sstevel /*
21141708Sstevel * Tunnel switch was successful. Set the new master.
21151708Sstevel * Also unmap old master IOSRAM and remove any interrupts
21161708Sstevel * associated with that.
21171708Sstevel *
21181708Sstevel * Note that a call to iosram_force_write() allows access
21191708Sstevel * to the IOSRAM while tunnel switch is in progress. That
21201708Sstevel * means we need to set the new master before unmapping
21211708Sstevel * the old master.
21221708Sstevel */
21231708Sstevel iosram_set_master(softp);
21241708Sstevel iosram_new_master = NULL;
21251708Sstevel mutex_exit(&iosram_mutex);
21261708Sstevel
21271708Sstevel if (prev_master) {
21281708Sstevel IOSRAMLOG(1, "TSWTCH: unmapping prev_master:%p (%d)\n",
21291708Sstevel prev_master, prev_master->instance, NULL, NULL);
2130*11311SSurya.Prakki@Sun.COM (void) iosram_remove_intr(prev_master);
21311708Sstevel iosram_remove_map(prev_master);
21321708Sstevel }
21331708Sstevel }
21341708Sstevel
21351708Sstevel done:
21361708Sstevel mutex_enter(&iosram_mutex);
21371708Sstevel
21381708Sstevel /*
21391708Sstevel * Clear the tunnel switch flag on the source and destination
21401708Sstevel * instances.
21411708Sstevel */
21421708Sstevel if (prev_master) {
21431708Sstevel prev_master->state &= ~IOSRAM_STATE_TSWITCH;
21441708Sstevel }
21451708Sstevel softp->state &= ~IOSRAM_STATE_TSWITCH;
21461708Sstevel
21471708Sstevel /*
21481708Sstevel * Since incoming interrupts could get lost during a tunnel switch,
21491708Sstevel * trigger a soft interrupt just in case. No harm other than a bit
21501708Sstevel * of wasted effort will be caused if no interrupts were dropped.
21511708Sstevel */
21521708Sstevel mutex_enter(&softp->intr_mutex);
21531708Sstevel iosram_master->intr_pending = 1;
21541708Sstevel if ((iosram_master->softintr_id != NULL) &&
21551708Sstevel (iosram_master->intr_busy == 0)) {
21561708Sstevel ddi_trigger_softintr(iosram_master->softintr_id);
21571708Sstevel }
21581708Sstevel mutex_exit(&softp->intr_mutex);
21591708Sstevel
21601708Sstevel IOSRAMLOG(1, "TSWTCH: done error:%d iosram_master:%p instance:%d\n",
21611708Sstevel error, iosram_master,
21621708Sstevel (iosram_master) ? iosram_master->instance : -1, NULL);
21631708Sstevel
21641708Sstevel return (error);
21651708Sstevel }
21661708Sstevel
21671708Sstevel
21681708Sstevel /*
21691708Sstevel * iosram_abort_tswitch()
21701708Sstevel * Must be called while holding iosram_mutex.
21711708Sstevel */
21721708Sstevel static void
iosram_abort_tswitch()21731708Sstevel iosram_abort_tswitch()
21741708Sstevel {
21751708Sstevel uint32_t master_valid, new_master_valid;
21761708Sstevel
21771708Sstevel ASSERT(mutex_owned(&iosram_mutex));
21781708Sstevel
21791708Sstevel if ((!iosram_tswitch_active) || iosram_tswitch_aborted) {
21801708Sstevel return;
21811708Sstevel }
21821708Sstevel
21831708Sstevel ASSERT(iosram_master != NULL);
21841708Sstevel
21851708Sstevel IOSRAMLOG(1, "ABORT: iosram_master:%p (%d) iosram_new_master:%p (%d)\n",
21861708Sstevel iosram_master, iosram_master->instance, iosram_new_master,
21871708Sstevel (iosram_new_master == NULL) ? -1 : iosram_new_master->instance);
21881708Sstevel
21891708Sstevel /*
21901708Sstevel * The first call to iosram_force_write() in the middle of tunnel switch
21911708Sstevel * will get here. We lookup IOSRAM VALID location and setup appropriate
21921708Sstevel * master, if one is still valid. We also set iosram_tswitch_aborted to
21931708Sstevel * prevent reentering this code and to catch if the OBP callback thread
21941708Sstevel * somehow resumes.
21951708Sstevel */
21961708Sstevel iosram_tswitch_aborted = 1;
21971708Sstevel
21981708Sstevel if ((iosram_new_master == NULL) ||
21991708Sstevel (iosram_new_master = iosram_master)) {
22001708Sstevel /*
22011708Sstevel * New master hasn't been selected yet, or OBP callback
22021708Sstevel * succeeded and we already selected new IOSRAM as master, but
22031708Sstevel * system crashed in the middle of unmapping previous master or
22041708Sstevel * cleaning up state. Use the existing master.
22051708Sstevel */
22061708Sstevel ASSERT(iosram_master->iosramp != NULL);
22071708Sstevel ASSERT(IOSRAM_GET_HDRFIELD32(iosram_master, status) ==
22081708Sstevel IOSRAM_VALID);
22091708Sstevel IOSRAMLOG(1, "ABORT: master (%d) already determined.\n",
22101708Sstevel iosram_master->instance, NULL, NULL, NULL);
22111708Sstevel
22121708Sstevel return;
22131708Sstevel }
22141708Sstevel
22151708Sstevel /*
22161708Sstevel * System crashed in the middle of tunnel switch and we know that the
22171708Sstevel * new target has not been marked master yet. That means, the old
22181708Sstevel * master should still be mapped. We need to abort the tunnel switch
22191708Sstevel * and setup a valid master, if possible, so that we can write to the
22201708Sstevel * IOSRAM.
22211708Sstevel *
22221708Sstevel * We select a new master based upon the IOSRAM header status fields in
22231708Sstevel * the previous master IOSRAM and the target IOSRAM as follows:
22241708Sstevel *
22251708Sstevel * iosram_master iosram-tswitch
22261708Sstevel * (Prev Master) (New Target) Decision
22271708Sstevel * --------------- --------------- -----------
22281708Sstevel * VALID don't care prev master
22291708Sstevel * INTRANSIT INVALID prev master
22301708Sstevel * INTRANSIT INTRANSIT prev master
22311708Sstevel * INTRANSIT VALID new target
22321708Sstevel * INVALID INVALID shouldn't ever happen
22331708Sstevel * INVALID INTRANSIT shouldn't ever happen
22341708Sstevel * INVALID VALID new target
22351708Sstevel */
22361708Sstevel
22371708Sstevel master_valid = (iosram_master->iosramp != NULL) ?
22381708Sstevel IOSRAM_GET_HDRFIELD32(iosram_master, status) : IOSRAM_INVALID;
22391708Sstevel new_master_valid = (iosram_new_master->iosramp != NULL) ?
22401708Sstevel IOSRAM_GET_HDRFIELD32(iosram_new_master, status) : IOSRAM_INVALID;
22411708Sstevel
22421708Sstevel if (master_valid == IOSRAM_VALID) {
22431708Sstevel /* EMPTY */
22441708Sstevel /*
22451708Sstevel * OBP hasn't been called yet or, if it has, it hasn't started
22461708Sstevel * copying yet. Use the existing master. Note that the new
22471708Sstevel * master may not be mapped yet.
22481708Sstevel */
22491708Sstevel IOSRAMLOG(1, "ABORT: prev master(%d) is VALID\n",
22501708Sstevel iosram_master->instance, NULL, NULL, NULL);
22511708Sstevel } else if (master_valid == IOSRAM_INTRANSIT) {
22521708Sstevel /*
22531708Sstevel * The system crashed after OBP started processing the tunnel
22541708Sstevel * switch but before the iosram driver determined that it was
22551708Sstevel * complete. Use the new master if it has been marked valid,
22561708Sstevel * meaning that OBP finished copying data to it, or the old
22571708Sstevel * master otherwise.
22581708Sstevel */
22591708Sstevel IOSRAMLOG(1, "ABORT: prev master(%d) is INTRANSIT\n",
22601708Sstevel iosram_master->instance, NULL, NULL, NULL);
22611708Sstevel
22621708Sstevel if (new_master_valid == IOSRAM_VALID) {
22631708Sstevel iosram_set_master(iosram_new_master);
22641708Sstevel IOSRAMLOG(1, "ABORT: new master(%d) is VALID\n",
22651708Sstevel iosram_new_master->instance, NULL, NULL,
22661708Sstevel NULL);
22671708Sstevel } else {
2268*11311SSurya.Prakki@Sun.COM (void) prom_starcat_switch_tunnel(iosram_master->portid,
22691708Sstevel OBP_TSWITCH_NOREPLY);
22701708Sstevel
22711708Sstevel IOSRAMLOG(1, "ABORT: new master(%d) is INVALID\n",
22721708Sstevel iosram_new_master->instance, NULL, NULL,
22731708Sstevel NULL);
22741708Sstevel }
22751708Sstevel } else {
22761708Sstevel /*
22771708Sstevel * The system crashed after OBP marked the old master INVALID,
22781708Sstevel * which means the new master is the way to go.
22791708Sstevel */
22801708Sstevel IOSRAMLOG(1, "ABORT: prev master(%d) is INVALID\n",
22811708Sstevel iosram_master->instance, NULL, NULL, NULL);
22821708Sstevel
22831708Sstevel ASSERT(new_master_valid == IOSRAM_VALID);
22841708Sstevel
22851708Sstevel iosram_set_master(iosram_new_master);
22861708Sstevel }
22871708Sstevel
22881708Sstevel IOSRAMLOG(1, "ABORT: Instance %d selected as master\n",
22897656SSherry.Moore@Sun.COM iosram_master->instance, NULL, NULL, NULL);
22901708Sstevel }
22911708Sstevel
22921708Sstevel
22931708Sstevel /*
22941708Sstevel * iosram_switchfrom(instance)
22951708Sstevel * Switch master tunnel away from the specified instance
22961708Sstevel */
22971708Sstevel /*ARGSUSED*/
22981708Sstevel int
iosram_switchfrom(int instance)22991708Sstevel iosram_switchfrom(int instance)
23001708Sstevel {
23011708Sstevel struct iosramsoft *softp;
23021708Sstevel int error = 0;
23031708Sstevel int count;
23041708Sstevel clock_t current_tstamp;
23051708Sstevel clock_t tstamp_interval;
23061708Sstevel struct iosramsoft *last_master = NULL;
23071708Sstevel static int last_master_instance = -1;
23081708Sstevel
23091708Sstevel IOSRAMLOG(1, "SwtchFrom: instance:%d iosram_master:%p (%d)\n",
23101708Sstevel instance, iosram_master,
23111708Sstevel ((iosram_master) ? iosram_master->instance : -1), NULL);
23121708Sstevel
23131708Sstevel mutex_enter(&iosram_mutex);
23141708Sstevel
23151708Sstevel /*
23161708Sstevel * Wait if another tunnel switch is in progress
23171708Sstevel */
23181708Sstevel for (count = 0; iosram_tswitch_active && count < IOSRAM_TSWITCH_RETRY;
23191708Sstevel count++) {
23201708Sstevel iosram_tswitch_wakeup = 1;
23211708Sstevel cv_wait(&iosram_tswitch_wait, &iosram_mutex);
23221708Sstevel }
23231708Sstevel
23241708Sstevel if (iosram_tswitch_active) {
23251708Sstevel mutex_exit(&iosram_mutex);
23261708Sstevel return (EAGAIN);
23271708Sstevel }
23281708Sstevel
23291708Sstevel /*
23301708Sstevel * Check if the specified instance holds the tunnel. If not,
23311708Sstevel * then we are done.
23321708Sstevel */
23331708Sstevel if ((iosram_master == NULL) || (iosram_master->instance != instance)) {
23341708Sstevel mutex_exit(&iosram_mutex);
23351708Sstevel return (0);
23361708Sstevel }
23371708Sstevel
23381708Sstevel /*
23391708Sstevel * Before beginning the tunnel switch process, wait for any outstanding
23401708Sstevel * read/write activity to complete.
23411708Sstevel */
23421708Sstevel iosram_tswitch_active = 1;
23431708Sstevel while (iosram_rw_active) {
23441708Sstevel iosram_rw_wakeup = 1;
23451708Sstevel cv_wait(&iosram_rw_wait, &iosram_mutex);
23461708Sstevel }
23471708Sstevel
23481708Sstevel /*
23491708Sstevel * If a previous tunnel switch just completed, we have to make sure
23501708Sstevel * HWAD has enough time to find the new tunnel before we switch
23511708Sstevel * away from it. Otherwise, OBP's mailbox message to OSD will never
23521708Sstevel * get through. Just to be paranoid about synchronization of lbolt
23531708Sstevel * across different CPUs, make sure the current attempt isn't noted
23541708Sstevel * as starting _before_ the last tunnel switch completed.
23551708Sstevel */
23561708Sstevel current_tstamp = ddi_get_lbolt();
23571708Sstevel if (current_tstamp > iosram_tswitch_tstamp) {
23581708Sstevel tstamp_interval = current_tstamp - iosram_tswitch_tstamp;
23591708Sstevel } else {
23601708Sstevel tstamp_interval = 0;
23611708Sstevel }
23621708Sstevel if (drv_hztousec(tstamp_interval) < IOSRAM_TSWITCH_DELAY_US) {
23631708Sstevel mutex_exit(&iosram_mutex);
23641708Sstevel delay(drv_usectohz(IOSRAM_TSWITCH_DELAY_US) - tstamp_interval);
23651708Sstevel mutex_enter(&iosram_mutex);
23661708Sstevel }
23671708Sstevel
23681708Sstevel /*
23691708Sstevel * The specified instance holds the tunnel. We need to move it to some
23701708Sstevel * other IOSRAM. Try out all possible IOSRAMs listed in
23711708Sstevel * iosram_instances. For now, we always search from the first entry.
23721708Sstevel * In future, it may be desirable to start where we left off.
23731708Sstevel */
23741708Sstevel for (softp = iosram_instances; softp != NULL; softp = softp->next) {
23751708Sstevel if (iosram_tswitch_aborted) {
23761708Sstevel break;
23771708Sstevel }
23781708Sstevel
23791708Sstevel /* we can't switch _to_ the instance we're switching _from_ */
23801708Sstevel if (softp->instance == instance) {
23811708Sstevel continue;
23821708Sstevel }
23831708Sstevel
23841708Sstevel /* skip over instances being detached */
23851708Sstevel if (softp->state & IOSRAM_STATE_DETACH) {
23861708Sstevel continue;
23871708Sstevel }
23881708Sstevel
23891708Sstevel /*
23901708Sstevel * Try to avoid reverting to the last instance we switched away
23911708Sstevel * from, as we expect that one to be detached eventually. Keep
23921708Sstevel * track of it, though, so we can go ahead and try switching to
23931708Sstevel * it if no other viable candidates are found.
23941708Sstevel */
23951708Sstevel if (softp->instance == last_master_instance) {
23961708Sstevel last_master = softp;
23971708Sstevel continue;
23981708Sstevel }
23991708Sstevel
24001708Sstevel /*
24011708Sstevel * Do the tunnel switch. If successful, record the instance of
24021708Sstevel * the master we just left behind so we can try to avoid
24031708Sstevel * reverting to it next time.
24041708Sstevel */
24051708Sstevel if (iosram_switch_tunnel(softp) == 0) {
24061708Sstevel last_master_instance = instance;
24071708Sstevel break;
24081708Sstevel }
24091708Sstevel }
24101708Sstevel
24111708Sstevel /*
24121708Sstevel * If we failed to switch the tunnel, but we skipped over an instance
24131708Sstevel * that had previously been switched out of because we expected it to be
24141708Sstevel * detached, go ahead and try it anyway (unless the tswitch was aborted
24151708Sstevel * or the instance we skipped is finally being detached).
24161708Sstevel */
24171708Sstevel if ((softp == NULL) && (last_master != NULL) &&
24181708Sstevel !iosram_tswitch_aborted &&
24191708Sstevel !(last_master->state & IOSRAM_STATE_DETACH)) {
24201708Sstevel if (iosram_switch_tunnel(last_master) == 0) {
24211708Sstevel softp = last_master;
24221708Sstevel last_master_instance = instance;
24231708Sstevel }
24241708Sstevel }
24251708Sstevel
24261708Sstevel if ((softp == NULL) || (iosram_tswitch_aborted)) {
24271708Sstevel error = EIO;
24281708Sstevel }
24291708Sstevel
24301708Sstevel /*
24311708Sstevel * If there are additional tunnel switches queued up waiting for this
24321708Sstevel * one to complete, wake them up.
24331708Sstevel */
24341708Sstevel if (iosram_tswitch_wakeup) {
24351708Sstevel iosram_tswitch_wakeup = 0;
24361708Sstevel cv_broadcast(&iosram_tswitch_wait);
24371708Sstevel }
24381708Sstevel iosram_tswitch_active = 0;
24391708Sstevel mutex_exit(&iosram_mutex);
24401708Sstevel return (error);
24411708Sstevel }
24421708Sstevel
24431708Sstevel
24441708Sstevel /*
24451708Sstevel * iosram_tunnel_capable(softp)
24461708Sstevel * Check if this IOSRAM instance is tunnel-capable by looing at
24471708Sstevel * "tunnel-capable" property.
24481708Sstevel */
24491708Sstevel static int
iosram_tunnel_capable(struct iosramsoft * softp)24501708Sstevel iosram_tunnel_capable(struct iosramsoft *softp)
24511708Sstevel {
24521708Sstevel int proplen;
24531708Sstevel int tunnel_capable;
24541708Sstevel
24551708Sstevel /*
24561708Sstevel * Look up IOSRAM_TUNNELOK_PROP property, if any.
24571708Sstevel */
24581708Sstevel proplen = sizeof (tunnel_capable);
24591708Sstevel if (ddi_getlongprop_buf(DDI_DEV_T_ANY, softp->dip,
24601708Sstevel DDI_PROP_DONTPASS, IOSRAM_TUNNELOK_PROP, (caddr_t)&tunnel_capable,
24611708Sstevel &proplen) != DDI_PROP_SUCCESS) {
24621708Sstevel tunnel_capable = 0;
24631708Sstevel }
24641708Sstevel return (tunnel_capable);
24651708Sstevel }
24661708Sstevel
24671708Sstevel
24681708Sstevel static int
iosram_sbbc_setup_map(struct iosramsoft * softp)24691708Sstevel iosram_sbbc_setup_map(struct iosramsoft *softp)
24701708Sstevel {
24711708Sstevel int rv;
24721708Sstevel struct ddi_device_acc_attr attr;
24731708Sstevel dev_info_t *dip = softp->dip;
24741708Sstevel uint32_t sema_val;
24751708Sstevel
24761708Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
24771708Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
24781708Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
24791708Sstevel
24801708Sstevel mutex_enter(&iosram_mutex);
24811708Sstevel mutex_enter(&softp->intr_mutex);
24821708Sstevel
24831708Sstevel /*
24841708Sstevel * Map SBBC region in
24851708Sstevel */
24861708Sstevel if ((rv = ddi_regs_map_setup(dip, IOSRAM_SBBC_MAP_INDEX,
24871708Sstevel (caddr_t *)&softp->sbbc_region,
24881708Sstevel IOSRAM_SBBC_MAP_OFFSET, sizeof (iosram_sbbc_region_t),
24891708Sstevel &attr, &softp->sbbc_handle)) != DDI_SUCCESS) {
24901708Sstevel DPRINTF(1, ("Failed to map SBBC region.\n"));
24911708Sstevel mutex_exit(&softp->intr_mutex);
24921708Sstevel mutex_exit(&iosram_mutex);
24931708Sstevel return (rv);
24941708Sstevel }
24951708Sstevel
24961708Sstevel /*
24971708Sstevel * Disable SBBC interrupts. SBBC interrupts are enabled
24981708Sstevel * once the interrupt handler is registered.
24991708Sstevel */
25001708Sstevel ddi_put32(softp->sbbc_handle,
25011708Sstevel &(softp->sbbc_region->int_enable.reg), 0x0);
25021708Sstevel
25031708Sstevel /*
25041708Sstevel * Clear hardware semaphore value if appropriate.
25051708Sstevel * When the first SBBC is mapped in by the IOSRAM driver,
25061708Sstevel * the value of the semaphore should be initialized only
25071708Sstevel * if it is not held by SMS. For subsequent SBBC's, the
25081708Sstevel * semaphore will be always initialized.
25091708Sstevel */
25101708Sstevel sema_val = IOSRAM_SEMA_RD(softp);
25111708Sstevel
25121708Sstevel if (!iosram_master) {
25131708Sstevel /* the first SBBC is being mapped in */
25141708Sstevel if (!(IOSRAM_SEMA_IS_HELD(sema_val) &&
25151708Sstevel IOSRAM_SEMA_GET_IDX(sema_val) == IOSRAM_SEMA_SMS_IDX)) {
25161708Sstevel /* not held by SMS, we clear the semaphore */
25171708Sstevel IOSRAM_SEMA_WR(softp, 0);
25181708Sstevel }
25191708Sstevel } else {
25201708Sstevel /* not the first SBBC, we clear the semaphore */
25211708Sstevel IOSRAM_SEMA_WR(softp, 0);
25221708Sstevel }
25231708Sstevel
25241708Sstevel mutex_exit(&softp->intr_mutex);
25251708Sstevel mutex_exit(&iosram_mutex);
25261708Sstevel return (0);
25271708Sstevel }
25281708Sstevel
25291708Sstevel
25301708Sstevel static int
iosram_setup_map(struct iosramsoft * softp)25311708Sstevel iosram_setup_map(struct iosramsoft *softp)
25321708Sstevel {
25331708Sstevel int instance = softp->instance;
25341708Sstevel dev_info_t *dip = softp->dip;
25351708Sstevel int portid;
25361708Sstevel int proplen;
25371708Sstevel caddr_t propvalue;
25381708Sstevel struct ddi_device_acc_attr attr;
25391708Sstevel
25401708Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
25411708Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
25421708Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
25431708Sstevel
25441708Sstevel /*
25451708Sstevel * Lookup IOSRAM_REG_PROP property to find out our IOSRAM length
25461708Sstevel */
25471708Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
25481708Sstevel DDI_PROP_DONTPASS, IOSRAM_REG_PROP, (caddr_t)&propvalue,
25491708Sstevel &proplen) != DDI_PROP_SUCCESS) {
25501708Sstevel cmn_err(CE_WARN, "iosram(%d): can't find register property.\n",
25511708Sstevel instance);
25521708Sstevel return (DDI_FAILURE);
25531708Sstevel } else {
25541708Sstevel iosram_reg_t *regprop = (iosram_reg_t *)propvalue;
25551708Sstevel
25561708Sstevel DPRINTF(1, ("SetupMap(%d): Got reg prop: %x %x %x\n",
25571708Sstevel instance, regprop->addr_hi,
25581708Sstevel regprop->addr_lo, regprop->size));
25591708Sstevel
25601708Sstevel softp->iosramlen = regprop->size;
25611708Sstevel
25621708Sstevel kmem_free(propvalue, proplen);
25631708Sstevel }
25641708Sstevel DPRINTF(1, ("SetupMap(%d): IOSRAM length: 0x%x\n", instance,
25651708Sstevel softp->iosramlen));
25661708Sstevel softp->handle = NULL;
25671708Sstevel
25681708Sstevel /*
25691708Sstevel * To minimize boot time, we map the entire IOSRAM as opposed to
25701708Sstevel * mapping individual chunk via ddi_regs_map_setup() call.
25711708Sstevel */
25721708Sstevel if (ddi_regs_map_setup(dip, 0, (caddr_t *)&softp->iosramp,
25731708Sstevel 0x0, softp->iosramlen, &attr, &softp->handle) != DDI_SUCCESS) {
25741708Sstevel cmn_err(CE_WARN, "iosram(%d): failed to map IOSRAM len:%x\n",
25751708Sstevel instance, softp->iosramlen);
25761708Sstevel iosram_remove_map(softp);
25771708Sstevel return (DDI_FAILURE);
25781708Sstevel }
25791708Sstevel
25801708Sstevel /*
25811708Sstevel * Lookup PORTID property on my parent hierarchy
25821708Sstevel */
25831708Sstevel proplen = sizeof (portid);
25841708Sstevel if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
25851708Sstevel 0, IOSRAM_PORTID_PROP, (caddr_t)&portid,
25861708Sstevel &proplen) != DDI_PROP_SUCCESS) {
25871708Sstevel cmn_err(CE_WARN, "iosram(%d): can't find portid property.\n",
25881708Sstevel instance);
25891708Sstevel iosram_remove_map(softp);
25901708Sstevel return (DDI_FAILURE);
25911708Sstevel }
25921708Sstevel softp->portid = portid;
25931708Sstevel
25941708Sstevel if (iosram_sbbc_setup_map(softp) != DDI_SUCCESS) {
25951708Sstevel cmn_err(CE_WARN, "iosram(%d): can't map SBBC region.\n",
25961708Sstevel instance);
25971708Sstevel iosram_remove_map(softp);
25981708Sstevel return (DDI_FAILURE);
25991708Sstevel }
26001708Sstevel
26011708Sstevel mutex_enter(&iosram_mutex);
26021708Sstevel softp->state |= IOSRAM_STATE_MAPPED;
26031708Sstevel mutex_exit(&iosram_mutex);
26041708Sstevel
26051708Sstevel return (DDI_SUCCESS);
26061708Sstevel }
26071708Sstevel
26081708Sstevel
26091708Sstevel static void
iosram_remove_map(struct iosramsoft * softp)26101708Sstevel iosram_remove_map(struct iosramsoft *softp)
26111708Sstevel {
26121708Sstevel mutex_enter(&iosram_mutex);
26131708Sstevel
26141708Sstevel ASSERT((softp->state & IOSRAM_STATE_MASTER) == 0);
26151708Sstevel
26161708Sstevel if (softp->handle) {
26171708Sstevel ddi_regs_map_free(&softp->handle);
26181708Sstevel softp->handle = NULL;
26191708Sstevel }
26201708Sstevel softp->iosramp = NULL;
26211708Sstevel
26221708Sstevel /*
26231708Sstevel * Umap SBBC registers region. Shared with handler for SBBC
26241708Sstevel * interrupts, take intr_mutex.
26251708Sstevel */
26261708Sstevel mutex_enter(&softp->intr_mutex);
26271708Sstevel if (softp->sbbc_region) {
26281708Sstevel ddi_regs_map_free(&softp->sbbc_handle);
26291708Sstevel softp->sbbc_region = NULL;
26301708Sstevel }
26311708Sstevel mutex_exit(&softp->intr_mutex);
26321708Sstevel
26331708Sstevel softp->state &= ~IOSRAM_STATE_MAPPED;
26341708Sstevel
26351708Sstevel mutex_exit(&iosram_mutex);
26361708Sstevel }
26371708Sstevel
26381708Sstevel
26391708Sstevel /*
26401708Sstevel * iosram_is_chosen(struct iosramsoft *softp)
26411708Sstevel *
26421708Sstevel * Looks up "chosen" node property to
26431708Sstevel * determine if it is the chosen IOSRAM.
26441708Sstevel */
26451708Sstevel static int
iosram_is_chosen(struct iosramsoft * softp)26461708Sstevel iosram_is_chosen(struct iosramsoft *softp)
26471708Sstevel {
26481708Sstevel char chosen_iosram[MAXNAMELEN];
26491708Sstevel char pn[MAXNAMELEN];
26501708Sstevel int nodeid;
26511708Sstevel int chosen;
26521708Sstevel pnode_t dnode;
26531708Sstevel
26541708Sstevel /*
26551708Sstevel * Get /chosen node info. prom interface will handle errors.
26561708Sstevel */
26571708Sstevel dnode = prom_chosennode();
26581708Sstevel
26591708Sstevel /*
26601708Sstevel * Look for the "iosram" property on the chosen node with a prom
26611708Sstevel * interface as ddi_find_devinfo() couldn't be used (calls
26621708Sstevel * ddi_walk_devs() that creates one extra lock on the device tree).
26631708Sstevel */
26641708Sstevel if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) {
26651708Sstevel /*
26661708Sstevel * Can't find IOSRAM_CHOSEN_PROP property under chosen node
26671708Sstevel */
26681708Sstevel cmn_err(CE_WARN,
26691708Sstevel "iosram(%d): can't find chosen iosram property\n",
26701708Sstevel softp->instance);
26711708Sstevel return (0);
26721708Sstevel }
26731708Sstevel
26741708Sstevel DPRINTF(1, ("iosram(%d): Got '%x' for chosen '%s' property\n",
26751708Sstevel softp->instance, nodeid, IOSRAM_CHOSEN_PROP));
26761708Sstevel
26771708Sstevel /*
26781708Sstevel * get the full OBP pathname of this node
26791708Sstevel */
26801708Sstevel if (prom_phandle_to_path((phandle_t)nodeid, chosen_iosram,
26811708Sstevel sizeof (chosen_iosram)) < 0) {
26821708Sstevel cmn_err(CE_NOTE, "prom_phandle_to_path(%x) failed\n", nodeid);
26831708Sstevel return (0);
26841708Sstevel }
26851708Sstevel DPRINTF(1, ("iosram(%d): prom_phandle_to_path(%x) is '%s'\n",
26861708Sstevel softp->instance, nodeid, chosen_iosram));
26871708Sstevel
26881708Sstevel (void) ddi_pathname(softp->dip, pn);
26891708Sstevel DPRINTF(1, ("iosram(%d): ddi_pathname(%p) is '%s'\n",
2690*11311SSurya.Prakki@Sun.COM softp->instance, (void *)softp->dip, pn));
26911708Sstevel
26921708Sstevel chosen = (strcmp(chosen_iosram, pn) == 0) ? 1 : 0;
26931708Sstevel DPRINTF(1, ("iosram(%d): ... %s\n", softp->instance,
26941708Sstevel chosen ? "MASTER" : "SLAVE"));
26951708Sstevel IOSRAMLOG(1, "iosram(%d): ... %s\n", softp->instance,
26961708Sstevel (chosen ? "MASTER" : "SLAVE"), NULL, NULL);
26971708Sstevel
26981708Sstevel return (chosen);
26991708Sstevel }
27001708Sstevel
27011708Sstevel
27021708Sstevel /*
27031708Sstevel * iosram_set_master(struct iosramsoft *softp)
27041708Sstevel *
27051708Sstevel * Set master tunnel to the specified IOSRAM
27061708Sstevel * Must be called while holding iosram_mutex.
27071708Sstevel */
27081708Sstevel static void
iosram_set_master(struct iosramsoft * softp)27091708Sstevel iosram_set_master(struct iosramsoft *softp)
27101708Sstevel {
27111708Sstevel ASSERT(mutex_owned(&iosram_mutex));
27121708Sstevel ASSERT(softp != NULL);
27131708Sstevel ASSERT(softp->state & IOSRAM_STATE_MAPPED);
27141708Sstevel ASSERT(IOSRAM_GET_HDRFIELD32(softp, status) == IOSRAM_VALID);
27151708Sstevel
27161708Sstevel /*
27171708Sstevel * Clear MASTER flag on any previous IOSRAM master, if any
27181708Sstevel */
27191708Sstevel if (iosram_master && (iosram_master != softp)) {
27201708Sstevel iosram_master->state &= ~IOSRAM_STATE_MASTER;
27211708Sstevel }
27221708Sstevel
27231708Sstevel /*
27241708Sstevel * Setup new IOSRAM master
27251708Sstevel */
27261708Sstevel iosram_update_addrs(softp);
27271708Sstevel iosram_handle = softp->handle;
27281708Sstevel softp->state |= IOSRAM_STATE_MASTER;
27291708Sstevel softp->tswitch_ok++;
27301708Sstevel iosram_master = softp;
27311708Sstevel
27321708Sstevel IOSRAMLOG(1, "SETMASTER: softp:%p instance:%d\n", softp,
27331708Sstevel softp->instance, NULL, NULL);
27341708Sstevel }
27351708Sstevel
27361708Sstevel
27371708Sstevel /*
27381708Sstevel * iosram_read_toc()
27391708Sstevel *
27401708Sstevel * Read the TOC from an IOSRAM instance that has been mapped in.
27411708Sstevel * If the TOC is flawed or the IOSRAM isn't valid, return an error.
27421708Sstevel */
27431708Sstevel static int
iosram_read_toc(struct iosramsoft * softp)27441708Sstevel iosram_read_toc(struct iosramsoft *softp)
27451708Sstevel {
27461708Sstevel int i;
27471708Sstevel int instance = softp->instance;
27481708Sstevel uint8_t *toc_entryp;
27491708Sstevel iosram_flags_t *flagsp = NULL;
27501708Sstevel int new_nchunks;
27511708Sstevel iosram_chunk_t *new_chunks;
27521708Sstevel iosram_chunk_t *chunkp;
27531708Sstevel iosram_chunk_t *old_chunkp;
27541708Sstevel iosram_toc_entry_t index;
27551708Sstevel
27561708Sstevel /*
27571708Sstevel * Never try to read the TOC out of an unmapped IOSRAM.
27581708Sstevel */
27591708Sstevel ASSERT(softp->state & IOSRAM_STATE_MAPPED);
27601708Sstevel
27611708Sstevel mutex_enter(&iosram_mutex);
27621708Sstevel
27631708Sstevel /*
27641708Sstevel * Check to make sure this IOSRAM is marked valid. Return
27651708Sstevel * an error if it isn't.
27661708Sstevel */
27671708Sstevel if (IOSRAM_GET_HDRFIELD32(softp, status) != IOSRAM_VALID) {
27681708Sstevel DPRINTF(1, ("iosram_read_toc(%d): IOSRAM not flagged valid\n",
27691708Sstevel instance));
27701708Sstevel mutex_exit(&iosram_mutex);
27711708Sstevel return (EINVAL);
27721708Sstevel }
27731708Sstevel
27741708Sstevel /*
27751708Sstevel * Get the location of the TOC.
27761708Sstevel */
27771708Sstevel toc_entryp = softp->iosramp + IOSRAM_GET_HDRFIELD32(softp, toc_offset);
27781708Sstevel
27791708Sstevel /*
27801708Sstevel * Read the index entry from the TOC and make sure it looks correct.
27811708Sstevel */
27821708Sstevel ddi_rep_get8(softp->handle, (uint8_t *)&index, toc_entryp,
27831708Sstevel sizeof (iosram_toc_entry_t), DDI_DEV_AUTOINCR);
27841708Sstevel if ((index.key != IOSRAM_INDEX_KEY) ||
27851708Sstevel (index.off != IOSRAM_INDEX_OFF)) {
27861708Sstevel cmn_err(CE_WARN, "iosram(%d): invalid TOC index.\n", instance);
27871708Sstevel mutex_exit(&iosram_mutex);
27881708Sstevel return (EINVAL);
27891708Sstevel }
27901708Sstevel
27911708Sstevel /*
27921708Sstevel * Allocate storage for the new chunks array and initialize it with data
27931708Sstevel * from the TOC and callback data from the corresponding old chunk, if
27941708Sstevel * it exists.
27951708Sstevel */
27961708Sstevel new_nchunks = index.len - 1;
27971708Sstevel new_chunks = (iosram_chunk_t *)kmem_zalloc(new_nchunks *
27981708Sstevel sizeof (iosram_chunk_t), KM_SLEEP);
27991708Sstevel for (i = 0, chunkp = new_chunks; i < new_nchunks; i++, chunkp++) {
28001708Sstevel toc_entryp += sizeof (iosram_toc_entry_t);
28011708Sstevel ddi_rep_get8(softp->handle, (uint8_t *)&(chunkp->toc_data),
28021708Sstevel toc_entryp, sizeof (iosram_toc_entry_t), DDI_DEV_AUTOINCR);
28031708Sstevel chunkp->hash = NULL;
28041708Sstevel if ((chunkp->toc_data.off < softp->iosramlen) &&
28051708Sstevel (chunkp->toc_data.len <= softp->iosramlen) &&
28061708Sstevel ((chunkp->toc_data.off + chunkp->toc_data.len) <=
28071708Sstevel softp->iosramlen)) {
28081708Sstevel chunkp->basep = softp->iosramp + chunkp->toc_data.off;
28091708Sstevel DPRINTF(1,
2810*11311SSurya.Prakki@Sun.COM ("iosram_read_toc(%d): k:%x o:%x l:%x p:%p\n",
28111708Sstevel instance, chunkp->toc_data.key,
28121708Sstevel chunkp->toc_data.off, chunkp->toc_data.len,
2813*11311SSurya.Prakki@Sun.COM (void *)chunkp->basep));
28141708Sstevel } else {
28151708Sstevel cmn_err(CE_WARN, "iosram(%d): TOC entry %d"
28161708Sstevel "out of range... off:%x len:%x\n",
28171708Sstevel instance, i + 1, chunkp->toc_data.off,
28181708Sstevel chunkp->toc_data.len);
28191708Sstevel kmem_free(new_chunks, new_nchunks *
28201708Sstevel sizeof (iosram_chunk_t));
28211708Sstevel mutex_exit(&iosram_mutex);
28221708Sstevel return (EINVAL);
28231708Sstevel }
28241708Sstevel
28251708Sstevel /*
28261708Sstevel * Note the existence of the flags chunk, which is required in
28271708Sstevel * a correct TOC.
28281708Sstevel */
28291708Sstevel if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) {
28301708Sstevel flagsp = (iosram_flags_t *)chunkp->basep;
28311708Sstevel }
28321708Sstevel
28331708Sstevel /*
28341708Sstevel * If there was an entry for this chunk in the old list, copy
28351708Sstevel * the callback data from old to new storage.
28361708Sstevel */
28371708Sstevel if ((nchunks > 0) &&
28381708Sstevel ((old_chunkp = iosram_find_chunk(chunkp->toc_data.key)) !=
28391708Sstevel NULL)) {
28401708Sstevel bcopy(&(old_chunkp->cback), &(chunkp->cback),
28411708Sstevel sizeof (iosram_cback_t));
28421708Sstevel }
28431708Sstevel }
28441708Sstevel /*
28451708Sstevel * The TOC is malformed if there is no entry for the flags chunk.
28461708Sstevel */
28471708Sstevel if (flagsp == NULL) {
28481708Sstevel kmem_free(new_chunks, new_nchunks * sizeof (iosram_chunk_t));
28491708Sstevel mutex_exit(&iosram_mutex);
28501708Sstevel return (EINVAL);
28511708Sstevel }
28521708Sstevel
28531708Sstevel /*
28541708Sstevel * Free any memory that is no longer needed and install the new data
28551708Sstevel * as current data.
28561708Sstevel */
28571708Sstevel if (chunks != NULL) {
28581708Sstevel kmem_free(chunks, nchunks * sizeof (iosram_chunk_t));
28591708Sstevel }
28601708Sstevel chunks = new_chunks;
28611708Sstevel nchunks = new_nchunks;
28621708Sstevel iosram_init_hashtab();
28631708Sstevel
28641708Sstevel mutex_exit(&iosram_mutex);
28651708Sstevel return (0);
28661708Sstevel }
28671708Sstevel
28681708Sstevel
28691708Sstevel /*
28701708Sstevel * iosram_init_hashtab()
28711708Sstevel *
28721708Sstevel * Initialize the hash table and populate it with the IOSRAM
28731708Sstevel * chunks previously read from the TOC. The caller must hold the
28741708Sstevel * ioram_mutex lock.
28751708Sstevel */
28761708Sstevel static void
iosram_init_hashtab(void)28771708Sstevel iosram_init_hashtab(void)
28781708Sstevel {
28791708Sstevel int i, bucket;
28801708Sstevel iosram_chunk_t *chunkp;
28811708Sstevel
28821708Sstevel ASSERT(mutex_owned(&iosram_mutex));
28831708Sstevel
28841708Sstevel for (i = 0; i < IOSRAM_HASHSZ; i++) {
28851708Sstevel iosram_hashtab[i] = NULL;
28861708Sstevel }
28871708Sstevel
28881708Sstevel if (chunks) {
28891708Sstevel for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
28901708Sstevel /*
28911708Sstevel * Hide the flags chunk by leaving it out of the hash
28921708Sstevel * table.
28931708Sstevel */
28941708Sstevel if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) {
28951708Sstevel continue;
28961708Sstevel }
28971708Sstevel
28981708Sstevel /*
28991708Sstevel * Add the current chunk to the hash table.
29001708Sstevel */
29011708Sstevel bucket = IOSRAM_HASH(chunkp->toc_data.key);
29021708Sstevel chunkp->hash = iosram_hashtab[bucket];
29031708Sstevel iosram_hashtab[bucket] = chunkp;
29041708Sstevel }
29051708Sstevel }
29061708Sstevel }
29071708Sstevel
29081708Sstevel
29091708Sstevel /*
29101708Sstevel * iosram_update_addrs()
29111708Sstevel *
29121708Sstevel * Process the chunk list, updating each chunk's basep, which is a pointer
29131708Sstevel * to the beginning of the chunk's memory in kvaddr space. Record the
29141708Sstevel * basep value of the flags chunk to speed up flag access. The caller
29151708Sstevel * must hold the iosram_mutex lock.
29161708Sstevel */
29171708Sstevel static void
iosram_update_addrs(struct iosramsoft * softp)29181708Sstevel iosram_update_addrs(struct iosramsoft *softp)
29191708Sstevel {
29201708Sstevel int i;
29211708Sstevel iosram_flags_t *flagsp;
29221708Sstevel iosram_chunk_t *chunkp;
29231708Sstevel
29241708Sstevel ASSERT(mutex_owned(&iosram_mutex));
29251708Sstevel
29261708Sstevel /*
29271708Sstevel * First go through all of the chunks updating their base pointers and
29281708Sstevel * looking for the flags chunk.
29291708Sstevel */
29301708Sstevel for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
29311708Sstevel chunkp->basep = softp->iosramp + chunkp->toc_data.off;
29321708Sstevel if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) {
29331708Sstevel flagsp = (iosram_flags_t *)(chunkp->basep);
29341708Sstevel DPRINTF(1,
29351708Sstevel ("iosram_update_addrs flags: o:0x%08x p:%p",
2936*11311SSurya.Prakki@Sun.COM chunkp->toc_data.off, (void *)flagsp));
29371708Sstevel }
29381708Sstevel }
29391708Sstevel
29401708Sstevel /*
29411708Sstevel * Now, go through and update each chunk's flags pointer. This can't be
29421708Sstevel * done in the first loop because we don't have the address of the flags
29431708Sstevel * chunk yet.
29441708Sstevel */
29451708Sstevel for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
29461708Sstevel chunkp->flagsp = flagsp++;
29471708Sstevel DPRINTF(1, ("iosram_update_addrs: k:0x%x f:%p\n",
2948*11311SSurya.Prakki@Sun.COM chunkp->toc_data.key, (void *)chunkp->flagsp));
29491708Sstevel }
29501708Sstevel }
29511708Sstevel
29521708Sstevel /*
29531708Sstevel * iosram_find_chunk(key)
29541708Sstevel *
29551708Sstevel * Return a pointer to iosram_chunk structure corresponding to the
29561708Sstevel * "key" IOSRAM chunk. The caller must hold the iosram_mutex lock.
29571708Sstevel */
29581708Sstevel static iosram_chunk_t *
iosram_find_chunk(uint32_t key)29591708Sstevel iosram_find_chunk(uint32_t key)
29601708Sstevel {
29611708Sstevel iosram_chunk_t *chunkp;
29621708Sstevel int index = IOSRAM_HASH(key);
29631708Sstevel
29641708Sstevel ASSERT(mutex_owned(&iosram_mutex));
29651708Sstevel
29661708Sstevel for (chunkp = iosram_hashtab[index]; chunkp; chunkp = chunkp->hash) {
29671708Sstevel if (chunkp->toc_data.key == key) {
29681708Sstevel break;
29691708Sstevel }
29701708Sstevel }
29711708Sstevel
29721708Sstevel return (chunkp);
29731708Sstevel }
29741708Sstevel
29751708Sstevel
29761708Sstevel /*
29771708Sstevel * iosram_add_intr(iosramsoft_t *)
29781708Sstevel */
29791708Sstevel static int
iosram_add_intr(iosramsoft_t * softp)29801708Sstevel iosram_add_intr(iosramsoft_t *softp)
29811708Sstevel {
29821708Sstevel IOSRAMLOG(2, "ADDINTR: softp:%p instance:%d\n",
29831708Sstevel softp, softp->instance, NULL, NULL);
29841708Sstevel
29851708Sstevel if (ddi_add_softintr(softp->dip, DDI_SOFTINT_MED,
29861708Sstevel &softp->softintr_id, &softp->soft_iblk, NULL,
29871708Sstevel iosram_softintr, (caddr_t)softp) != DDI_SUCCESS) {
29881708Sstevel cmn_err(CE_WARN,
29891708Sstevel "iosram(%d): Can't register softintr.\n",
29901708Sstevel softp->instance);
29911708Sstevel return (DDI_FAILURE);
29921708Sstevel }
29931708Sstevel
29941708Sstevel if (ddi_add_intr(softp->dip, 0, &softp->real_iblk, NULL,
29951708Sstevel iosram_intr, (caddr_t)softp) != DDI_SUCCESS) {
29961708Sstevel cmn_err(CE_WARN,
29971708Sstevel "iosram(%d): Can't register intr"
29981708Sstevel " handler.\n", softp->instance);
29991708Sstevel ddi_remove_softintr(softp->softintr_id);
30001708Sstevel return (DDI_FAILURE);
30011708Sstevel }
30021708Sstevel
30031708Sstevel /*
30041708Sstevel * Enable SBBC interrupts
30051708Sstevel */
30061708Sstevel ddi_put32(softp->sbbc_handle, &(softp->sbbc_region->int_enable.reg),
30071708Sstevel IOSRAM_SBBC_INT0|IOSRAM_SBBC_INT1);
30081708Sstevel
30091708Sstevel return (DDI_SUCCESS);
30101708Sstevel }
30111708Sstevel
30121708Sstevel
30131708Sstevel /*
30141708Sstevel * iosram_remove_intr(iosramsoft_t *)
30151708Sstevel */
30161708Sstevel static int
iosram_remove_intr(iosramsoft_t * softp)30171708Sstevel iosram_remove_intr(iosramsoft_t *softp)
30181708Sstevel {
30191708Sstevel IOSRAMLOG(2, "REMINTR: softp:%p instance:%d\n",
30201708Sstevel softp, softp->instance, NULL, NULL);
30211708Sstevel
30221708Sstevel /*
30231708Sstevel * Disable SBBC interrupts if SBBC is mapped in
30241708Sstevel */
30251708Sstevel if (softp->sbbc_region) {
30261708Sstevel ddi_put32(softp->sbbc_handle,
30271708Sstevel &(softp->sbbc_region->int_enable.reg), 0);
30281708Sstevel }
30291708Sstevel
30301708Sstevel /*
30311708Sstevel * Remove SBBC interrupt handler
30321708Sstevel */
30331708Sstevel ddi_remove_intr(softp->dip, 0, softp->real_iblk);
30341708Sstevel
30351708Sstevel /*
30361708Sstevel * Remove soft interrupt handler
30371708Sstevel */
30381708Sstevel mutex_enter(&iosram_mutex);
30391708Sstevel if (softp->softintr_id != NULL) {
30401708Sstevel ddi_remove_softintr(softp->softintr_id);
30411708Sstevel softp->softintr_id = NULL;
30421708Sstevel }
30431708Sstevel mutex_exit(&iosram_mutex);
30441708Sstevel
30451708Sstevel return (0);
30461708Sstevel }
30471708Sstevel
30481708Sstevel
30491708Sstevel /*
30501708Sstevel * iosram_add_instance(iosramsoft_t *)
30511708Sstevel * Must be called while holding iosram_mutex
30521708Sstevel */
30531708Sstevel static void
iosram_add_instance(iosramsoft_t * new_softp)30541708Sstevel iosram_add_instance(iosramsoft_t *new_softp)
30551708Sstevel {
30561708Sstevel #ifdef DEBUG
30571708Sstevel int instance = new_softp->instance;
30581708Sstevel iosramsoft_t *softp;
30591708Sstevel #endif
30601708Sstevel
30611708Sstevel ASSERT(mutex_owned(&iosram_mutex));
30621708Sstevel
30631708Sstevel #if defined(DEBUG)
30641708Sstevel /* Verify that this instance is not in the list */
30651708Sstevel for (softp = iosram_instances; softp != NULL; softp = softp->next) {
30661708Sstevel ASSERT(softp->instance != instance);
30671708Sstevel }
30681708Sstevel #endif
30691708Sstevel
30701708Sstevel /*
30711708Sstevel * Add this instance to the list
30721708Sstevel */
30731708Sstevel if (iosram_instances != NULL) {
30741708Sstevel iosram_instances->prev = new_softp;
30751708Sstevel }
30761708Sstevel new_softp->next = iosram_instances;
30771708Sstevel new_softp->prev = NULL;
30781708Sstevel iosram_instances = new_softp;
30791708Sstevel }
30801708Sstevel
30811708Sstevel
30821708Sstevel /*
30831708Sstevel * iosram_remove_instance(int instance)
30841708Sstevel * Must be called while holding iosram_mutex
30851708Sstevel */
30861708Sstevel static void
iosram_remove_instance(int instance)30871708Sstevel iosram_remove_instance(int instance)
30881708Sstevel {
30891708Sstevel iosramsoft_t *softp;
30901708Sstevel
30911708Sstevel /*
30921708Sstevel * Remove specified instance from the iosram_instances list so that
30931708Sstevel * it can't be chosen for tunnel in future.
30941708Sstevel */
30951708Sstevel ASSERT(mutex_owned(&iosram_mutex));
30961708Sstevel
30971708Sstevel for (softp = iosram_instances; softp != NULL; softp = softp->next) {
30981708Sstevel if (softp->instance == instance) {
30991708Sstevel if (softp->next != NULL) {
31001708Sstevel softp->next->prev = softp->prev;
31011708Sstevel }
31021708Sstevel if (softp->prev != NULL) {
31031708Sstevel softp->prev->next = softp->next;
31041708Sstevel }
31051708Sstevel if (iosram_instances == softp) {
31061708Sstevel iosram_instances = softp->next;
31071708Sstevel }
31081708Sstevel
31091708Sstevel return;
31101708Sstevel }
31111708Sstevel }
31121708Sstevel }
31131708Sstevel
31141708Sstevel
31151708Sstevel /*
31161708Sstevel * iosram_sema_acquire: Acquire hardware semaphore.
31171708Sstevel * Return 0 if the semaphore could be acquired, or one of the following
31181708Sstevel * possible values:
31191708Sstevel * EAGAIN: there is a tunnel switch in progress
31201708Sstevel * EBUSY: the semaphore was already "held"
31211708Sstevel * ENXIO: an IO error occured (e.g. SBBC not mapped)
31221708Sstevel * If old_value is not NULL, the location it points to will be updated
31231708Sstevel * with the semaphore value read when attempting to acquire it.
31241708Sstevel */
31251708Sstevel int
iosram_sema_acquire(uint32_t * old_value)31261708Sstevel iosram_sema_acquire(uint32_t *old_value)
31271708Sstevel {
31281708Sstevel struct iosramsoft *softp;
31291708Sstevel int rv;
31301708Sstevel uint32_t sema_val;
31311708Sstevel
31321708Sstevel DPRINTF(2, ("IOSRAM: in iosram_sema_acquire\n"));
31331708Sstevel
31341708Sstevel mutex_enter(&iosram_mutex);
31351708Sstevel
31361708Sstevel /*
31371708Sstevel * Disallow access if there is a tunnel switch in progress.
31381708Sstevel */
31391708Sstevel if (iosram_tswitch_active) {
31401708Sstevel mutex_exit(&iosram_mutex);
31411708Sstevel return (EAGAIN);
31421708Sstevel }
31431708Sstevel
31441708Sstevel /*
31451708Sstevel * Use current master IOSRAM for operation, fail if none is
31461708Sstevel * currently active.
31471708Sstevel */
31481708Sstevel if ((softp = iosram_master) == NULL) {
31491708Sstevel mutex_exit(&iosram_mutex);
31501708Sstevel DPRINTF(1, ("IOSRAM: iosram_sema_acquire: no master\n"));
31511708Sstevel return (ENXIO);
31521708Sstevel }
31531708Sstevel
31541708Sstevel mutex_enter(&softp->intr_mutex);
31551708Sstevel
31561708Sstevel /*
31571708Sstevel * Fail if SBBC region has not been mapped. This shouldn't
31581708Sstevel * happen if we have a master IOSRAM, but we double-check.
31591708Sstevel */
31601708Sstevel if (softp->sbbc_region == NULL) {
31611708Sstevel mutex_exit(&softp->intr_mutex);
31621708Sstevel mutex_exit(&iosram_mutex);
31631708Sstevel DPRINTF(1, ("IOSRAM(%d): iosram_sema_acquire: "
31641708Sstevel "SBBC not mapped\n", softp->instance));
31651708Sstevel return (ENXIO);
31661708Sstevel }
31671708Sstevel
31681708Sstevel /* read semaphore value */
31691708Sstevel sema_val = IOSRAM_SEMA_RD(softp);
31701708Sstevel if (old_value != NULL)
31711708Sstevel *old_value = sema_val;
31721708Sstevel
31731708Sstevel if (IOSRAM_SEMA_IS_HELD(sema_val)) {
31741708Sstevel /* semaphore was held by someone else */
31751708Sstevel rv = EBUSY;
31761708Sstevel } else {
31771708Sstevel /* semaphore was not held, we just acquired it */
31781708Sstevel rv = 0;
31791708Sstevel }
31801708Sstevel
31811708Sstevel mutex_exit(&softp->intr_mutex);
31821708Sstevel mutex_exit(&iosram_mutex);
31831708Sstevel
31841708Sstevel DPRINTF(1, ("IOSRAM(%d): iosram_sema_acquire: "
31851708Sstevel "old value=0x%x rv=%d\n", softp->instance, sema_val, rv));
31861708Sstevel
31871708Sstevel return (rv);
31881708Sstevel }
31891708Sstevel
31901708Sstevel
31911708Sstevel /*
31921708Sstevel * iosram_sema_release: Release hardware semaphore.
31931708Sstevel * This function will "release" the hardware semaphore, and return 0 on
31941708Sstevel * success. If an error occured, one of the following values will be
31951708Sstevel * returned:
31961708Sstevel * EAGAIN: there is a tunnel switch in progress
31971708Sstevel * ENXIO: an IO error occured (e.g. SBBC not mapped)
31981708Sstevel */
31991708Sstevel int
iosram_sema_release(void)32001708Sstevel iosram_sema_release(void)
32011708Sstevel {
32021708Sstevel struct iosramsoft *softp;
32031708Sstevel
32041708Sstevel DPRINTF(2, ("IOSRAM: in iosram_sema_release\n"));
32051708Sstevel
32061708Sstevel mutex_enter(&iosram_mutex);
32071708Sstevel
32081708Sstevel /*
32091708Sstevel * Disallow access if there is a tunnel switch in progress.
32101708Sstevel */
32111708Sstevel if (iosram_tswitch_active) {
32121708Sstevel mutex_exit(&iosram_mutex);
32131708Sstevel return (EAGAIN);
32141708Sstevel }
32151708Sstevel
32161708Sstevel /*
32171708Sstevel * Use current master IOSRAM for operation, fail if none is
32181708Sstevel * currently active.
32191708Sstevel */
32201708Sstevel if ((softp = iosram_master) == NULL) {
32211708Sstevel mutex_exit(&iosram_mutex);
32221708Sstevel DPRINTF(1, ("IOSRAM: iosram_sema_release: no master\n"));
32231708Sstevel return (ENXIO);
32241708Sstevel }
32251708Sstevel
32261708Sstevel mutex_enter(&softp->intr_mutex);
32271708Sstevel
32281708Sstevel /*
32291708Sstevel * Fail if SBBC region has not been mapped in. This shouldn't
32301708Sstevel * happen if we have a master IOSRAM, but we double-check.
32311708Sstevel */
32321708Sstevel if (softp->sbbc_region == NULL) {
32331708Sstevel mutex_exit(&softp->intr_mutex);
32341708Sstevel mutex_exit(&iosram_mutex);
32351708Sstevel DPRINTF(1, ("IOSRAM(%d): iosram_sema_release: "
32361708Sstevel "SBBC not mapped\n", softp->instance));
32371708Sstevel return (ENXIO);
32381708Sstevel }
32391708Sstevel
32401708Sstevel /* Release semaphore by clearing our semaphore register */
32411708Sstevel IOSRAM_SEMA_WR(softp, 0);
32421708Sstevel
32431708Sstevel mutex_exit(&softp->intr_mutex);
32441708Sstevel mutex_exit(&iosram_mutex);
32451708Sstevel
32461708Sstevel DPRINTF(1, ("IOSRAM(%d): iosram_sema_release: success\n",
32471708Sstevel softp->instance));
32481708Sstevel
32491708Sstevel return (0);
32501708Sstevel }
32511708Sstevel
32521708Sstevel
32531708Sstevel #if defined(IOSRAM_LOG)
32541708Sstevel void
iosram_log(caddr_t fmt,intptr_t a1,intptr_t a2,intptr_t a3,intptr_t a4)32551708Sstevel iosram_log(caddr_t fmt, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4)
32561708Sstevel {
32571708Sstevel uint32_t seq;
32581708Sstevel iosram_log_t *logp;
32591708Sstevel
32601708Sstevel mutex_enter(&iosram_log_mutex);
32611708Sstevel
32621708Sstevel seq = iosram_logseq++;
32631708Sstevel logp = &iosram_logbuf[seq % IOSRAM_MAXLOG];
32641708Sstevel logp->seq = seq;
326511066Srafael.vanoni@sun.com logp->tstamp = ddi_get_lbolt();
32661708Sstevel logp->fmt = fmt;
32671708Sstevel logp->arg1 = a1;
32681708Sstevel logp->arg2 = a2;
32691708Sstevel logp->arg3 = a3;
32701708Sstevel logp->arg4 = a4;
32711708Sstevel
32721708Sstevel mutex_exit(&iosram_log_mutex);
32731708Sstevel
32741708Sstevel if (iosram_log_print) {
32751708Sstevel cmn_err(CE_CONT, "#%x @%lx ", logp->seq, logp->tstamp);
32761708Sstevel if (logp->fmt) {
32771708Sstevel cmn_err(CE_CONT, logp->fmt, logp->arg1, logp->arg2,
32781708Sstevel logp->arg3, logp->arg4);
32791708Sstevel if (logp->fmt[strlen(logp->fmt)-1] != '\n') {
32801708Sstevel cmn_err(CE_CONT, "\n");
32811708Sstevel }
32821708Sstevel } else {
32831708Sstevel cmn_err(CE_CONT, "fmt:%p args: %lx %lx %lx %lx\n",
3284*11311SSurya.Prakki@Sun.COM (void *)logp->fmt, logp->arg1, logp->arg2,
3285*11311SSurya.Prakki@Sun.COM logp->arg3, logp->arg4);
32861708Sstevel }
32871708Sstevel }
32881708Sstevel }
32891708Sstevel #endif /* IOSRAM_LOG */
32901708Sstevel
32911708Sstevel
32921708Sstevel #if defined(DEBUG)
32931708Sstevel /*
32941708Sstevel * iosram_get_keys(buf, len)
32951708Sstevel * Return IOSRAM TOC in the specified buffer
32961708Sstevel */
32971708Sstevel static int
iosram_get_keys(iosram_toc_entry_t * bufp,uint32_t * len)32981708Sstevel iosram_get_keys(iosram_toc_entry_t *bufp, uint32_t *len)
32991708Sstevel {
33001708Sstevel struct iosram_chunk *chunkp;
33011708Sstevel int error = 0;
33021708Sstevel int i;
33031708Sstevel int cnt = (*len) / sizeof (iosram_toc_entry_t);
33041708Sstevel
33051708Sstevel IOSRAMLOG(2, "iosram_get_keys(bufp:%p *len:%x)\n", bufp, *len, NULL,
33061708Sstevel NULL);
33071708Sstevel
33081708Sstevel /*
33091708Sstevel * Copy data while holding the lock to prevent any data
33101708Sstevel * corruption or invalid pointer dereferencing.
33111708Sstevel */
33121708Sstevel mutex_enter(&iosram_mutex);
33131708Sstevel
33141708Sstevel if (iosram_master == NULL) {
33151708Sstevel error = EIO;
33161708Sstevel } else {
33171708Sstevel for (i = 0, chunkp = chunks; i < nchunks && i < cnt;
33181708Sstevel i++, chunkp++) {
33191708Sstevel bufp[i].key = chunkp->toc_data.key;
33201708Sstevel bufp[i].off = chunkp->toc_data.off;
33211708Sstevel bufp[i].len = chunkp->toc_data.len;
33221708Sstevel bufp[i].unused = chunkp->toc_data.unused;
33231708Sstevel }
33241708Sstevel *len = i * sizeof (iosram_toc_entry_t);
33251708Sstevel }
33261708Sstevel
33271708Sstevel mutex_exit(&iosram_mutex);
33281708Sstevel return (error);
33291708Sstevel }
33301708Sstevel
33311708Sstevel
33321708Sstevel /*
33331708Sstevel * iosram_print_state(instance)
33341708Sstevel */
33351708Sstevel static void
iosram_print_state(int instance)33361708Sstevel iosram_print_state(int instance)
33371708Sstevel {
33381708Sstevel struct iosramsoft *softp;
33391708Sstevel char pn[MAXNAMELEN];
33401708Sstevel
33411708Sstevel if (instance < 0) {
33421708Sstevel softp = iosram_master;
33431708Sstevel } else {
33441708Sstevel softp = ddi_get_soft_state(iosramsoft_statep, instance);
33451708Sstevel }
33461708Sstevel
33471708Sstevel if (softp == NULL) {
33481708Sstevel cmn_err(CE_CONT, "iosram_print_state: Can't find instance %d\n",
33491708Sstevel instance);
33501708Sstevel return;
33511708Sstevel }
33521708Sstevel instance = softp->instance;
33531708Sstevel
33541708Sstevel mutex_enter(&iosram_mutex);
33551708Sstevel mutex_enter(&softp->intr_mutex);
33561708Sstevel
33571708Sstevel cmn_err(CE_CONT, "iosram_print_state(%d): ... %s\n", instance,
33581708Sstevel ((softp == iosram_master) ? "MASTER" : "SLAVE"));
33591708Sstevel
33601708Sstevel (void) ddi_pathname(softp->dip, pn);
33611708Sstevel cmn_err(CE_CONT, " pathname:%s\n", pn);
33621708Sstevel cmn_err(CE_CONT, " instance:%d portid:%d iosramlen:0x%x\n",
33631708Sstevel softp->instance, softp->portid, softp->iosramlen);
3364*11311SSurya.Prakki@Sun.COM cmn_err(CE_CONT, " softp:%p handle:%p iosramp:%p\n", (void *)softp,
3365*11311SSurya.Prakki@Sun.COM (void *)softp->handle, (void *)softp->iosramp);
33661708Sstevel cmn_err(CE_CONT, " state:0x%x tswitch_ok:%x tswitch_fail:%x\n",
33671708Sstevel softp->state, softp->tswitch_ok, softp->tswitch_fail);
33681708Sstevel cmn_err(CE_CONT, " softintr_id:%p intr_busy:%x intr_pending:%x\n",
3369*11311SSurya.Prakki@Sun.COM (void *)softp->softintr_id, softp->intr_busy, softp->intr_pending);
33701708Sstevel
33711708Sstevel mutex_exit(&softp->intr_mutex);
33721708Sstevel mutex_exit(&iosram_mutex);
33731708Sstevel }
33741708Sstevel
33751708Sstevel
33761708Sstevel /*
33771708Sstevel * iosram_print_stats()
33781708Sstevel */
33791708Sstevel static void
iosram_print_stats()33801708Sstevel iosram_print_stats()
33811708Sstevel {
33821708Sstevel uint32_t calls;
33831708Sstevel
33841708Sstevel cmn_err(CE_CONT, "iosram_stats:\n");
33851708Sstevel calls = iosram_stats.read;
33861708Sstevel cmn_err(CE_CONT, " read ... calls:%x bytes:%lx avg_sz:%x\n",
33871708Sstevel calls, iosram_stats.bread,
33881708Sstevel (uint32_t)((calls != 0) ? (iosram_stats.bread/calls) : 0));
33891708Sstevel
33901708Sstevel calls = iosram_stats.write;
33911708Sstevel cmn_err(CE_CONT, " write ... calls:%x bytes:%lx avg_sz:%x\n",
33921708Sstevel calls, iosram_stats.bwrite,
33931708Sstevel (uint32_t)((calls != 0) ? (iosram_stats.bwrite/calls) : 0));
33941708Sstevel
33951708Sstevel cmn_err(CE_CONT, " intr recv (real:%x soft:%x) sent:%x cback:%x\n",
33961708Sstevel iosram_stats.intr_recv, iosram_stats.sintr_recv,
33971708Sstevel iosram_stats.intr_send, iosram_stats.callbacks);
33981708Sstevel
33991708Sstevel cmn_err(CE_CONT, " tswitch: %x getflag:%x setflag:%x\n",
34001708Sstevel iosram_stats.tswitch, iosram_stats.getflag,
34011708Sstevel iosram_stats.setflag);
34021708Sstevel
34031708Sstevel cmn_err(CE_CONT, " iosram_rw_active_max: %x\n", iosram_rw_active_max);
34041708Sstevel }
34051708Sstevel
34061708Sstevel
34071708Sstevel static void
iosram_print_cback()34081708Sstevel iosram_print_cback()
34091708Sstevel {
34101708Sstevel iosram_chunk_t *chunkp;
34111708Sstevel int i;
34121708Sstevel
34131708Sstevel /*
34141708Sstevel * Print callback handlers
34151708Sstevel */
34161708Sstevel mutex_enter(&iosram_mutex);
34171708Sstevel
34181708Sstevel cmn_err(CE_CONT, "IOSRAM callbacks:\n");
34191708Sstevel for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
34201708Sstevel if (chunkp->cback.handler) {
34211708Sstevel cmn_err(CE_CONT, " %2d: key:0x%x hdlr:%p arg:%p "
34221708Sstevel "busy:%d unreg:%d\n", i, chunkp->toc_data.key,
3423*11311SSurya.Prakki@Sun.COM (void *)chunkp->cback.handler,
3424*11311SSurya.Prakki@Sun.COM (void *)chunkp->cback.arg,
34251708Sstevel chunkp->cback.busy, chunkp->cback.unregister);
34261708Sstevel }
34271708Sstevel }
34281708Sstevel mutex_exit(&iosram_mutex);
34291708Sstevel }
34301708Sstevel
34311708Sstevel
34321708Sstevel static void
iosram_print_flags()34331708Sstevel iosram_print_flags()
34341708Sstevel {
34351708Sstevel int i;
34361708Sstevel uint32_t *keys;
34371708Sstevel iosram_flags_t *flags;
34381708Sstevel
34391708Sstevel mutex_enter(&iosram_mutex);
34401708Sstevel
34411708Sstevel if (iosram_master == NULL) {
34421708Sstevel mutex_exit(&iosram_mutex);
34431708Sstevel cmn_err(CE_CONT, "IOSRAM Flags: not accessible\n");
34441708Sstevel return;
34451708Sstevel }
34461708Sstevel
34471708Sstevel keys = kmem_alloc(nchunks * sizeof (uint32_t), KM_SLEEP);
34481708Sstevel flags = kmem_alloc(nchunks * sizeof (iosram_flags_t), KM_SLEEP);
34491708Sstevel
34501708Sstevel for (i = 0; i < nchunks; i++) {
34511708Sstevel keys[i] = chunks[i].toc_data.key;
34521708Sstevel ddi_rep_get8(iosram_handle, (uint8_t *)&(flags[i]),
34531708Sstevel (uint8_t *)(chunks[i].flagsp), sizeof (iosram_flags_t),
34541708Sstevel DDI_DEV_AUTOINCR);
34551708Sstevel }
34561708Sstevel
34571708Sstevel mutex_exit(&iosram_mutex);
34581708Sstevel
34591708Sstevel cmn_err(CE_CONT, "IOSRAM Flags:\n");
34601708Sstevel for (i = 0; i < nchunks; i++) {
34611708Sstevel cmn_err(CE_CONT,
34621708Sstevel " %2d: key: 0x%x data_valid:%x int_pending:%x\n",
34631708Sstevel i, keys[i], flags[i].data_valid, flags[i].int_pending);
34641708Sstevel }
34651708Sstevel
34661708Sstevel kmem_free(keys, nchunks * sizeof (uint32_t));
34671708Sstevel kmem_free(flags, nchunks * sizeof (iosram_flags_t));
34681708Sstevel }
34691708Sstevel
34701708Sstevel
34711708Sstevel /*PRINTFLIKE1*/
34721708Sstevel static void
iosram_dprintf(const char * fmt,...)34731708Sstevel iosram_dprintf(const char *fmt, ...)
34741708Sstevel {
34751708Sstevel char msg_buf[256];
34761708Sstevel va_list adx;
34771708Sstevel
34781708Sstevel va_start(adx, fmt);
3479*11311SSurya.Prakki@Sun.COM (void) vsprintf(msg_buf, fmt, adx);
34801708Sstevel va_end(adx);
34811708Sstevel
34821708Sstevel cmn_err(CE_CONT, "%s", msg_buf);
34831708Sstevel }
34841708Sstevel #endif /* DEBUG */
34851708Sstevel
34861708Sstevel
34871708Sstevel #if IOSRAM_LOG
34881708Sstevel /*
34891708Sstevel * iosram_print_log(int cnt)
34901708Sstevel * Print last few entries of the IOSRAM log in reverse order
34911708Sstevel */
34921708Sstevel static void
iosram_print_log(int cnt)34931708Sstevel iosram_print_log(int cnt)
34941708Sstevel {
34951708Sstevel int i;
34961708Sstevel
34971708Sstevel if (cnt <= 0) {
34981708Sstevel cnt = 20;
34991708Sstevel } else if (cnt > IOSRAM_MAXLOG) {
35001708Sstevel cnt = IOSRAM_MAXLOG;
35011708Sstevel }
35021708Sstevel
35031708Sstevel
35041708Sstevel cmn_err(CE_CONT,
35051708Sstevel "\niosram_logseq: 0x%x lbolt: %lx iosram_log_level:%x\n",
350611066Srafael.vanoni@sun.com iosram_logseq, ddi_get_lbolt(), iosram_log_level);
35071708Sstevel cmn_err(CE_CONT, "iosram_logbuf: %p max entries:0x%x\n",
3508*11311SSurya.Prakki@Sun.COM (void *)iosram_logbuf, IOSRAM_MAXLOG);
35091708Sstevel for (i = iosram_logseq; --i >= 0 && --cnt >= 0; ) {
35101708Sstevel iosram_log_t *logp;
35111708Sstevel
35121708Sstevel mutex_enter(&iosram_log_mutex);
35131708Sstevel
35141708Sstevel logp = &iosram_logbuf[i %IOSRAM_MAXLOG];
35151708Sstevel cmn_err(CE_CONT, "#%x @%lx ", logp->seq, logp->tstamp);
35161708Sstevel
35171708Sstevel if (logp->fmt) {
35181708Sstevel cmn_err(CE_CONT, logp->fmt, logp->arg1, logp->arg2,
35191708Sstevel logp->arg3, logp->arg4);
35201708Sstevel if (logp->fmt[strlen(logp->fmt)-1] != '\n') {
35211708Sstevel cmn_err(CE_CONT, "\n");
35221708Sstevel }
35231708Sstevel } else {
35241708Sstevel cmn_err(CE_CONT, "fmt:%p args: %lx %lx %lx %lx\n",
3525*11311SSurya.Prakki@Sun.COM (void *)logp->fmt, logp->arg1, logp->arg2,
35261708Sstevel logp->arg3, logp->arg4);
35271708Sstevel }
35281708Sstevel
35291708Sstevel mutex_exit(&iosram_log_mutex);
35301708Sstevel }
35311708Sstevel }
35321708Sstevel #endif /* IOSRAM_LOG */
3533