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