xref: /titanic_50/usr/src/uts/sun4u/starcat/io/iosram.c (revision 9b79392525856301c6f8962f189c2a32242af618)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * IOSRAM leaf driver to SBBC nexus driver.  This driver is used
29  * by Starcat Domain SW to read/write from/to the IO sram.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/conf.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/ddi_impldefs.h>
37 #include <sys/obpdefs.h>
38 #include <sys/promif.h>
39 #include <sys/prom_plat.h>
40 #include <sys/cmn_err.h>
41 #include <sys/conf.h>		/* req. by dev_ops flags MTSAFE etc. */
42 #include <sys/modctl.h>		/* for modldrv */
43 #include <sys/stat.h>		/* ddi_create_minor_node S_IFCHR */
44 #include <sys/errno.h>
45 #include <sys/kmem.h>
46 #include <sys/kstat.h>
47 #include <sys/debug.h>
48 
49 #include <sys/axq.h>
50 #include <sys/iosramreg.h>
51 #include <sys/iosramio.h>
52 #include <sys/iosramvar.h>
53 
54 
55 #if defined(DEBUG)
56 int	iosram_debug = 0;
57 static void iosram_dprintf(const char *fmt, ...);
58 #define	DPRINTF(level, arg)	\
59 		{ if (iosram_debug >= level) iosram_dprintf arg; }
60 #else	/* !DEBUG */
61 #define	DPRINTF(level, arg)
62 #endif	/* !DEBUG */
63 
64 
65 /*
66  * IOSRAM module global state
67  */
68 static void	*iosramsoft_statep;	/* IOSRAM state pointer */
69 static kmutex_t	iosram_mutex;		/* mutex lock */
70 
71 static iosram_chunk_t	*chunks = NULL;	/* array of TOC entries */
72 static int	nchunks = 0;		/* # of TOC entries */
73 static iosram_chunk_t	*iosram_hashtab[IOSRAM_HASHSZ];	/* key hash table */
74 
75 static kcondvar_t	iosram_tswitch_wait;	/* tunnel switch wait cv */
76 static int	iosram_tswitch_wakeup = 0;	/* flag indicationg one or */
77 						/* more threads waiting on */
78 						/* iosram_tswitch_wait cv */
79 static int	iosram_tswitch_active = 0;	/* tunnel switch active flag */
80 static int	iosram_tswitch_aborted = 0;	/* tunnel switch abort flag */
81 static clock_t	iosram_tswitch_tstamp = 0;	/* lbolt of last tswitch end */
82 static kcondvar_t	iosram_rw_wait;		/* read/write wait cv */
83 static int	iosram_rw_wakeup = 0;		/* flag indicationg one or */
84 						/* more threads waiting on */
85 						/* iosram_rw_wait cv */
86 static int	iosram_rw_active = 0;		/* # threads accessing IOSRAM */
87 #if defined(DEBUG)
88 static int	iosram_rw_active_max = 0;
89 #endif
90 
91 static struct iosramsoft *iosram_new_master = NULL;	/* new tunnel target */
92 static struct iosramsoft *iosram_master = NULL;		/* master tunnel */
93 static struct iosramsoft *iosram_instances = NULL;	/* list of softstates */
94 
95 static ddi_acc_handle_t	iosram_handle = NULL;	/* master IOSRAM map handle */
96 
97 static void	(*iosram_hdrchange_handler)() = NULL;
98 
99 #if IOSRAM_STATS
100 static struct	iosram_stat iosram_stats;	/* IOSRAM statistics */
101 static void	iosram_print_stats();		/* forward declaration */
102 #endif /* IOSRAM_STATS */
103 
104 
105 #if IOSRAM_LOG
106 kmutex_t 	iosram_log_mutex;
107 int		iosram_log_level = 1;
108 int		iosram_log_print = 0;		/* print log when recorded */
109 uint32_t	iosram_logseq;
110 iosram_log_t	iosram_logbuf[IOSRAM_MAXLOG];
111 static void	iosram_print_log(int cnt);	/* forward declaration */
112 #endif	/* IOSRAM_LOG */
113 
114 
115 /* driver entry point fn definitions */
116 static int 	iosram_open(dev_t *, int, int, cred_t *);
117 static int	iosram_close(dev_t, int, int, cred_t *);
118 static int	iosram_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
119 
120 /* configuration entry point fn definitions */
121 static int 	iosram_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
122 static int	iosram_attach(dev_info_t *, ddi_attach_cmd_t);
123 static int	iosram_detach(dev_info_t *, ddi_detach_cmd_t);
124 
125 
126 /* forward declaractions */
127 static iosram_chunk_t	*iosram_find_chunk(uint32_t key);
128 static void	iosram_set_master(struct iosramsoft *softp);
129 static int	iosram_is_chosen(struct iosramsoft *softp);
130 static int	iosram_tunnel_capable(struct iosramsoft *softp);
131 static int	iosram_read_toc(struct iosramsoft *softp);
132 static void	iosram_init_hashtab(void);
133 static void	iosram_update_addrs(struct iosramsoft *softp);
134 
135 static int	iosram_setup_map(struct iosramsoft *softp);
136 static void	iosram_remove_map(struct iosramsoft *softp);
137 static int	iosram_add_intr(iosramsoft_t *);
138 static int	iosram_remove_intr(iosramsoft_t *);
139 
140 static void	iosram_add_instance(struct iosramsoft *softp);
141 static void	iosram_remove_instance(int instance);
142 static int	iosram_switch_tunnel(iosramsoft_t *softp);
143 static void	iosram_abort_tswitch();
144 
145 #if defined(DEBUG)
146 /* forward declaractions for debugging */
147 static int	iosram_get_keys(iosram_toc_entry_t *buf, uint32_t *len);
148 static void	iosram_print_cback();
149 static void	iosram_print_state(int);
150 static void	iosram_print_flags();
151 #endif
152 
153 
154 
155 /*
156  * cb_ops
157  */
158 static struct cb_ops iosram_cb_ops = {
159 	iosram_open,		/* cb_open */
160 	iosram_close,		/* cb_close */
161 	nodev,			/* cb_strategy */
162 	nodev,			/* cb_print */
163 	nodev,			/* cb_dump */
164 	nodev,			/* cb_read */
165 	nodev,			/* cb_write */
166 	iosram_ioctl,		/* cb_ioctl */
167 	nodev,			/* cb_devmap */
168 	nodev,			/* cb_mmap */
169 	nodev,			/* cb_segmap */
170 	nochpoll,		/* cb_chpoll */
171 	ddi_prop_op,		/* cb_prop_op */
172 	NULL,			/* cb_stream */
173 	(int)(D_NEW | D_MP | D_HOTPLUG)	/* cb_flag */
174 };
175 
176 /*
177  * Declare ops vectors for auto configuration.
178  */
179 struct dev_ops  iosram_ops = {
180 	DEVO_REV,		/* devo_rev */
181 	0,			/* devo_refcnt */
182 	iosram_getinfo,		/* devo_getinfo */
183 	nulldev,		/* devo_identify */
184 	nulldev,		/* devo_probe */
185 	iosram_attach,		/* devo_attach */
186 	iosram_detach,		/* devo_detach */
187 	nodev,			/* devo_reset */
188 	&iosram_cb_ops,		/* devo_cb_ops */
189 	(struct bus_ops *)NULL,	/* devo_bus_ops */
190 	nulldev,		/* devo_power */
191 	ddi_quiesce_not_supported,	/* devo_quiesce */
192 };
193 
194 /*
195  * Loadable module support.
196  */
197 extern struct mod_ops mod_driverops;
198 
199 static struct modldrv iosrammodldrv = {
200 	&mod_driverops,		/* type of module - driver */
201 	"IOSRAM Leaf driver",
202 	&iosram_ops,
203 };
204 
205 static struct modlinkage iosrammodlinkage = {
206 	MODREV_1,
207 	&iosrammodldrv,
208 	NULL
209 };
210 
211 
212 int
213 _init(void)
214 {
215 	int    error;
216 	int	i;
217 
218 	mutex_init(&iosram_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
219 	cv_init(&iosram_tswitch_wait, NULL, CV_DRIVER, NULL);
220 	cv_init(&iosram_rw_wait, NULL, CV_DRIVER, NULL);
221 #if defined(IOSRAM_LOG)
222 	mutex_init(&iosram_log_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
223 #endif
224 
225 	DPRINTF(1, ("_init:IOSRAM\n"));
226 
227 	for (i = 0; i < IOSRAM_HASHSZ; i++) {
228 		iosram_hashtab[i] = NULL;
229 	}
230 
231 	if ((error = ddi_soft_state_init(&iosramsoft_statep,
232 	    sizeof (struct iosramsoft), 1)) != 0) {
233 		goto failed;
234 	}
235 	if ((error = mod_install(&iosrammodlinkage)) != 0) {
236 		ddi_soft_state_fini(&iosramsoft_statep);
237 		goto failed;
238 	}
239 
240 	IOSRAMLOG(0, "_init:IOSRAM ... error:%d  statep:%p\n",
241 	    error, iosramsoft_statep, NULL, NULL);
242 
243 	return (error);
244 
245 failed:
246 	cv_destroy(&iosram_tswitch_wait);
247 	cv_destroy(&iosram_rw_wait);
248 	mutex_destroy(&iosram_mutex);
249 #if defined(IOSRAM_LOG)
250 	mutex_destroy(&iosram_log_mutex);
251 #endif
252 	IOSRAMLOG(0, "_init:IOSRAM ... error:%d  statep:%p\n",
253 	    error, iosramsoft_statep, NULL, NULL);
254 
255 	return (error);
256 }
257 
258 
259 int
260 _fini(void)
261 {
262 #ifndef DEBUG
263 	return (EBUSY);
264 #else /* !DEBUG */
265 	int    error;
266 
267 	if ((error = mod_remove(&iosrammodlinkage)) == 0) {
268 		ddi_soft_state_fini(&iosramsoft_statep);
269 
270 		cv_destroy(&iosram_tswitch_wait);
271 		cv_destroy(&iosram_rw_wait);
272 		mutex_destroy(&iosram_mutex);
273 #if defined(IOSRAM_LOG)
274 		mutex_destroy(&iosram_log_mutex);
275 #endif
276 	}
277 	DPRINTF(1, ("_fini:IOSRAM  error:%d\n", error));
278 
279 	return (error);
280 #endif /* !DEBUG */
281 }
282 
283 
284 int
285 _info(struct modinfo *modinfop)
286 {
287 	return (mod_info(&iosrammodlinkage, modinfop));
288 }
289 
290 
291 static int
292 iosram_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
293 {
294 	int	instance;
295 	int	propval;
296 	int	length;
297 	char	name[32];
298 	struct	iosramsoft *softp;
299 
300 	instance = ddi_get_instance(dip);
301 
302 	DPRINTF(1, ("iosram(%d): attach dip:%p\n", instance, (void *)dip));
303 
304 	IOSRAMLOG(1, "ATTACH: dip:%p instance %d ... start\n",
305 	    dip, instance, NULL, NULL);
306 	switch (cmd) {
307 	case DDI_ATTACH:
308 		break;
309 	case DDI_RESUME:
310 		if (!(softp = ddi_get_soft_state(iosramsoft_statep,
311 		    instance))) {
312 			return (DDI_FAILURE);
313 		}
314 		mutex_enter(&iosram_mutex);
315 		mutex_enter(&softp->intr_mutex);
316 		if (!softp->suspended) {
317 			mutex_exit(&softp->intr_mutex);
318 			mutex_exit(&iosram_mutex);
319 			return (DDI_FAILURE);
320 		}
321 		softp->suspended = 0;
322 
323 		/*
324 		 * enable SBBC interrupts if SBBC is mapped in
325 		 * restore the value saved during detach
326 		 */
327 		if (softp->sbbc_region) {
328 			ddi_put32(softp->sbbc_handle,
329 			    &(softp->sbbc_region->int_enable.reg),
330 			    softp->int_enable_sav);
331 		}
332 
333 		/*
334 		 * Trigger soft interrupt handler to process any pending
335 		 * interrupts.
336 		 */
337 		if (softp->intr_pending && !softp->intr_busy &&
338 		    (softp->softintr_id != NULL)) {
339 			ddi_trigger_softintr(softp->softintr_id);
340 		}
341 
342 		mutex_exit(&softp->intr_mutex);
343 		mutex_exit(&iosram_mutex);
344 
345 		return (DDI_SUCCESS);
346 
347 	default:
348 		return (DDI_FAILURE);
349 	}
350 
351 	if (ddi_soft_state_zalloc(iosramsoft_statep, instance) != 0) {
352 		return (DDI_FAILURE);
353 	}
354 
355 	if ((softp = ddi_get_soft_state(iosramsoft_statep, instance)) == NULL) {
356 			return (DDI_FAILURE);
357 	}
358 	softp->dip = dip;
359 	softp->instance = instance;
360 	softp->sbbc_region = NULL;
361 
362 	/*
363 	 * If this instance is not tunnel capable, we don't attach it.
364 	 */
365 	if (iosram_tunnel_capable(softp) == 0) {
366 		DPRINTF(1, ("iosram(%d): not tunnel_capable\n", instance));
367 		IOSRAMLOG(1, "ATTACH(%d): not tunnel_capable\n", instance, NULL,
368 		    NULL, NULL);
369 		goto attach_fail;
370 	}
371 
372 	/*
373 	 * Need to create an "interrupt-priorities" property to define the PIL
374 	 * to be used with the interrupt service routine.
375 	 */
376 	if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
377 	    "interrupt-priorities", &length) == DDI_PROP_NOT_FOUND) {
378 		DPRINTF(1, ("iosram(%d): creating interrupt priority property",
379 		    instance));
380 		propval = IOSRAM_PIL;
381 		if (ddi_prop_create(DDI_DEV_T_NONE, dip, 0,
382 		    "interrupt-priorities", (caddr_t)&propval, sizeof (propval))
383 		    != DDI_PROP_SUCCESS) {
384 			cmn_err(CE_WARN,
385 			    "iosram_attach: failed to create property");
386 			goto attach_fail;
387 		}
388 	}
389 
390 	/*
391 	 * Get interrupts cookies and initialize per-instance mutexes
392 	 */
393 	if (ddi_get_iblock_cookie(softp->dip, 0, &softp->real_iblk)
394 	    != DDI_SUCCESS) {
395 		IOSRAMLOG(1, "ATTACH(%d): cannot get soft intr cookie\n",
396 		    instance, NULL, NULL, NULL);
397 		goto attach_fail;
398 	}
399 	mutex_init(&softp->intr_mutex, NULL, MUTEX_DRIVER,
400 	    (void *)softp->real_iblk);
401 
402 	/*
403 	 * Add this instance to the iosram_instances list so that it can be used
404 	 * for tunnel in future.
405 	 */
406 	mutex_enter(&iosram_mutex);
407 	softp->state = IOSRAM_STATE_INIT;
408 	iosram_add_instance(softp);
409 
410 	/*
411 	 * If this is the chosen IOSRAM and there is no master IOSRAM yet, then
412 	 * let's set this instance as the master.
413 	 */
414 	if (iosram_master == NULL && iosram_is_chosen(softp)) {
415 		(void) iosram_switch_tunnel(softp);
416 
417 		/*
418 		 * XXX Do we need to panic if unable to setup master IOSRAM?
419 		 */
420 		if (iosram_master == NULL) {
421 			cmn_err(CE_WARN,
422 			    "iosram(%d): can't setup master tunnel\n",
423 			    instance);
424 			softp->state = 0;
425 			iosram_remove_instance(softp->instance);
426 			mutex_exit(&iosram_mutex);
427 			mutex_destroy(&softp->intr_mutex);
428 			goto attach_fail;
429 		}
430 	}
431 
432 	mutex_exit(&iosram_mutex);
433 
434 	/*
435 	 * Create minor node
436 	 */
437 	(void) sprintf(name, "iosram%d", instance);
438 	if (ddi_create_minor_node(dip, name, S_IFCHR, instance, NULL, NULL) ==
439 	    DDI_FAILURE) {
440 		/*
441 		 * Minor node seems to be needed only for debugging purposes.
442 		 * Therefore, there is no need to fail this attach request.
443 		 * Simply print a message out.
444 		 */
445 		cmn_err(CE_NOTE, "!iosram(%d): can't create minor node\n",
446 		    instance);
447 	}
448 	ddi_report_dev(dip);
449 
450 	DPRINTF(1, ("iosram_attach(%d): success.\n", instance));
451 	IOSRAMLOG(1, "ATTACH: dip:%p instance:%d ... success  softp:%p\n",
452 	    dip, instance, softp, NULL);
453 
454 	return (DDI_SUCCESS);
455 
456 attach_fail:
457 	DPRINTF(1, ("iosram_attach(%d):failed.\n", instance));
458 	IOSRAMLOG(1, "ATTACH: dip:%p instance:%d ... failed.\n",
459 	    dip, instance, NULL, NULL);
460 
461 	ddi_soft_state_free(iosramsoft_statep, instance);
462 	return (DDI_FAILURE);
463 }
464 
465 
466 static int
467 iosram_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
468 {
469 	int			instance;
470 	struct iosramsoft	*softp;
471 
472 	instance = ddi_get_instance(dip);
473 	if (!(softp = ddi_get_soft_state(iosramsoft_statep, instance))) {
474 		return (DDI_FAILURE);
475 	}
476 
477 	IOSRAMLOG(1, "DETACH: dip:%p instance %d softp:%p\n",
478 	    dip, instance, softp, NULL);
479 
480 	switch (cmd) {
481 	case DDI_DETACH:
482 		break;
483 	case DDI_SUSPEND:
484 		mutex_enter(&iosram_mutex);
485 		mutex_enter(&softp->intr_mutex);
486 		if (softp->suspended) {
487 			mutex_exit(&softp->intr_mutex);
488 			mutex_exit(&iosram_mutex);
489 			return (DDI_FAILURE);
490 		}
491 		softp->suspended = 1;
492 		/*
493 		 * Disable SBBC interrupts if SBBC is mapped in
494 		 */
495 		if (softp->sbbc_region) {
496 			/* save current interrupt enable register */
497 			softp->int_enable_sav = ddi_get32(softp->sbbc_handle,
498 			    &(softp->sbbc_region->int_enable.reg));
499 			ddi_put32(softp->sbbc_handle,
500 			    &(softp->sbbc_region->int_enable.reg), 0x0);
501 		}
502 		mutex_exit(&softp->intr_mutex);
503 		mutex_exit(&iosram_mutex);
504 		return (DDI_SUCCESS);
505 
506 	default:
507 		return (DDI_FAILURE);
508 	}
509 
510 
511 	/*
512 	 * Indicate that this instance is being detached so that this instance
513 	 * does not become a target for tunnel switch in future.
514 	 */
515 	mutex_enter(&iosram_mutex);
516 	softp->state |= IOSRAM_STATE_DETACH;
517 
518 	/*
519 	 * If this instance is currently the master or the target of the tunnel
520 	 * switch, then we need to wait and switch tunnel, if necessary.
521 	 */
522 	if (iosram_master == softp || (softp->state & IOSRAM_STATE_TSWITCH)) {
523 		mutex_exit(&iosram_mutex);
524 		(void) iosram_switchfrom(instance);
525 		mutex_enter(&iosram_mutex);
526 	}
527 
528 	/*
529 	 * If the tunnel switch is in progress and we are the master or target
530 	 * of tunnel relocation, then we can't detach this instance right now.
531 	 */
532 	if (softp->state & IOSRAM_STATE_TSWITCH) {
533 		softp->state &= ~IOSRAM_STATE_DETACH;
534 		mutex_exit(&iosram_mutex);
535 		return (DDI_FAILURE);
536 	}
537 
538 	/*
539 	 * We can't allow master IOSRAM to be detached as we won't be able to
540 	 * communicate otherwise.
541 	 */
542 	if (iosram_master == softp) {
543 		softp->state &= ~IOSRAM_STATE_DETACH;
544 		mutex_exit(&iosram_mutex);
545 		return (DDI_FAILURE);
546 	}
547 
548 	/*
549 	 * Now remove our instance from the iosram_instances list.
550 	 */
551 	iosram_remove_instance(instance);
552 	mutex_exit(&iosram_mutex);
553 
554 	/*
555 	 * Instances should only ever be mapped if they are the master and/or
556 	 * participating in a tunnel switch.  Neither should be the case here.
557 	 */
558 	ASSERT((softp->state & IOSRAM_STATE_MAPPED) == 0);
559 
560 	/*
561 	 * Destroy per-instance mutexes
562 	 */
563 	mutex_destroy(&softp->intr_mutex);
564 
565 	ddi_remove_minor_node(dip, NULL);
566 
567 	/*
568 	 * Finally remove our soft state structure
569 	 */
570 	ddi_soft_state_free(iosramsoft_statep, instance);
571 
572 	return (DDI_SUCCESS);
573 }
574 
575 
576 /* ARGSUSED0 */
577 static int
578 iosram_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
579 		void **result)
580 {
581 	dev_t			dev = (dev_t)arg;
582 	struct iosramsoft	*softp;
583 	int			instance, ret;
584 
585 	instance = getminor(dev);
586 
587 	IOSRAMLOG(2, "GETINFO: dip:%x instance %d dev:%x infocmd:%x\n",
588 	    dip, instance, dev, infocmd);
589 
590 	switch (infocmd) {
591 		case DDI_INFO_DEVT2DEVINFO:
592 			softp = ddi_get_soft_state(iosramsoft_statep, instance);
593 			if (softp == NULL) {
594 				*result = NULL;
595 				ret = DDI_FAILURE;
596 			} else {
597 				*result = softp->dip;
598 				ret = DDI_SUCCESS;
599 			}
600 			break;
601 		case DDI_INFO_DEVT2INSTANCE:
602 			*result = (void *)(uintptr_t)instance;
603 			ret = DDI_SUCCESS;
604 			break;
605 		default:
606 			ret = DDI_FAILURE;
607 			break;
608 	}
609 
610 	return (ret);
611 }
612 
613 
614 /*ARGSUSED1*/
615 static int
616 iosram_open(dev_t *dev, int flag, int otype, cred_t *credp)
617 {
618 	struct iosramsoft	*softp;
619 	int			instance;
620 
621 	instance = getminor(*dev);
622 	softp = ddi_get_soft_state(iosramsoft_statep, instance);
623 
624 	if (softp == NULL) {
625 		return (ENXIO);
626 	}
627 
628 	IOSRAMLOG(1, "OPEN: dev:%p otype:%x ... instance:%d softp:%p\n",
629 	    *dev, otype, softp->instance, softp);
630 
631 	return (0);
632 }
633 
634 
635 /*ARGSUSED1*/
636 static int
637 iosram_close(dev_t dev, int flag, int otype, cred_t *credp)
638 {
639 	struct iosramsoft	*softp;
640 	int			instance;
641 
642 	instance = getminor(dev);
643 	softp = ddi_get_soft_state(iosramsoft_statep, instance);
644 	if (softp == NULL) {
645 		return (ENXIO);
646 	}
647 
648 	IOSRAMLOG(1, "CLOSE: dev:%p otype:%x ... instance:%d softp:%p\n",
649 	    dev, otype, softp->instance, softp);
650 
651 	return (0);
652 }
653 
654 
655 int
656 iosram_rd(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr)
657 {
658 	iosram_chunk_t		*chunkp;
659 	uint32_t		chunk_len;
660 	uint8_t			*iosramp;
661 	ddi_acc_handle_t	handle;
662 	int			boff;
663 	union {
664 		uchar_t	cbuf[UINT32SZ];
665 		uint32_t  data;
666 	} word;
667 
668 	int			error = 0;
669 	uint8_t			*buf = (uint8_t *)dptr;
670 
671 	/*
672 	 * We try to read from the IOSRAM using double word or word access
673 	 * provided both "off" and "buf" are (or can be) double word or word
674 	 * aligned.  Othewise, we try to align the "off" to a word boundary and
675 	 * then try to read data from the IOSRAM using word access, but store it
676 	 * into buf buffer using byte access.
677 	 *
678 	 * If the leading/trailing portion of the IOSRAM data is not word
679 	 * aligned, it will always be copied using byte access.
680 	 */
681 	IOSRAMLOG(1, "RD: key: 0x%x off:%x len:%x buf:%p\n",
682 	    key, off, len, buf);
683 
684 	/*
685 	 * Acquire lock and look for the requested chunk.  If it exists, make
686 	 * sure the requested read is within the chunk's bounds and no tunnel
687 	 * switch is active.
688 	 */
689 	mutex_enter(&iosram_mutex);
690 	chunkp = iosram_find_chunk(key);
691 	chunk_len = (chunkp != NULL) ? chunkp->toc_data.len : 0;
692 
693 	if (iosram_master == NULL) {
694 		error = EIO;
695 	} else if (chunkp == NULL) {
696 		error = EINVAL;
697 	} else if ((off >= chunk_len) || (len > chunk_len) ||
698 	    ((off + len) > chunk_len)) {
699 		error = EMSGSIZE;
700 	} else if (iosram_tswitch_active) {
701 		error = EAGAIN;
702 	}
703 
704 	if (error) {
705 		mutex_exit(&iosram_mutex);
706 		return (error);
707 	}
708 
709 	/*
710 	 * Bump reference count to indicate #thread accessing IOSRAM and release
711 	 * the lock.
712 	 */
713 	iosram_rw_active++;
714 #if defined(DEBUG)
715 	if (iosram_rw_active > iosram_rw_active_max) {
716 		iosram_rw_active_max = iosram_rw_active;
717 	}
718 #endif
719 	mutex_exit(&iosram_mutex);
720 
721 	IOSRAM_STAT(read);
722 	IOSRAM_STAT_ADD(bread, len);
723 
724 	/* Get starting address and map handle */
725 	iosramp = chunkp->basep + off;
726 	handle = iosram_handle;
727 
728 	/*
729 	 * Align the off to word boundary and then try reading/writing data
730 	 * using double word or word access.
731 	 */
732 	if ((boff = ((uintptr_t)iosramp & (UINT32SZ - 1))) != 0) {
733 		int	cnt = UINT32SZ - boff;
734 
735 		if (cnt > len) {
736 			cnt = len;
737 		}
738 		IOSRAMLOG(2,
739 		    "RD: align rep_get8(buf:%p sramp:%p cnt:%x) len:%x\n",
740 		    buf, iosramp, cnt, len);
741 		ddi_rep_get8(handle, buf, iosramp, cnt, DDI_DEV_AUTOINCR);
742 		buf += cnt;
743 		iosramp += cnt;
744 		len -= cnt;
745 	}
746 
747 	if ((len >= UINT64SZ) &&
748 	    ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT64SZ - 1)) == 0)) {
749 		/*
750 		 * Both source and destination are double word aligned
751 		 */
752 		int cnt = len/UINT64SZ;
753 
754 		IOSRAMLOG(2,
755 		    "RD: rep_get64(buf:%p sramp:%p cnt:%x) len:%x\n",
756 		    buf, iosramp, cnt, len);
757 		ddi_rep_get64(handle, (uint64_t *)buf, (uint64_t *)iosramp,
758 		    cnt, DDI_DEV_AUTOINCR);
759 		iosramp += cnt * UINT64SZ;
760 		buf += cnt * UINT64SZ;
761 		len -= cnt * UINT64SZ;
762 
763 		/*
764 		 * read remaining data using word and byte access
765 		 */
766 		if (len >= UINT32SZ) {
767 			IOSRAMLOG(2,
768 			    "RD: get32(buf:%p sramp:%p) len:%x\n",
769 			    buf, iosramp, len, NULL);
770 			*(uint32_t *)buf = ddi_get32(handle,
771 			    (uint32_t *)iosramp);
772 			iosramp += UINT32SZ;
773 			buf += UINT32SZ;
774 			len -= UINT32SZ;
775 		}
776 
777 		if (len != 0) {
778 			ddi_rep_get8(handle, buf, iosramp, len,
779 			    DDI_DEV_AUTOINCR);
780 		}
781 	} else if ((len >= UINT32SZ) &&
782 	    ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT32SZ - 1)) == 0)) {
783 		/*
784 		 * Both source and destination are word aligned
785 		 */
786 		int cnt = len/UINT32SZ;
787 
788 		IOSRAMLOG(2,
789 		    "RD: rep_get32(buf:%p sramp:%p cnt:%x) len:%x\n",
790 		    buf, iosramp, cnt, len);
791 		ddi_rep_get32(handle, (uint32_t *)buf, (uint32_t *)iosramp,
792 		    cnt, DDI_DEV_AUTOINCR);
793 		iosramp += cnt * UINT32SZ;
794 		buf += cnt * UINT32SZ;
795 		len -= cnt * UINT32SZ;
796 
797 		/*
798 		 * copy the remainder using byte access
799 		 */
800 		if (len != 0) {
801 			ddi_rep_get8(handle, buf, iosramp, len,
802 			    DDI_DEV_AUTOINCR);
803 		}
804 	} else if (len != 0) {
805 		/*
806 		 * We know that the "off" (i.e. iosramp) is at least word
807 		 * aligned. We need to read IOSRAM word at a time and copy it
808 		 * byte at a time.
809 		 */
810 		ASSERT(((uintptr_t)iosramp & (UINT32SZ - 1)) == 0);
811 
812 		IOSRAMLOG(2,
813 		    "RD: unaligned get32(buf:%p sramp:%p) len:%x\n",
814 		    buf, iosramp, len, NULL);
815 		for (; len >= UINT32SZ; len -= UINT32SZ, iosramp += UINT32SZ) {
816 			word.data =  ddi_get32(handle, (uint32_t *)iosramp);
817 			*buf++ = word.cbuf[0];
818 			*buf++ = word.cbuf[1];
819 			*buf++ = word.cbuf[2];
820 			*buf++ = word.cbuf[3];
821 		}
822 
823 		/*
824 		 * copy the remaining data using byte access
825 		 */
826 		if (len != 0) {
827 			ddi_rep_get8(handle, buf, iosramp, len,
828 			    DDI_DEV_AUTOINCR);
829 		}
830 	}
831 
832 	/*
833 	 * Reacquire mutex lock, decrement refcnt and if refcnt is 0 and any
834 	 * threads are waiting for r/w activity to complete, wake them up.
835 	 */
836 	mutex_enter(&iosram_mutex);
837 	ASSERT(iosram_rw_active > 0);
838 
839 	if ((--iosram_rw_active == 0) && iosram_rw_wakeup) {
840 		iosram_rw_wakeup = 0;
841 		cv_broadcast(&iosram_rw_wait);
842 	}
843 	mutex_exit(&iosram_mutex);
844 
845 	return (error);
846 }
847 
848 
849 /*
850  * _iosram_write(key, off, len, dptr, force)
851  *	Internal common routine to write to the IOSRAM.
852  */
853 static int
854 _iosram_write(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr, int force)
855 {
856 	iosram_chunk_t		*chunkp;
857 	uint32_t		chunk_len;
858 	uint8_t			*iosramp;
859 	ddi_acc_handle_t	handle;
860 	int			boff;
861 	union {
862 		uint8_t	cbuf[UINT32SZ];
863 		uint32_t data;
864 	} word;
865 
866 	int			error = 0;
867 	uint8_t			*buf = (uint8_t *)dptr;
868 
869 	/*
870 	 * We try to write to the IOSRAM using double word or word access
871 	 * provided both "off" and "buf" are (or can be) double word or word
872 	 * aligned.  Othewise, we try to align the "off" to a word boundary and
873 	 * then try to write data to the IOSRAM using word access, but read data
874 	 * from the buf buffer using byte access.
875 	 *
876 	 * If the leading/trailing portion of the IOSRAM data is not word
877 	 * aligned, it will always be written using byte access.
878 	 */
879 	IOSRAMLOG(1, "WR: key: 0x%x off:%x len:%x buf:%p\n",
880 	    key, off, len, buf);
881 
882 	/*
883 	 * Acquire lock and look for the requested chunk.  If it exists, make
884 	 * sure the requested write is within the chunk's bounds and no tunnel
885 	 * switch is active.
886 	 */
887 	mutex_enter(&iosram_mutex);
888 	chunkp = iosram_find_chunk(key);
889 	chunk_len = (chunkp != NULL) ? chunkp->toc_data.len : 0;
890 
891 	if (iosram_master == NULL) {
892 		error = EIO;
893 	} else if (chunkp == NULL) {
894 		error = EINVAL;
895 	} else if ((off >= chunk_len) || (len > chunk_len) ||
896 	    ((off+len) > chunk_len)) {
897 		error = EMSGSIZE;
898 	} else if (iosram_tswitch_active && !force) {
899 		error = EAGAIN;
900 	}
901 
902 	if (error) {
903 		mutex_exit(&iosram_mutex);
904 		return (error);
905 	}
906 
907 	/*
908 	 * If this is a forced write and there's a tunnel switch in progress,
909 	 * abort the switch.
910 	 */
911 	if (iosram_tswitch_active && force) {
912 		cmn_err(CE_NOTE, "!iosram: Aborting tswitch on force_write");
913 		iosram_abort_tswitch();
914 	}
915 
916 	/*
917 	 * Bump reference count to indicate #thread accessing IOSRAM
918 	 * and release the lock.
919 	 */
920 	iosram_rw_active++;
921 #if defined(DEBUG)
922 	if (iosram_rw_active > iosram_rw_active_max) {
923 		iosram_rw_active_max = iosram_rw_active;
924 	}
925 #endif
926 	mutex_exit(&iosram_mutex);
927 
928 
929 	IOSRAM_STAT(write);
930 	IOSRAM_STAT_ADD(bwrite, len);
931 
932 	/* Get starting address and map handle */
933 	iosramp = chunkp->basep + off;
934 	handle = iosram_handle;
935 
936 	/*
937 	 * Align the off to word boundary and then try reading/writing
938 	 * data using double word or word access.
939 	 */
940 	if ((boff = ((uintptr_t)iosramp & (UINT32SZ - 1))) != 0) {
941 		int	cnt = UINT32SZ - boff;
942 
943 		if (cnt > len) {
944 			cnt = len;
945 		}
946 		IOSRAMLOG(2,
947 		    "WR: align rep_put8(buf:%p sramp:%p cnt:%x) len:%x\n",
948 		    buf, iosramp, cnt, len);
949 		ddi_rep_put8(handle, buf, iosramp, cnt, DDI_DEV_AUTOINCR);
950 		buf += cnt;
951 		iosramp += cnt;
952 		len -= cnt;
953 	}
954 
955 	if ((len >= UINT64SZ) &&
956 	    ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT64SZ - 1)) == 0)) {
957 		/*
958 		 * Both source and destination are double word aligned
959 		 */
960 		int cnt = len/UINT64SZ;
961 
962 		IOSRAMLOG(2,
963 		    "WR: rep_put64(buf:%p sramp:%p cnt:%x) len:%x\n",
964 		    buf, iosramp, cnt, len);
965 		ddi_rep_put64(handle, (uint64_t *)buf, (uint64_t *)iosramp,
966 		    cnt, DDI_DEV_AUTOINCR);
967 		iosramp += cnt * UINT64SZ;
968 		buf += cnt * UINT64SZ;
969 		len -= cnt * UINT64SZ;
970 
971 		/*
972 		 * Copy the remaining data using word & byte access
973 		 */
974 		if (len >= UINT32SZ) {
975 			IOSRAMLOG(2,
976 			    "WR: put32(buf:%p sramp:%p) len:%x\n", buf, iosramp,
977 			    len, NULL);
978 			ddi_put32(handle, (uint32_t *)iosramp,
979 			    *(uint32_t *)buf);
980 			iosramp += UINT32SZ;
981 			buf += UINT32SZ;
982 			len -= UINT32SZ;
983 		}
984 
985 		if (len != 0) {
986 			ddi_rep_put8(handle, buf, iosramp, len,
987 			    DDI_DEV_AUTOINCR);
988 		}
989 	} else if ((len >= UINT32SZ) &&
990 	    ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT32SZ - 1)) == 0)) {
991 		/*
992 		 * Both source and destination are word aligned
993 		 */
994 		int cnt = len/UINT32SZ;
995 
996 		IOSRAMLOG(2,
997 		    "WR: rep_put32(buf:%p sramp:%p cnt:%x) len:%x\n",
998 		    buf, iosramp, cnt, len);
999 		ddi_rep_put32(handle, (uint32_t *)buf, (uint32_t *)iosramp,
1000 		    cnt, DDI_DEV_AUTOINCR);
1001 		iosramp += cnt * UINT32SZ;
1002 		buf += cnt * UINT32SZ;
1003 		len -= cnt * UINT32SZ;
1004 
1005 		/*
1006 		 * copy the remainder using byte access
1007 		 */
1008 		if (len != 0) {
1009 			ddi_rep_put8(handle, buf, iosramp, len,
1010 			    DDI_DEV_AUTOINCR);
1011 		}
1012 	} else if (len != 0) {
1013 		/*
1014 		 * We know that the "off" is at least word aligned. We
1015 		 * need to read data from buf buffer byte at a time, and
1016 		 * write it to the IOSRAM word at a time.
1017 		 */
1018 
1019 		ASSERT(((uintptr_t)iosramp & (UINT32SZ - 1)) == 0);
1020 
1021 		IOSRAMLOG(2,
1022 		    "WR: unaligned put32(buf:%p sramp:%p) len:%x\n",
1023 		    buf, iosramp, len, NULL);
1024 		for (; len >= UINT32SZ; len -= UINT32SZ, iosramp += UINT32SZ) {
1025 			word.cbuf[0] = *buf++;
1026 			word.cbuf[1] = *buf++;
1027 			word.cbuf[2] = *buf++;
1028 			word.cbuf[3] = *buf++;
1029 			ddi_put32(handle, (uint32_t *)iosramp, word.data);
1030 		}
1031 
1032 		/*
1033 		 * copy the remaining data using byte access
1034 		 */
1035 		if (len != 0) {
1036 			ddi_rep_put8(handle, buf, iosramp,
1037 			    len, DDI_DEV_AUTOINCR);
1038 		}
1039 	}
1040 
1041 	/*
1042 	 * Reacquire mutex lock, decrement refcnt and if refcnt is 0 and
1043 	 * any threads are waiting for r/w activity to complete, wake them up.
1044 	 */
1045 	mutex_enter(&iosram_mutex);
1046 	ASSERT(iosram_rw_active > 0);
1047 
1048 	if ((--iosram_rw_active == 0) && iosram_rw_wakeup) {
1049 		iosram_rw_wakeup = 0;
1050 		cv_broadcast(&iosram_rw_wait);
1051 	}
1052 	mutex_exit(&iosram_mutex);
1053 
1054 	return (error);
1055 }
1056 
1057 
1058 int
1059 iosram_force_write(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr)
1060 {
1061 	return (_iosram_write(key, off, len, dptr, 1 /* force */));
1062 }
1063 
1064 
1065 int
1066 iosram_wr(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr)
1067 {
1068 	return (_iosram_write(key, off, len, dptr, 0));
1069 }
1070 
1071 
1072 /*
1073  * iosram_register(key, handler, arg)
1074  *	Register a handler and an arg for the specified chunk.  This handler
1075  *	will be invoked when an interrupt is received from the other side and
1076  *	the int_pending flag for the corresponding key is marked
1077  *	IOSRAM_INT_TO_DOM.
1078  */
1079 /* ARGSUSED */
1080 int
1081 iosram_register(uint32_t key, void (*handler)(), void *arg)
1082 {
1083 	struct iosram_chunk	*chunkp;
1084 	int			error = 0;
1085 
1086 	/*
1087 	 * Acquire lock and look for the requested chunk.  If it exists, and no
1088 	 * other callback is registered, proceed with the registration.
1089 	 */
1090 	mutex_enter(&iosram_mutex);
1091 	chunkp = iosram_find_chunk(key);
1092 
1093 	if (iosram_master == NULL) {
1094 		error = EIO;
1095 	} else if (chunkp == NULL) {
1096 		error = EINVAL;
1097 	} else if (chunkp->cback.handler != NULL) {
1098 		error = EBUSY;
1099 	} else {
1100 		chunkp->cback.busy = 0;
1101 		chunkp->cback.unregister = 0;
1102 		chunkp->cback.handler = handler;
1103 		chunkp->cback.arg = arg;
1104 	}
1105 	mutex_exit(&iosram_mutex);
1106 
1107 	IOSRAMLOG(1, "REG: key: 0x%x hdlr:%p arg:%p error:%d\n",
1108 	    key, handler, arg, error);
1109 
1110 	return (error);
1111 }
1112 
1113 
1114 /*
1115  * iosram_unregister()
1116  *	Unregister handler associated with the specified chunk.
1117  */
1118 int
1119 iosram_unregister(uint32_t key)
1120 {
1121 	struct iosram_chunk	*chunkp;
1122 	int			error = 0;
1123 
1124 	/*
1125 	 * Acquire lock and look for the requested chunk.  If it exists and has
1126 	 * a callback registered, unregister it.
1127 	 */
1128 	mutex_enter(&iosram_mutex);
1129 	chunkp = iosram_find_chunk(key);
1130 
1131 	if (iosram_master == NULL) {
1132 		error = EIO;
1133 	} else if (chunkp == NULL) {
1134 		error = EINVAL;
1135 	} else if (chunkp->cback.busy) {
1136 		/*
1137 		 * If the handler is already busy (being invoked), then we flag
1138 		 * it so it will be unregistered after the invocation completes.
1139 		 */
1140 		DPRINTF(1, ("IOSRAM(%d): unregister: delaying unreg k:0x%08x\n",
1141 		    iosram_master->instance, key));
1142 		chunkp->cback.unregister = 1;
1143 	} else if (chunkp->cback.handler != NULL) {
1144 		chunkp->cback.handler = NULL;
1145 		chunkp->cback.arg = NULL;
1146 	}
1147 	mutex_exit(&iosram_mutex);
1148 
1149 	IOSRAMLOG(1, "UNREG: key:%x error:%d\n", key, error, NULL, NULL);
1150 	return (error);
1151 }
1152 
1153 
1154 /*
1155  * iosram_get_flag():
1156  *	Get data_valid and/or int_pending flags associated with the
1157  *	specified key.
1158  */
1159 int
1160 iosram_get_flag(uint32_t key, uint8_t *data_valid, uint8_t *int_pending)
1161 {
1162 	iosram_chunk_t	*chunkp;
1163 	iosram_flags_t	flags;
1164 	int		error = 0;
1165 
1166 	/*
1167 	 * Acquire lock and look for the requested chunk.  If it exists, and no
1168 	 * tunnel switch is in progress, read the chunk's flags.
1169 	 */
1170 	mutex_enter(&iosram_mutex);
1171 	chunkp = iosram_find_chunk(key);
1172 
1173 	if (iosram_master == NULL) {
1174 		error = EIO;
1175 	} else if (chunkp == NULL) {
1176 		error = EINVAL;
1177 	} else if (iosram_tswitch_active) {
1178 		error = EAGAIN;
1179 	} else {
1180 		IOSRAM_STAT(getflag);
1181 
1182 		/*
1183 		 * Read the flags
1184 		 */
1185 		ddi_rep_get8(iosram_handle, (uint8_t *)&flags,
1186 		    (uint8_t *)(chunkp->flagsp), sizeof (iosram_flags_t),
1187 		    DDI_DEV_AUTOINCR);
1188 
1189 		/*
1190 		 * Get each flag value that the caller is interested in.
1191 		 */
1192 		if (data_valid != NULL) {
1193 			*data_valid = flags.data_valid;
1194 		}
1195 
1196 		if (int_pending != NULL) {
1197 			*int_pending = flags.int_pending;
1198 		}
1199 	}
1200 	mutex_exit(&iosram_mutex);
1201 
1202 	IOSRAMLOG(1, "GetFlag key:%x data_valid:%x int_pending:%x error:%d\n",
1203 	    key, flags.data_valid, flags.int_pending, error);
1204 	return (error);
1205 }
1206 
1207 
1208 /*
1209  * iosram_set_flag():
1210  *	Set data_valid and int_pending flags associated with the specified key.
1211  */
1212 int
1213 iosram_set_flag(uint32_t key, uint8_t data_valid, uint8_t int_pending)
1214 {
1215 	iosram_chunk_t	*chunkp;
1216 	iosram_flags_t	flags;
1217 	int		error = 0;
1218 
1219 	/*
1220 	 * Acquire lock and look for the requested chunk.  If it exists, and no
1221 	 * tunnel switch is in progress, write the chunk's flags.
1222 	 */
1223 	mutex_enter(&iosram_mutex);
1224 	chunkp = iosram_find_chunk(key);
1225 
1226 	if (iosram_master == NULL) {
1227 		error = EIO;
1228 	} else if ((chunkp == NULL) ||
1229 	    ((data_valid != IOSRAM_DATA_INVALID) &&
1230 	    (data_valid != IOSRAM_DATA_VALID)) ||
1231 	    ((int_pending != IOSRAM_INT_NONE) &&
1232 	    (int_pending != IOSRAM_INT_TO_SSC) &&
1233 	    (int_pending != IOSRAM_INT_TO_DOM))) {
1234 		error = EINVAL;
1235 	} else if (iosram_tswitch_active) {
1236 		error = EAGAIN;
1237 	} else {
1238 		IOSRAM_STAT(setflag);
1239 		flags.data_valid = data_valid;
1240 		flags.int_pending = int_pending;
1241 		ddi_rep_put8(iosram_handle, (uint8_t *)&flags,
1242 		    (uint8_t *)(chunkp->flagsp), sizeof (iosram_flags_t),
1243 		    DDI_DEV_AUTOINCR);
1244 	}
1245 	mutex_exit(&iosram_mutex);
1246 
1247 	IOSRAMLOG(1, "SetFlag key:%x data_valid:%x int_pending:%x error:%d\n",
1248 	    key, flags.data_valid, flags.int_pending, error);
1249 	return (error);
1250 }
1251 
1252 
1253 /*
1254  * iosram_ctrl()
1255  *	This function provides access to a variety of services not available
1256  *	through the basic API.
1257  */
1258 int
1259 iosram_ctrl(uint32_t key, uint32_t cmd, void *arg)
1260 {
1261 	struct iosram_chunk	*chunkp;
1262 	int			error = 0;
1263 
1264 	/*
1265 	 * Acquire lock and do some argument sanity checking.
1266 	 */
1267 	mutex_enter(&iosram_mutex);
1268 	chunkp = iosram_find_chunk(key);
1269 
1270 	if (iosram_master == NULL) {
1271 		error = EIO;
1272 	} else if (chunkp == NULL) {
1273 		error = EINVAL;
1274 	}
1275 
1276 	if (error != 0) {
1277 		mutex_exit(&iosram_mutex);
1278 		return (error);
1279 	}
1280 
1281 	/*
1282 	 * Arguments seem okay so far, so process the command.
1283 	 */
1284 	switch (cmd) {
1285 		case IOSRAM_CMD_CHUNKLEN:
1286 			/*
1287 			 * Return the length of the chunk indicated by the key.
1288 			 */
1289 			if (arg == NULL) {
1290 				error = EINVAL;
1291 				break;
1292 			}
1293 
1294 			*(uint32_t *)arg = chunkp->toc_data.len;
1295 			break;
1296 
1297 		default:
1298 			error = ENOTSUP;
1299 			break;
1300 	}
1301 
1302 	mutex_exit(&iosram_mutex);
1303 	return (error);
1304 }
1305 
1306 
1307 /*
1308  * iosram_hdr_ctrl()
1309  *	This function provides an interface for the Mailbox Protocol
1310  *	implementation to use when interacting with the IOSRAM header.
1311  */
1312 int
1313 iosram_hdr_ctrl(uint32_t cmd, void *arg)
1314 {
1315 	int	error = 0;
1316 
1317 	/*
1318 	 * Acquire lock and do some argument sanity checking.
1319 	 */
1320 	mutex_enter(&iosram_mutex);
1321 
1322 	if (iosram_master == NULL) {
1323 		error = EIO;
1324 	}
1325 
1326 	if (error != 0) {
1327 		mutex_exit(&iosram_mutex);
1328 		return (error);
1329 	}
1330 
1331 	switch (cmd) {
1332 		case IOSRAM_HDRCMD_GET_SMS_MBOX_VER:
1333 			/*
1334 			 * Return the value of the sms_mbox_version field.
1335 			 */
1336 			if (arg == NULL) {
1337 				error = EINVAL;
1338 				break;
1339 			}
1340 
1341 			*(uint32_t *)arg = IOSRAM_GET_HDRFIELD32(iosram_master,
1342 			    sms_mbox_version);
1343 			break;
1344 
1345 		case IOSRAM_HDRCMD_SET_OS_MBOX_VER:
1346 			/*
1347 			 * Set the value of the os_mbox_version field.
1348 			 */
1349 			IOSRAM_SET_HDRFIELD32(iosram_master, os_mbox_version,
1350 			    (uint32_t)(uintptr_t)arg);
1351 			IOSRAM_SET_HDRFIELD32(iosram_master, os_change_mask,
1352 			    IOSRAM_HDRFIELD_OS_MBOX_VER);
1353 			(void) iosram_send_intr();
1354 			break;
1355 
1356 		case IOSRAM_HDRCMD_REG_CALLBACK:
1357 			iosram_hdrchange_handler = (void (*)())arg;
1358 			break;
1359 
1360 		default:
1361 			error = ENOTSUP;
1362 			break;
1363 	}
1364 
1365 	mutex_exit(&iosram_mutex);
1366 	return (error);
1367 }
1368 
1369 
1370 /*
1371  * iosram_softintr()
1372  *	IOSRAM soft interrupt handler
1373  */
1374 static uint_t
1375 iosram_softintr(caddr_t arg)
1376 {
1377 	uint32_t	hdr_changes;
1378 	iosramsoft_t	*softp = (iosramsoft_t *)arg;
1379 	iosram_chunk_t	*chunkp;
1380 	void		(*handler)();
1381 	int		i;
1382 	uint8_t		flag;
1383 
1384 	DPRINTF(1, ("iosram(%d): in iosram_softintr\n", softp->instance));
1385 
1386 	IOSRAMLOG(2, "SINTR arg/softp:%p  pending:%d busy:%d\n",
1387 	    arg, softp->intr_pending, softp->intr_busy, NULL);
1388 
1389 	mutex_enter(&iosram_mutex);
1390 	mutex_enter(&softp->intr_mutex);
1391 
1392 	/*
1393 	 * Do not process interrupt if interrupt handler is already running or
1394 	 * no interrupts are pending.
1395 	 */
1396 	if (softp->intr_busy || !softp->intr_pending) {
1397 		mutex_exit(&softp->intr_mutex);
1398 		mutex_exit(&iosram_mutex);
1399 		DPRINTF(1, ("IOSRAM(%d): softintr: busy=%d pending=%d\n",
1400 		    softp->instance, softp->intr_busy, softp->intr_pending));
1401 		return (softp->intr_pending ? DDI_INTR_CLAIMED :
1402 		    DDI_INTR_UNCLAIMED);
1403 	}
1404 
1405 	/*
1406 	 * It's possible for the SC to send an interrupt on the new master
1407 	 * before we are able to set our internal state.  If so, we'll retrigger
1408 	 * soft interrupt right after tunnel switch completion.
1409 	 */
1410 	if (softp->state & IOSRAM_STATE_TSWITCH) {
1411 		mutex_exit(&softp->intr_mutex);
1412 		mutex_exit(&iosram_mutex);
1413 		DPRINTF(1, ("IOSRAM(%d): softintr: doing switch "
1414 		    "state=0x%x\n", softp->instance, softp->state));
1415 		return (DDI_INTR_CLAIMED);
1416 	}
1417 
1418 	/*
1419 	 * Do not process interrupt if we are not the master.
1420 	 */
1421 	if (!(softp->state & IOSRAM_STATE_MASTER)) {
1422 		mutex_exit(&softp->intr_mutex);
1423 		mutex_exit(&iosram_mutex);
1424 		DPRINTF(1, ("IOSRAM(%d): softintr: no master state=0x%x\n ",
1425 		    softp->instance, softp->state));
1426 		return (DDI_INTR_CLAIMED);
1427 	}
1428 
1429 	IOSRAM_STAT(sintr_recv);
1430 
1431 	/*
1432 	 * If the driver is suspended, then we should not process any
1433 	 * interrupts.  Instead, we trigger a soft interrupt when the driver
1434 	 * resumes.
1435 	 */
1436 	if (softp->suspended) {
1437 		mutex_exit(&softp->intr_mutex);
1438 		mutex_exit(&iosram_mutex);
1439 		DPRINTF(1, ("IOSRAM(%d): softintr: suspended\n",
1440 		    softp->instance));
1441 		return (DDI_INTR_CLAIMED);
1442 	}
1443 
1444 	/*
1445 	 * Indicate that the IOSRAM interrupt handler is busy.  Note that this
1446 	 * includes incrementing the reader/writer count, since we don't want
1447 	 * any tunnel switches to start up while we're processing callbacks.
1448 	 */
1449 	softp->intr_busy = 1;
1450 	iosram_rw_active++;
1451 #if defined(DEBUG)
1452 	if (iosram_rw_active > iosram_rw_active_max) {
1453 		iosram_rw_active_max = iosram_rw_active;
1454 	}
1455 #endif
1456 
1457 	do {
1458 		DPRINTF(1, ("IOSRAM(%d): softintr: processing interrupt\n",
1459 		    softp->instance));
1460 
1461 		softp->intr_pending = 0;
1462 
1463 		mutex_exit(&softp->intr_mutex);
1464 
1465 		/*
1466 		 * Process changes to the IOSRAM header.
1467 		 */
1468 		hdr_changes = IOSRAM_GET_HDRFIELD32(iosram_master,
1469 		    sms_change_mask);
1470 		if (hdr_changes != 0) {
1471 			int	error;
1472 
1473 			IOSRAM_SET_HDRFIELD32(iosram_master, sms_change_mask,
1474 			    0);
1475 			if (hdr_changes & IOSRAM_HDRFIELD_TOC_INDEX) {
1476 				/*
1477 				 * XXX is it safe to temporarily release the
1478 				 * iosram_mutex here?
1479 				 */
1480 				mutex_exit(&iosram_mutex);
1481 				error = iosram_read_toc(iosram_master);
1482 				mutex_enter(&iosram_mutex);
1483 				if (error) {
1484 					cmn_err(CE_WARN, "iosram_read_toc: new"
1485 					    " TOC invalid; using old TOC.");
1486 				}
1487 				iosram_update_addrs(iosram_master);
1488 			}
1489 
1490 			if (iosram_hdrchange_handler != NULL) {
1491 				mutex_exit(&iosram_mutex);
1492 				iosram_hdrchange_handler();
1493 				mutex_enter(&iosram_mutex);
1494 			}
1495 		}
1496 
1497 		/*
1498 		 * Get data_valid/int_pending flags and generate a callback if
1499 		 * applicable.  For now, we read only those flags for which a
1500 		 * callback has been registered.  We can optimize reading of
1501 		 * flags by reading them all at once and then process them
1502 		 * later.
1503 		 */
1504 		for (i = 0, chunkp = chunks; i < nchunks; i++,
1505 		    chunkp++) {
1506 #if DEBUG
1507 			flag =  ddi_get8(iosram_handle,
1508 			    &(chunkp->flagsp->int_pending));
1509 			DPRINTF(1, ("IOSRAM(%d): softintr chunk #%d "
1510 			    "flag=0x%x handler=%p\n",
1511 			    softp->instance, i, (int)flag,
1512 			    (void *)chunkp->cback.handler));
1513 #endif
1514 			if ((handler = chunkp->cback.handler) == NULL) {
1515 				continue;
1516 			}
1517 			flag = ddi_get8(iosram_handle,
1518 			    &(chunkp->flagsp->int_pending));
1519 			if (flag == IOSRAM_INT_TO_DOM) {
1520 				DPRINTF(1,
1521 				    ("IOSRAM(%d): softintr: invoking handler\n",
1522 				    softp->instance));
1523 				IOSRAMLOG(1,
1524 				    "SINTR invoking hdlr:%p arg:%p index:%d\n",
1525 				    handler, chunkp->cback.arg, i, NULL);
1526 				IOSRAM_STAT(callbacks);
1527 
1528 				ddi_put8(iosram_handle,
1529 				    &(chunkp->flagsp->int_pending),
1530 				    IOSRAM_INT_NONE);
1531 				chunkp->cback.busy = 1;
1532 				mutex_exit(&iosram_mutex);
1533 				(*handler)(chunkp->cback.arg);
1534 				mutex_enter(&iosram_mutex);
1535 				chunkp->cback.busy = 0;
1536 
1537 				/*
1538 				 * If iosram_unregister was called while the
1539 				 * callback was being invoked, complete the
1540 				 * unregistration here.
1541 				 */
1542 				if (chunkp->cback.unregister) {
1543 					DPRINTF(1, ("IOSRAM(%d): softintr: "
1544 					    "delayed unreg k:0x%08x\n",
1545 					    softp->instance,
1546 					    chunkp->toc_data.key));
1547 					chunkp->cback.handler = NULL;
1548 					chunkp->cback.arg = NULL;
1549 					chunkp->cback.unregister = 0;
1550 				}
1551 			}
1552 
1553 			/*
1554 			 * If there's a tunnel switch waiting to run, give it
1555 			 * higher priority than these callbacks by bailing out.
1556 			 * They'll still be invoked on the new master iosram
1557 			 * when the tunnel switch is done.
1558 			 */
1559 			if (iosram_tswitch_active) {
1560 				break;
1561 			}
1562 		}
1563 
1564 		mutex_enter(&softp->intr_mutex);
1565 
1566 	} while (softp->intr_pending && !softp->suspended &&
1567 	    !iosram_tswitch_active);
1568 
1569 	/*
1570 	 * Indicate IOSRAM interrupt handler is not BUSY any more
1571 	 */
1572 	softp->intr_busy = 0;
1573 
1574 	ASSERT(iosram_rw_active > 0);
1575 	if ((--iosram_rw_active == 0) && iosram_rw_wakeup) {
1576 		iosram_rw_wakeup = 0;
1577 		cv_broadcast(&iosram_rw_wait);
1578 	}
1579 
1580 	mutex_exit(&softp->intr_mutex);
1581 	mutex_exit(&iosram_mutex);
1582 
1583 	DPRINTF(1, ("iosram(%d): softintr exit\n", softp->instance));
1584 
1585 	return (DDI_INTR_CLAIMED);
1586 }
1587 
1588 
1589 /*
1590  * iosram_intr()
1591  *	IOSRAM real interrupt handler
1592  */
1593 static uint_t
1594 iosram_intr(caddr_t arg)
1595 {
1596 	iosramsoft_t	*softp = (iosramsoft_t *)arg;
1597 	int		result = DDI_INTR_UNCLAIMED;
1598 	uint32_t	int_status;
1599 
1600 	DPRINTF(2, ("iosram(%d): in iosram_intr\n", softp->instance));
1601 
1602 	mutex_enter(&softp->intr_mutex);
1603 
1604 	if (softp->sbbc_handle == NULL) {
1605 		/*
1606 		 * The SBBC registers region is not mapped in.
1607 		 * Set the interrupt pending flag here, and process the
1608 		 * interrupt after the tunnel switch.
1609 		 */
1610 		DPRINTF(1, ("IOSRAM(%d): iosram_intr: SBBC not mapped\n",
1611 		    softp->instance));
1612 		softp->intr_pending = 1;
1613 		mutex_exit(&softp->intr_mutex);
1614 		return (DDI_INTR_UNCLAIMED);
1615 	}
1616 
1617 	int_status = ddi_get32(softp->sbbc_handle,
1618 	    &(softp->sbbc_region->int_status.reg));
1619 	DPRINTF(1, ("iosram_intr: int_status = 0x%08x\n", int_status));
1620 
1621 	if (int_status & IOSRAM_SBBC_INT0) {
1622 		result = DDI_INTR_CLAIMED;
1623 		DPRINTF(1, ("iosram_intr: int0 detected!\n"));
1624 	}
1625 
1626 	if (int_status & IOSRAM_SBBC_INT1) {
1627 		result = DDI_INTR_CLAIMED;
1628 		DPRINTF(1, ("iosram_intr: int1 detected!\n"));
1629 	}
1630 
1631 	if (result == DDI_INTR_CLAIMED) {
1632 		ddi_put32(softp->sbbc_handle,
1633 		    &(softp->sbbc_region->int_status.reg), int_status);
1634 		int_status = ddi_get32(softp->sbbc_handle,
1635 		    &(softp->sbbc_region->int_status.reg));
1636 		DPRINTF(1, ("iosram_intr: int_status = 0x%08x\n",
1637 		    int_status));
1638 
1639 		softp->intr_pending = 1;
1640 		/*
1641 		 * Trigger soft interrupt if not executing and
1642 		 * not suspended.
1643 		 */
1644 		if (!softp->intr_busy && !softp->suspended &&
1645 		    (softp->softintr_id != NULL)) {
1646 			DPRINTF(1, ("iosram(%d): trigger softint\n",
1647 			    softp->instance));
1648 			ddi_trigger_softintr(softp->softintr_id);
1649 		}
1650 	}
1651 
1652 	IOSRAM_STAT(intr_recv);
1653 
1654 	mutex_exit(&softp->intr_mutex);
1655 
1656 	IOSRAMLOG(2, "INTR arg/softp:%p  pending:%d busy:%d\n",
1657 	    arg, softp->intr_pending, softp->intr_busy, NULL);
1658 	DPRINTF(1, ("iosram(%d): iosram_intr exit\n", softp->instance));
1659 
1660 	return (result);
1661 }
1662 
1663 
1664 /*
1665  * iosram_send_intr()
1666  *	Send an interrupt to the SSP side via AXQ driver
1667  */
1668 int
1669 iosram_send_intr()
1670 {
1671 	IOSRAMLOG(1, "SendIntr called\n", NULL, NULL, NULL, NULL);
1672 	IOSRAM_STAT(intr_send);
1673 	DPRINTF(1, ("iosram iosram_send_intr invoked\n"));
1674 
1675 	return (axq_cpu2ssc_intr(0));
1676 }
1677 
1678 
1679 #if defined(DEBUG)
1680 static void
1681 iosram_dummy_cback(void *arg)
1682 {
1683 	DPRINTF(1, ("iosram_dummy_cback invoked arg:%p\n", arg));
1684 }
1685 #endif /* DEBUG */
1686 
1687 
1688 /*ARGSUSED1*/
1689 static int
1690 iosram_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1691 		int *rvalp)
1692 {
1693 	struct iosramsoft	*softp;
1694 	int			error = DDI_SUCCESS;
1695 
1696 	softp = ddi_get_soft_state(iosramsoft_statep, getminor(dev));
1697 	if (softp == NULL) {
1698 		return (ENXIO);
1699 	}
1700 	IOSRAMLOG(1, "IOCTL: dev:%p cmd:%x arg:%p ... instance %d\n",
1701 	    dev, cmd, arg, softp->instance);
1702 
1703 	switch (cmd) {
1704 #if defined(DEBUG)
1705 	case IOSRAM_GET_FLAG:
1706 		{
1707 		iosram_io_t	req;
1708 		uint8_t		data_valid, int_pending;
1709 
1710 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
1711 			return (EFAULT);
1712 		}
1713 
1714 		DPRINTF(2, ("IOSRAM_GET_FLAG(key:%x\n", req.key));
1715 
1716 		req.retval = iosram_get_flag(req.key, &data_valid,
1717 		    &int_pending);
1718 		req.data_valid = (uint32_t)data_valid;
1719 		req.int_pending = (uint32_t)int_pending;
1720 
1721 		if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
1722 			DPRINTF(1,
1723 			    ("IOSRAM_GET_FLAG: can't copyout req.retval (%x)",
1724 			    req.retval));
1725 			error = EFAULT;
1726 		}
1727 
1728 		return (error);
1729 		}
1730 
1731 	case IOSRAM_SET_FLAG:
1732 		{
1733 		iosram_io_t	req;
1734 
1735 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
1736 			return (EFAULT);
1737 		}
1738 
1739 		DPRINTF(2, ("IOSRAM_SET_FLAG(key:%x data_valid:%x "
1740 		    "int_pending:%x\n", req.key, req.data_valid,
1741 		    req.int_pending));
1742 
1743 		req.retval = iosram_set_flag(req.key, req.data_valid,
1744 		    req.int_pending);
1745 
1746 		if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
1747 			DPRINTF(1, ("IOSRAM_SET_FLAG: can't copyout req.retval"
1748 			    " (%x)\n", req.retval));
1749 			error = EFAULT;
1750 		}
1751 
1752 		return (error);
1753 		}
1754 
1755 	case IOSRAM_RD:
1756 		{
1757 		caddr_t		bufp;
1758 		int		len;
1759 		iosram_io_t	req;
1760 
1761 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
1762 			return (EFAULT);
1763 		}
1764 
1765 		DPRINTF(2, ("IOSRAM_RD(k:%x o:%x len:%x bufp:%p\n", req.key,
1766 		    req.off, req.len, (void *)(uintptr_t)req.bufp));
1767 
1768 		len = req.len;
1769 		bufp = kmem_alloc(len, KM_SLEEP);
1770 
1771 		req.retval = iosram_rd(req.key, req.off, req.len, bufp);
1772 
1773 		if (ddi_copyout(bufp, (void *)(uintptr_t)req.bufp, len, mode)) {
1774 			DPRINTF(1, ("IOSRAM_RD: copyout(%p, %p,%x,%x) failed\n",
1775 			    (void *)bufp, (void *)(uintptr_t)req.bufp, len,
1776 			    mode));
1777 			error = EFAULT;
1778 		} else if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
1779 			DPRINTF(1, ("IOSRAM_RD: can't copyout retval (%x)\n",
1780 			    req.retval));
1781 			error = EFAULT;
1782 		}
1783 
1784 		kmem_free(bufp, len);
1785 		return (error);
1786 		}
1787 
1788 	case IOSRAM_WR:
1789 		{
1790 		caddr_t		bufp;
1791 		iosram_io_t	req;
1792 		int		len;
1793 
1794 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
1795 			return (EFAULT);
1796 		}
1797 
1798 		DPRINTF(2, ("IOSRAM_WR(k:%x o:%x len:%x bufp:%p\n",
1799 		    req.key, req.off, req.len, (void *)(uintptr_t)req.bufp));
1800 		len = req.len;
1801 		bufp = kmem_alloc(len, KM_SLEEP);
1802 		if (ddi_copyin((void *)(uintptr_t)req.bufp, bufp, len, mode)) {
1803 			error = EFAULT;
1804 		} else {
1805 			req.retval = iosram_wr(req.key, req.off, req.len,
1806 			    bufp);
1807 
1808 			if (ddi_copyout(&req, (void *)arg, sizeof (req),
1809 			    mode)) {
1810 				error = EFAULT;
1811 			}
1812 		}
1813 		kmem_free(bufp, len);
1814 		return (error);
1815 		}
1816 
1817 	case IOSRAM_TOC:
1818 		{
1819 		caddr_t		bufp;
1820 		int		len;
1821 		iosram_io_t	req;
1822 
1823 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
1824 			return (EFAULT);
1825 		}
1826 
1827 		DPRINTF(2, ("IOSRAM_TOC (req.bufp:%x req.len:%x) \n",
1828 		    req.bufp, req.len));
1829 
1830 		len = req.len;
1831 		bufp = kmem_alloc(len, KM_SLEEP);
1832 
1833 		req.retval = iosram_get_keys((iosram_toc_entry_t *)bufp,
1834 		    &req.len);
1835 
1836 		if (ddi_copyout(bufp, (void *)(uintptr_t)req.bufp, req.len,
1837 		    mode)) {
1838 			DPRINTF(1,
1839 			    ("IOSRAM_TOC: copyout(%p, %p,%x,%x) failed\n",
1840 			    (void *)bufp, (void *)(uintptr_t)req.bufp, req.len,
1841 			    mode));
1842 			error = EFAULT;
1843 		} else if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
1844 			DPRINTF(1, ("IOSRAM_TOC: can't copyout retval (%x)\n",
1845 			    req.retval));
1846 			error = EFAULT;
1847 		}
1848 		kmem_free(bufp, len);
1849 		return (error);
1850 		}
1851 
1852 	case IOSRAM_SEND_INTR:
1853 		{
1854 		DPRINTF(2, ("IOSRAM_SEND_INTR\n"));
1855 
1856 		switch ((int)arg) {
1857 		case 0x11:
1858 		case 0x22:
1859 		case 0x44:
1860 		case 0x88:
1861 			ddi_put32(softp->sbbc_handle,
1862 			    &(softp->sbbc_region->int_enable.reg), (int)arg);
1863 			DPRINTF(1, ("Wrote 0x%x to int_enable.reg\n",
1864 			    (int)arg));
1865 			break;
1866 		case 0xBB:
1867 			ddi_put32(softp->sbbc_handle,
1868 			    &(softp->sbbc_region->p0_int_gen.reg), 1);
1869 			DPRINTF(1, ("Wrote 1 to p0_int_gen.reg\n"));
1870 			break;
1871 		default:
1872 			error = iosram_send_intr();
1873 		}
1874 
1875 		return (error);
1876 		}
1877 
1878 	case IOSRAM_PRINT_CBACK:
1879 		iosram_print_cback();
1880 		break;
1881 
1882 	case IOSRAM_PRINT_STATE:
1883 		iosram_print_state((int)arg);
1884 		break;
1885 
1886 #if IOSRAM_STATS
1887 	case IOSRAM_PRINT_STATS:
1888 		iosram_print_stats();
1889 		break;
1890 #endif
1891 
1892 #if IOSRAM_LOG
1893 	case IOSRAM_PRINT_LOG:
1894 		iosram_print_log((int)arg);
1895 		break;
1896 #endif
1897 
1898 	case IOSRAM_TUNNEL_SWITCH:
1899 		error = iosram_switchfrom((int)arg);
1900 		break;
1901 
1902 	case IOSRAM_PRINT_FLAGS:
1903 		iosram_print_flags();
1904 		break;
1905 
1906 	case IOSRAM_REG_CBACK:
1907 		{
1908 		iosram_io_t	req;
1909 
1910 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
1911 			return (EFAULT);
1912 		}
1913 
1914 		DPRINTF(2, ("IOSRAM_REG_CBACK(k:%x)\n", req.key));
1915 
1916 		req.retval = iosram_register(req.key, iosram_dummy_cback,
1917 		    (void *)(uintptr_t)req.key);
1918 		if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
1919 			error = EFAULT;
1920 		}
1921 
1922 		return (error);
1923 		}
1924 
1925 	case IOSRAM_UNREG_CBACK:
1926 		{
1927 		iosram_io_t	req;
1928 
1929 		if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) {
1930 			return (EFAULT);
1931 		}
1932 
1933 		DPRINTF(2, ("IOSRAM_REG_CBACK(k:%x)\n", req.key));
1934 
1935 		req.retval = iosram_unregister(req.key);
1936 		if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) {
1937 			error = EFAULT;
1938 		}
1939 
1940 		return (error);
1941 		}
1942 
1943 	case IOSRAM_SEMA_ACQUIRE:
1944 	{
1945 		DPRINTF(1, ("IOSRAM_SEMA_ACQUIRE\n"));
1946 		error = iosram_sema_acquire(NULL);
1947 		return (error);
1948 	}
1949 
1950 	case IOSRAM_SEMA_RELEASE:
1951 	{
1952 		DPRINTF(1, ("IOSRAM_SEMA_RELEASE\n"));
1953 		error = iosram_sema_release();
1954 		return (error);
1955 	}
1956 
1957 #endif /* DEBUG */
1958 
1959 	default:
1960 		DPRINTF(1, ("iosram_ioctl: Illegal command %x\n", cmd));
1961 		error = ENOTTY;
1962 	}
1963 
1964 	return (error);
1965 }
1966 
1967 
1968 /*
1969  * iosram_switch_tunnel(softp)
1970  *	Switch master tunnel to the specified instance
1971  *	Must be called while holding iosram_mutex
1972  */
1973 /*ARGSUSED*/
1974 static int
1975 iosram_switch_tunnel(iosramsoft_t *softp)
1976 {
1977 #ifdef DEBUG
1978 	int		instance = softp->instance;
1979 #endif
1980 	int		error = 0;
1981 	iosramsoft_t	*prev_master;
1982 
1983 	ASSERT(mutex_owned(&iosram_mutex));
1984 
1985 	DPRINTF(1, ("tunnel switch new master:%p (%d) current master:%p (%d)\n",
1986 	    (void *)softp, instance, (void *)iosram_master,
1987 	    ((iosram_master) ? iosram_master->instance : -1)));
1988 	IOSRAMLOG(1, "TSWTCH: new_master:%p (%p) iosram_master:%p (%d)\n",
1989 	    softp, instance, iosram_master,
1990 	    ((iosram_master) ? iosram_master->instance : -1));
1991 
1992 	if (softp == NULL || (softp->state & IOSRAM_STATE_DETACH)) {
1993 		return (ENXIO);
1994 	}
1995 	if (iosram_master == softp) {
1996 		return (0);
1997 	}
1998 
1999 
2000 	/*
2001 	 * We protect against the softp structure being deallocated by setting
2002 	 * the IOSRAM_STATE_TSWITCH state flag. The detach routine will check
2003 	 * for this flag and if set, it will wait for this flag to be reset or
2004 	 * refuse the detach operation.
2005 	 */
2006 	iosram_new_master = softp;
2007 	softp->state |= IOSRAM_STATE_TSWITCH;
2008 	prev_master = iosram_master;
2009 	if (prev_master) {
2010 		prev_master->state |= IOSRAM_STATE_TSWITCH;
2011 	}
2012 	mutex_exit(&iosram_mutex);
2013 
2014 	/*
2015 	 * Map the target IOSRAM, read the TOC, and register interrupts if not
2016 	 * already done.
2017 	 */
2018 	DPRINTF(1, ("iosram(%d): mapping IOSRAM and SBBC\n",
2019 	    softp->instance));
2020 	IOSRAMLOG(1, "TSWTCH: mapping instance:%d  softp:%p\n",
2021 	    instance, softp, NULL, NULL);
2022 
2023 	if (iosram_setup_map(softp) != DDI_SUCCESS) {
2024 		error = ENXIO;
2025 	} else if ((chunks == NULL) && (iosram_read_toc(softp) != 0)) {
2026 		iosram_remove_map(softp);
2027 		error = EINVAL;
2028 	} else if (iosram_add_intr(softp) != DDI_SUCCESS) {
2029 		/*
2030 		 * If there was no previous master, purge the TOC data that
2031 		 * iosram_read_toc() created.
2032 		 */
2033 		if ((prev_master == NULL) && (chunks != NULL)) {
2034 			kmem_free(chunks, nchunks * sizeof (iosram_chunk_t));
2035 			chunks = NULL;
2036 			nchunks = 0;
2037 			iosram_init_hashtab();
2038 		}
2039 		iosram_remove_map(softp);
2040 		error = ENXIO;
2041 	}
2042 
2043 	/*
2044 	 * If we are asked to abort tunnel switch, do so now, before invoking
2045 	 * the OBP callback.
2046 	 */
2047 	if (iosram_tswitch_aborted) {
2048 
2049 		/*
2050 		 * Once the tunnel switch is aborted, this thread should not
2051 		 * resume.  If it does, we simply log a message.  We can't unmap
2052 		 * the new master IOSRAM as it may be accessed in
2053 		 * iosram_abort_tswitch(). It will be unmapped when it is
2054 		 * detached.
2055 		 */
2056 		IOSRAMLOG(1,
2057 		    "TSWTCH: aborted (pre OBP cback). Thread resumed.\n",
2058 		    NULL, NULL, NULL, NULL);
2059 		error = EIO;
2060 	}
2061 
2062 	if (error) {
2063 		IOSRAMLOG(1,
2064 		    "TSWTCH: map failed instance:%d  softp:%p error:%x\n",
2065 		    instance, softp, error, NULL);
2066 		goto done;
2067 	}
2068 
2069 	if (prev_master != NULL) {
2070 		int	result;
2071 
2072 		/*
2073 		 * Now invoke the OBP interface to do the tunnel switch.
2074 		 */
2075 		result = prom_starcat_switch_tunnel(softp->portid,
2076 		    OBP_TSWITCH_REQREPLY);
2077 		if (result != 0) {
2078 			error = EIO;
2079 		}
2080 		IOSRAMLOG(1,
2081 		    "TSWTCH: OBP tswitch portid:%x result:%x error:%x\n",
2082 		    softp->portid, result, error, NULL);
2083 		IOSRAM_STAT(tswitch);
2084 		iosram_tswitch_tstamp = ddi_get_lbolt();
2085 	}
2086 
2087 	mutex_enter(&iosram_mutex);
2088 	if (iosram_tswitch_aborted) {
2089 		/*
2090 		 * Tunnel switch aborted.  This thread should not resume.
2091 		 * For now, we simply log a message, but don't unmap any
2092 		 * IOSRAM at this stage as it may be accessed within the
2093 		 * isoram_abort_tswitch(). The IOSRAM will be unmapped
2094 		 * when that instance is detached.
2095 		 */
2096 		if (iosram_tswitch_aborted) {
2097 			IOSRAMLOG(1,
2098 			    "TSWTCH: aborted (post OBP cback). Thread"
2099 			    " resumed.\n", NULL, NULL, NULL, NULL);
2100 			error = EIO;
2101 			mutex_exit(&iosram_mutex);
2102 		}
2103 	} else if (error) {
2104 		/*
2105 		 * Tunnel switch failed.  Continue using previous tunnel.
2106 		 * However, unmap new (target) IOSRAM.
2107 		 */
2108 		iosram_new_master = NULL;
2109 		mutex_exit(&iosram_mutex);
2110 		(void) iosram_remove_intr(softp);
2111 		iosram_remove_map(softp);
2112 	} else {
2113 		/*
2114 		 * Tunnel switch was successful.  Set the new master.
2115 		 * Also unmap old master IOSRAM and remove any interrupts
2116 		 * associated with that.
2117 		 *
2118 		 * Note that a call to iosram_force_write() allows access
2119 		 * to the IOSRAM while tunnel switch is in progress.  That
2120 		 * means we need to set the new master before unmapping
2121 		 * the old master.
2122 		 */
2123 		iosram_set_master(softp);
2124 		iosram_new_master = NULL;
2125 		mutex_exit(&iosram_mutex);
2126 
2127 		if (prev_master) {
2128 			IOSRAMLOG(1, "TSWTCH: unmapping prev_master:%p (%d)\n",
2129 			    prev_master, prev_master->instance, NULL, NULL);
2130 			(void) iosram_remove_intr(prev_master);
2131 			iosram_remove_map(prev_master);
2132 		}
2133 	}
2134 
2135 done:
2136 	mutex_enter(&iosram_mutex);
2137 
2138 	/*
2139 	 * Clear the tunnel switch flag on the source and destination
2140 	 * instances.
2141 	 */
2142 	if (prev_master) {
2143 		prev_master->state &= ~IOSRAM_STATE_TSWITCH;
2144 	}
2145 	softp->state &= ~IOSRAM_STATE_TSWITCH;
2146 
2147 	/*
2148 	 * Since incoming interrupts could get lost during a tunnel switch,
2149 	 * trigger a soft interrupt just in case.  No harm other than a bit
2150 	 * of wasted effort will be caused if no interrupts were dropped.
2151 	 */
2152 	mutex_enter(&softp->intr_mutex);
2153 	iosram_master->intr_pending = 1;
2154 	if ((iosram_master->softintr_id != NULL) &&
2155 	    (iosram_master->intr_busy == 0)) {
2156 		ddi_trigger_softintr(iosram_master->softintr_id);
2157 	}
2158 	mutex_exit(&softp->intr_mutex);
2159 
2160 	IOSRAMLOG(1, "TSWTCH: done error:%d iosram_master:%p instance:%d\n",
2161 	    error, iosram_master,
2162 	    (iosram_master) ? iosram_master->instance : -1, NULL);
2163 
2164 	return (error);
2165 }
2166 
2167 
2168 /*
2169  * iosram_abort_tswitch()
2170  * Must be called while holding iosram_mutex.
2171  */
2172 static void
2173 iosram_abort_tswitch()
2174 {
2175 	uint32_t  master_valid, new_master_valid;
2176 
2177 	ASSERT(mutex_owned(&iosram_mutex));
2178 
2179 	if ((!iosram_tswitch_active) || iosram_tswitch_aborted) {
2180 		return;
2181 	}
2182 
2183 	ASSERT(iosram_master != NULL);
2184 
2185 	IOSRAMLOG(1, "ABORT: iosram_master:%p (%d) iosram_new_master:%p (%d)\n",
2186 	    iosram_master, iosram_master->instance, iosram_new_master,
2187 	    (iosram_new_master == NULL) ? -1 : iosram_new_master->instance);
2188 
2189 	/*
2190 	 * The first call to iosram_force_write() in the middle of tunnel switch
2191 	 * will get here. We lookup IOSRAM VALID location and setup appropriate
2192 	 * master, if one is still valid.  We also set iosram_tswitch_aborted to
2193 	 * prevent reentering this code and to catch if the OBP callback thread
2194 	 * somehow resumes.
2195 	 */
2196 	iosram_tswitch_aborted = 1;
2197 
2198 	if ((iosram_new_master == NULL) ||
2199 	    (iosram_new_master = iosram_master)) {
2200 		/*
2201 		 * New master hasn't been selected yet, or OBP callback
2202 		 * succeeded and we already selected new IOSRAM as master, but
2203 		 * system crashed in the middle of unmapping previous master or
2204 		 * cleaning up state.  Use the existing master.
2205 		 */
2206 		ASSERT(iosram_master->iosramp != NULL);
2207 		ASSERT(IOSRAM_GET_HDRFIELD32(iosram_master, status) ==
2208 		    IOSRAM_VALID);
2209 		IOSRAMLOG(1, "ABORT: master (%d) already determined.\n",
2210 		    iosram_master->instance, NULL, NULL, NULL);
2211 
2212 		return;
2213 	}
2214 
2215 	/*
2216 	 * System crashed in the middle of tunnel switch and we know that the
2217 	 * new target has not been marked master yet.  That means, the old
2218 	 * master should still be mapped.  We need to abort the tunnel switch
2219 	 * and setup a valid master, if possible, so that we can write to the
2220 	 * IOSRAM.
2221 	 *
2222 	 * We select a new master based upon the IOSRAM header status fields in
2223 	 * the previous master IOSRAM and the target IOSRAM as follows:
2224 	 *
2225 	 *	iosram_master	iosram-tswitch
2226 	 * 	(Prev Master)	(New Target)	Decision
2227 	 *	---------------	---------------	-----------
2228 	 *	  VALID		  don't care	prev master
2229 	 *	  INTRANSIT	  INVALID	prev master
2230 	 *	  INTRANSIT	  INTRANSIT	prev master
2231 	 *	  INTRANSIT	  VALID		new target
2232 	 *	  INVALID	  INVALID	shouldn't ever happen
2233 	 *	  INVALID	  INTRANSIT	shouldn't ever happen
2234 	 *	  INVALID	  VALID		new target
2235 	 */
2236 
2237 	master_valid = (iosram_master->iosramp != NULL) ?
2238 	    IOSRAM_GET_HDRFIELD32(iosram_master, status) : IOSRAM_INVALID;
2239 	new_master_valid = (iosram_new_master->iosramp != NULL) ?
2240 	    IOSRAM_GET_HDRFIELD32(iosram_new_master, status) : IOSRAM_INVALID;
2241 
2242 	if (master_valid == IOSRAM_VALID) {
2243 		/* EMPTY */
2244 		/*
2245 		 * OBP hasn't been called yet or, if it has, it hasn't started
2246 		 * copying yet.  Use the existing master.  Note that the new
2247 		 * master may not be mapped yet.
2248 		 */
2249 		IOSRAMLOG(1, "ABORT: prev master(%d) is VALID\n",
2250 		    iosram_master->instance, NULL, NULL, NULL);
2251 	} else if (master_valid == IOSRAM_INTRANSIT) {
2252 		/*
2253 		 * The system crashed after OBP started processing the tunnel
2254 		 * switch but before the iosram driver determined that it was
2255 		 * complete.  Use the new master if it has been marked valid,
2256 		 * meaning that OBP finished copying data to it, or the old
2257 		 * master otherwise.
2258 		 */
2259 		IOSRAMLOG(1, "ABORT: prev master(%d) is INTRANSIT\n",
2260 		    iosram_master->instance, NULL, NULL, NULL);
2261 
2262 		if (new_master_valid == IOSRAM_VALID) {
2263 			iosram_set_master(iosram_new_master);
2264 			IOSRAMLOG(1, "ABORT: new master(%d) is VALID\n",
2265 			    iosram_new_master->instance, NULL, NULL,
2266 			    NULL);
2267 		} else {
2268 			(void) prom_starcat_switch_tunnel(iosram_master->portid,
2269 			    OBP_TSWITCH_NOREPLY);
2270 
2271 			IOSRAMLOG(1, "ABORT: new master(%d) is INVALID\n",
2272 			    iosram_new_master->instance, NULL, NULL,
2273 			    NULL);
2274 		}
2275 	} else {
2276 		/*
2277 		 * The system crashed after OBP marked the old master INVALID,
2278 		 * which means the new master is the way to go.
2279 		 */
2280 		IOSRAMLOG(1, "ABORT: prev master(%d) is INVALID\n",
2281 		    iosram_master->instance, NULL, NULL, NULL);
2282 
2283 		ASSERT(new_master_valid == IOSRAM_VALID);
2284 
2285 		iosram_set_master(iosram_new_master);
2286 	}
2287 
2288 	IOSRAMLOG(1, "ABORT: Instance %d selected as master\n",
2289 	    iosram_master->instance, NULL, NULL, NULL);
2290 }
2291 
2292 
2293 /*
2294  * iosram_switchfrom(instance)
2295  *	Switch master tunnel away from the specified instance
2296  */
2297 /*ARGSUSED*/
2298 int
2299 iosram_switchfrom(int instance)
2300 {
2301 	struct iosramsoft	*softp;
2302 	int			error = 0;
2303 	int			count;
2304 	clock_t			current_tstamp;
2305 	clock_t			tstamp_interval;
2306 	struct iosramsoft	*last_master = NULL;
2307 	static int		last_master_instance = -1;
2308 
2309 	IOSRAMLOG(1, "SwtchFrom: instance:%d  iosram_master:%p (%d)\n",
2310 	    instance, iosram_master,
2311 	    ((iosram_master) ? iosram_master->instance : -1), NULL);
2312 
2313 	mutex_enter(&iosram_mutex);
2314 
2315 	/*
2316 	 * Wait if another tunnel switch is in progress
2317 	 */
2318 	for (count = 0; iosram_tswitch_active && count < IOSRAM_TSWITCH_RETRY;
2319 	    count++) {
2320 		iosram_tswitch_wakeup = 1;
2321 		cv_wait(&iosram_tswitch_wait, &iosram_mutex);
2322 	}
2323 
2324 	if (iosram_tswitch_active) {
2325 		mutex_exit(&iosram_mutex);
2326 		return (EAGAIN);
2327 	}
2328 
2329 	/*
2330 	 * Check if the specified instance holds the tunnel. If not,
2331 	 * then we are done.
2332 	 */
2333 	if ((iosram_master == NULL) || (iosram_master->instance != instance)) {
2334 		mutex_exit(&iosram_mutex);
2335 		return (0);
2336 	}
2337 
2338 	/*
2339 	 * Before beginning the tunnel switch process, wait for any outstanding
2340 	 * read/write activity to complete.
2341 	 */
2342 	iosram_tswitch_active = 1;
2343 	while (iosram_rw_active) {
2344 		iosram_rw_wakeup = 1;
2345 		cv_wait(&iosram_rw_wait, &iosram_mutex);
2346 	}
2347 
2348 	/*
2349 	 * If a previous tunnel switch just completed, we have to make sure
2350 	 * HWAD has enough time to find the new tunnel before we switch
2351 	 * away from it.  Otherwise, OBP's mailbox message to OSD will never
2352 	 * get through.  Just to be paranoid about synchronization of lbolt
2353 	 * across different CPUs, make sure the current attempt isn't noted
2354 	 * as starting _before_ the last tunnel switch completed.
2355 	 */
2356 	current_tstamp = ddi_get_lbolt();
2357 	if (current_tstamp > iosram_tswitch_tstamp) {
2358 		tstamp_interval = current_tstamp - iosram_tswitch_tstamp;
2359 	} else {
2360 		tstamp_interval = 0;
2361 	}
2362 	if (drv_hztousec(tstamp_interval) < IOSRAM_TSWITCH_DELAY_US) {
2363 		mutex_exit(&iosram_mutex);
2364 		delay(drv_usectohz(IOSRAM_TSWITCH_DELAY_US) - tstamp_interval);
2365 		mutex_enter(&iosram_mutex);
2366 	}
2367 
2368 	/*
2369 	 * The specified instance holds the tunnel.  We need to move it to some
2370 	 * other IOSRAM.  Try out all possible IOSRAMs listed in
2371 	 * iosram_instances.  For now, we always search from the first entry.
2372 	 * In future, it may be desirable to start where we left off.
2373 	 */
2374 	for (softp = iosram_instances; softp != NULL; softp = softp->next) {
2375 		if (iosram_tswitch_aborted) {
2376 			break;
2377 		}
2378 
2379 		/* we can't switch _to_ the instance we're switching _from_ */
2380 		if (softp->instance == instance) {
2381 			continue;
2382 		}
2383 
2384 		/* skip over instances being detached */
2385 		if (softp->state & IOSRAM_STATE_DETACH) {
2386 			continue;
2387 		}
2388 
2389 		/*
2390 		 * Try to avoid reverting to the last instance we switched away
2391 		 * from, as we expect that one to be detached eventually.  Keep
2392 		 * track of it, though, so we can go ahead and try switching to
2393 		 * it if no other viable candidates are found.
2394 		 */
2395 		if (softp->instance == last_master_instance) {
2396 			last_master = softp;
2397 			continue;
2398 		}
2399 
2400 		/*
2401 		 * Do the tunnel switch.  If successful, record the instance of
2402 		 * the master we just left behind so we can try to avoid
2403 		 * reverting to it next time.
2404 		 */
2405 		if (iosram_switch_tunnel(softp) == 0) {
2406 			last_master_instance = instance;
2407 			break;
2408 		}
2409 	}
2410 
2411 	/*
2412 	 * If we failed to switch the tunnel, but we skipped over an instance
2413 	 * that had previously been switched out of because we expected it to be
2414 	 * detached, go ahead and try it anyway (unless the tswitch was aborted
2415 	 * or the instance we skipped is finally being detached).
2416 	 */
2417 	if ((softp == NULL) && (last_master != NULL) &&
2418 	    !iosram_tswitch_aborted &&
2419 	    !(last_master->state & IOSRAM_STATE_DETACH)) {
2420 		if (iosram_switch_tunnel(last_master) == 0) {
2421 			softp = last_master;
2422 			last_master_instance = instance;
2423 		}
2424 	}
2425 
2426 	if ((softp == NULL) || (iosram_tswitch_aborted)) {
2427 		error = EIO;
2428 	}
2429 
2430 	/*
2431 	 * If there are additional tunnel switches queued up waiting for this
2432 	 * one to complete, wake them up.
2433 	 */
2434 	if (iosram_tswitch_wakeup) {
2435 		iosram_tswitch_wakeup = 0;
2436 		cv_broadcast(&iosram_tswitch_wait);
2437 	}
2438 	iosram_tswitch_active = 0;
2439 	mutex_exit(&iosram_mutex);
2440 	return (error);
2441 }
2442 
2443 
2444 /*
2445  * iosram_tunnel_capable(softp)
2446  *	Check if this IOSRAM instance is tunnel-capable by looing at
2447  *	"tunnel-capable" property.
2448  */
2449 static int
2450 iosram_tunnel_capable(struct iosramsoft *softp)
2451 {
2452 	int	proplen;
2453 	int	tunnel_capable;
2454 
2455 	/*
2456 	 * Look up IOSRAM_TUNNELOK_PROP property, if any.
2457 	 */
2458 	proplen = sizeof (tunnel_capable);
2459 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, softp->dip,
2460 	    DDI_PROP_DONTPASS, IOSRAM_TUNNELOK_PROP, (caddr_t)&tunnel_capable,
2461 	    &proplen) != DDI_PROP_SUCCESS) {
2462 		tunnel_capable = 0;
2463 	}
2464 	return (tunnel_capable);
2465 }
2466 
2467 
2468 static int
2469 iosram_sbbc_setup_map(struct iosramsoft *softp)
2470 {
2471 	int				rv;
2472 	struct ddi_device_acc_attr	attr;
2473 	dev_info_t			*dip = softp->dip;
2474 	uint32_t			sema_val;
2475 
2476 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2477 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2478 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
2479 
2480 	mutex_enter(&iosram_mutex);
2481 	mutex_enter(&softp->intr_mutex);
2482 
2483 	/*
2484 	 * Map SBBC region in
2485 	 */
2486 	if ((rv = ddi_regs_map_setup(dip, IOSRAM_SBBC_MAP_INDEX,
2487 	    (caddr_t *)&softp->sbbc_region,
2488 	    IOSRAM_SBBC_MAP_OFFSET, sizeof (iosram_sbbc_region_t),
2489 	    &attr, &softp->sbbc_handle)) != DDI_SUCCESS) {
2490 		DPRINTF(1, ("Failed to map SBBC region.\n"));
2491 		mutex_exit(&softp->intr_mutex);
2492 		mutex_exit(&iosram_mutex);
2493 		return (rv);
2494 	}
2495 
2496 	/*
2497 	 * Disable SBBC interrupts. SBBC interrupts are enabled
2498 	 * once the interrupt handler is registered.
2499 	 */
2500 	ddi_put32(softp->sbbc_handle,
2501 	    &(softp->sbbc_region->int_enable.reg), 0x0);
2502 
2503 	/*
2504 	 * Clear hardware semaphore value if appropriate.
2505 	 * When the first SBBC is mapped in by the IOSRAM driver,
2506 	 * the value of the semaphore should be initialized only
2507 	 * if it is not held by SMS. For subsequent SBBC's, the
2508 	 * semaphore will be always initialized.
2509 	 */
2510 	sema_val = IOSRAM_SEMA_RD(softp);
2511 
2512 	if (!iosram_master) {
2513 		/* the first SBBC is being mapped in */
2514 		if (!(IOSRAM_SEMA_IS_HELD(sema_val) &&
2515 		    IOSRAM_SEMA_GET_IDX(sema_val) == IOSRAM_SEMA_SMS_IDX)) {
2516 			/* not held by SMS, we clear the semaphore */
2517 			IOSRAM_SEMA_WR(softp, 0);
2518 		}
2519 	} else {
2520 		/* not the first SBBC, we clear the semaphore */
2521 		IOSRAM_SEMA_WR(softp, 0);
2522 	}
2523 
2524 	mutex_exit(&softp->intr_mutex);
2525 	mutex_exit(&iosram_mutex);
2526 	return (0);
2527 }
2528 
2529 
2530 static int
2531 iosram_setup_map(struct iosramsoft *softp)
2532 {
2533 	int				instance = softp->instance;
2534 	dev_info_t			*dip = softp->dip;
2535 	int				portid;
2536 	int				proplen;
2537 	caddr_t				propvalue;
2538 	struct ddi_device_acc_attr	attr;
2539 
2540 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2541 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2542 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
2543 
2544 	/*
2545 	 * Lookup IOSRAM_REG_PROP property to find out our IOSRAM length
2546 	 */
2547 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
2548 	    DDI_PROP_DONTPASS, IOSRAM_REG_PROP, (caddr_t)&propvalue,
2549 	    &proplen) != DDI_PROP_SUCCESS) {
2550 		cmn_err(CE_WARN, "iosram(%d): can't find register property.\n",
2551 		    instance);
2552 		return (DDI_FAILURE);
2553 	} else {
2554 		iosram_reg_t	*regprop = (iosram_reg_t *)propvalue;
2555 
2556 		DPRINTF(1, ("SetupMap(%d): Got reg prop: %x %x %x\n",
2557 		    instance, regprop->addr_hi,
2558 		    regprop->addr_lo, regprop->size));
2559 
2560 		softp->iosramlen = regprop->size;
2561 
2562 		kmem_free(propvalue, proplen);
2563 	}
2564 	DPRINTF(1, ("SetupMap(%d): IOSRAM length: 0x%x\n", instance,
2565 	    softp->iosramlen));
2566 	softp->handle = NULL;
2567 
2568 	/*
2569 	 * To minimize boot time, we map the entire IOSRAM as opposed to
2570 	 * mapping individual chunk via ddi_regs_map_setup() call.
2571 	 */
2572 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&softp->iosramp,
2573 	    0x0, softp->iosramlen, &attr, &softp->handle) != DDI_SUCCESS) {
2574 		cmn_err(CE_WARN, "iosram(%d): failed to map IOSRAM len:%x\n",
2575 		    instance, softp->iosramlen);
2576 		iosram_remove_map(softp);
2577 		return (DDI_FAILURE);
2578 	}
2579 
2580 	/*
2581 	 * Lookup PORTID property on my parent hierarchy
2582 	 */
2583 	proplen = sizeof (portid);
2584 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
2585 	    0, IOSRAM_PORTID_PROP, (caddr_t)&portid,
2586 	    &proplen) != DDI_PROP_SUCCESS) {
2587 		cmn_err(CE_WARN, "iosram(%d): can't find portid property.\n",
2588 		    instance);
2589 		iosram_remove_map(softp);
2590 		return (DDI_FAILURE);
2591 	}
2592 	softp->portid = portid;
2593 
2594 	if (iosram_sbbc_setup_map(softp) != DDI_SUCCESS) {
2595 		cmn_err(CE_WARN, "iosram(%d): can't map SBBC region.\n",
2596 		    instance);
2597 		iosram_remove_map(softp);
2598 		return (DDI_FAILURE);
2599 	}
2600 
2601 	mutex_enter(&iosram_mutex);
2602 	softp->state |= IOSRAM_STATE_MAPPED;
2603 	mutex_exit(&iosram_mutex);
2604 
2605 	return (DDI_SUCCESS);
2606 }
2607 
2608 
2609 static void
2610 iosram_remove_map(struct iosramsoft *softp)
2611 {
2612 	mutex_enter(&iosram_mutex);
2613 
2614 	ASSERT((softp->state & IOSRAM_STATE_MASTER) == 0);
2615 
2616 	if (softp->handle) {
2617 		ddi_regs_map_free(&softp->handle);
2618 		softp->handle = NULL;
2619 	}
2620 	softp->iosramp = NULL;
2621 
2622 	/*
2623 	 * Umap SBBC registers region. Shared with handler for SBBC
2624 	 * interrupts, take intr_mutex.
2625 	 */
2626 	mutex_enter(&softp->intr_mutex);
2627 	if (softp->sbbc_region) {
2628 		ddi_regs_map_free(&softp->sbbc_handle);
2629 		softp->sbbc_region = NULL;
2630 	}
2631 	mutex_exit(&softp->intr_mutex);
2632 
2633 	softp->state &= ~IOSRAM_STATE_MAPPED;
2634 
2635 	mutex_exit(&iosram_mutex);
2636 }
2637 
2638 
2639 /*
2640  * iosram_is_chosen(struct iosramsoft *softp)
2641  *
2642  *	Looks up "chosen" node property to
2643  *	determine if it is the chosen IOSRAM.
2644  */
2645 static int
2646 iosram_is_chosen(struct iosramsoft *softp)
2647 {
2648 	char		chosen_iosram[MAXNAMELEN];
2649 	char		pn[MAXNAMELEN];
2650 	int		nodeid;
2651 	int		chosen;
2652 	pnode_t		dnode;
2653 
2654 	/*
2655 	 * Get /chosen node info. prom interface will handle errors.
2656 	 */
2657 	dnode = prom_chosennode();
2658 
2659 	/*
2660 	 * Look for the "iosram" property on the chosen node with a prom
2661 	 * interface as ddi_find_devinfo() couldn't be used (calls
2662 	 * ddi_walk_devs() that creates one extra lock on the device tree).
2663 	 */
2664 	if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) {
2665 		/*
2666 		 * Can't find IOSRAM_CHOSEN_PROP property under chosen node
2667 		 */
2668 		cmn_err(CE_WARN,
2669 		    "iosram(%d): can't find chosen iosram property\n",
2670 		    softp->instance);
2671 		return (0);
2672 	}
2673 
2674 	DPRINTF(1, ("iosram(%d): Got '%x' for chosen '%s' property\n",
2675 	    softp->instance, nodeid, IOSRAM_CHOSEN_PROP));
2676 
2677 	/*
2678 	 * get the full OBP pathname of this node
2679 	 */
2680 	if (prom_phandle_to_path((phandle_t)nodeid, chosen_iosram,
2681 	    sizeof (chosen_iosram)) < 0) {
2682 		cmn_err(CE_NOTE, "prom_phandle_to_path(%x) failed\n", nodeid);
2683 		return (0);
2684 	}
2685 	DPRINTF(1, ("iosram(%d): prom_phandle_to_path(%x) is '%s'\n",
2686 	    softp->instance, nodeid, chosen_iosram));
2687 
2688 	(void) ddi_pathname(softp->dip, pn);
2689 	DPRINTF(1, ("iosram(%d): ddi_pathname(%p) is '%s'\n",
2690 	    softp->instance, (void *)softp->dip, pn));
2691 
2692 	chosen = (strcmp(chosen_iosram, pn) == 0) ? 1 : 0;
2693 	DPRINTF(1, ("iosram(%d): ... %s\n", softp->instance,
2694 	    chosen ? "MASTER" : "SLAVE"));
2695 	IOSRAMLOG(1, "iosram(%d): ... %s\n", softp->instance,
2696 	    (chosen ? "MASTER" : "SLAVE"), NULL, NULL);
2697 
2698 	return (chosen);
2699 }
2700 
2701 
2702 /*
2703  * iosram_set_master(struct iosramsoft *softp)
2704  *
2705  *	Set master tunnel to the specified IOSRAM
2706  *	Must be called while holding iosram_mutex.
2707  */
2708 static void
2709 iosram_set_master(struct iosramsoft *softp)
2710 {
2711 	ASSERT(mutex_owned(&iosram_mutex));
2712 	ASSERT(softp != NULL);
2713 	ASSERT(softp->state & IOSRAM_STATE_MAPPED);
2714 	ASSERT(IOSRAM_GET_HDRFIELD32(softp, status) == IOSRAM_VALID);
2715 
2716 	/*
2717 	 * Clear MASTER flag on any previous IOSRAM master, if any
2718 	 */
2719 	if (iosram_master && (iosram_master != softp)) {
2720 		iosram_master->state &= ~IOSRAM_STATE_MASTER;
2721 	}
2722 
2723 	/*
2724 	 * Setup new IOSRAM master
2725 	 */
2726 	iosram_update_addrs(softp);
2727 	iosram_handle = softp->handle;
2728 	softp->state |= IOSRAM_STATE_MASTER;
2729 	softp->tswitch_ok++;
2730 	iosram_master = softp;
2731 
2732 	IOSRAMLOG(1, "SETMASTER: softp:%p instance:%d\n", softp,
2733 	    softp->instance, NULL, NULL);
2734 }
2735 
2736 
2737 /*
2738  * iosram_read_toc()
2739  *
2740  *	Read the TOC from an IOSRAM instance that has been mapped in.
2741  *	If the TOC is flawed or the IOSRAM isn't valid, return an error.
2742  */
2743 static int
2744 iosram_read_toc(struct iosramsoft *softp)
2745 {
2746 	int			i;
2747 	int			instance = softp->instance;
2748 	uint8_t			*toc_entryp;
2749 	iosram_flags_t		*flagsp = NULL;
2750 	int			new_nchunks;
2751 	iosram_chunk_t		*new_chunks;
2752 	iosram_chunk_t		*chunkp;
2753 	iosram_chunk_t		*old_chunkp;
2754 	iosram_toc_entry_t	index;
2755 
2756 	/*
2757 	 * Never try to read the TOC out of an unmapped IOSRAM.
2758 	 */
2759 	ASSERT(softp->state & IOSRAM_STATE_MAPPED);
2760 
2761 	mutex_enter(&iosram_mutex);
2762 
2763 	/*
2764 	 * Check to make sure this IOSRAM is marked valid.  Return
2765 	 * an error if it isn't.
2766 	 */
2767 	if (IOSRAM_GET_HDRFIELD32(softp, status) != IOSRAM_VALID) {
2768 		DPRINTF(1, ("iosram_read_toc(%d): IOSRAM not flagged valid\n",
2769 		    instance));
2770 		mutex_exit(&iosram_mutex);
2771 		return (EINVAL);
2772 	}
2773 
2774 	/*
2775 	 * Get the location of the TOC.
2776 	 */
2777 	toc_entryp = softp->iosramp + IOSRAM_GET_HDRFIELD32(softp, toc_offset);
2778 
2779 	/*
2780 	 * Read the index entry from the TOC and make sure it looks correct.
2781 	 */
2782 	ddi_rep_get8(softp->handle, (uint8_t *)&index, toc_entryp,
2783 	    sizeof (iosram_toc_entry_t), DDI_DEV_AUTOINCR);
2784 	if ((index.key != IOSRAM_INDEX_KEY) ||
2785 	    (index.off != IOSRAM_INDEX_OFF)) {
2786 		cmn_err(CE_WARN, "iosram(%d): invalid TOC index.\n", instance);
2787 		mutex_exit(&iosram_mutex);
2788 		return (EINVAL);
2789 	}
2790 
2791 	/*
2792 	 * Allocate storage for the new chunks array and initialize it with data
2793 	 * from the TOC and callback data from the corresponding old chunk, if
2794 	 * it exists.
2795 	 */
2796 	new_nchunks = index.len - 1;
2797 	new_chunks = (iosram_chunk_t *)kmem_zalloc(new_nchunks *
2798 	    sizeof (iosram_chunk_t), KM_SLEEP);
2799 	for (i = 0, chunkp = new_chunks; i < new_nchunks; i++, chunkp++) {
2800 		toc_entryp += sizeof (iosram_toc_entry_t);
2801 		ddi_rep_get8(softp->handle, (uint8_t *)&(chunkp->toc_data),
2802 		    toc_entryp, sizeof (iosram_toc_entry_t), DDI_DEV_AUTOINCR);
2803 		chunkp->hash = NULL;
2804 		if ((chunkp->toc_data.off < softp->iosramlen) &&
2805 		    (chunkp->toc_data.len <= softp->iosramlen) &&
2806 		    ((chunkp->toc_data.off + chunkp->toc_data.len) <=
2807 		    softp->iosramlen)) {
2808 			chunkp->basep = softp->iosramp + chunkp->toc_data.off;
2809 			DPRINTF(1,
2810 			    ("iosram_read_toc(%d): k:%x o:%x l:%x p:%p\n",
2811 			    instance, chunkp->toc_data.key,
2812 			    chunkp->toc_data.off, chunkp->toc_data.len,
2813 			    (void *)chunkp->basep));
2814 		} else {
2815 			cmn_err(CE_WARN, "iosram(%d): TOC entry %d"
2816 			    "out of range... off:%x  len:%x\n",
2817 			    instance, i + 1, chunkp->toc_data.off,
2818 			    chunkp->toc_data.len);
2819 			kmem_free(new_chunks, new_nchunks *
2820 			    sizeof (iosram_chunk_t));
2821 			mutex_exit(&iosram_mutex);
2822 			return (EINVAL);
2823 		}
2824 
2825 		/*
2826 		 * Note the existence of the flags chunk, which is required in
2827 		 * a correct TOC.
2828 		 */
2829 		if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) {
2830 			flagsp = (iosram_flags_t *)chunkp->basep;
2831 		}
2832 
2833 		/*
2834 		 * If there was an entry for this chunk in the old list, copy
2835 		 * the callback data from old to new storage.
2836 		 */
2837 		if ((nchunks > 0) &&
2838 		    ((old_chunkp = iosram_find_chunk(chunkp->toc_data.key)) !=
2839 		    NULL)) {
2840 			bcopy(&(old_chunkp->cback), &(chunkp->cback),
2841 			    sizeof (iosram_cback_t));
2842 		}
2843 	}
2844 	/*
2845 	 * The TOC is malformed if there is no entry for the flags chunk.
2846 	 */
2847 	if (flagsp == NULL) {
2848 		kmem_free(new_chunks, new_nchunks * sizeof (iosram_chunk_t));
2849 		mutex_exit(&iosram_mutex);
2850 		return (EINVAL);
2851 	}
2852 
2853 	/*
2854 	 * Free any memory that is no longer needed and install the new data
2855 	 * as current data.
2856 	 */
2857 	if (chunks != NULL) {
2858 		kmem_free(chunks, nchunks * sizeof (iosram_chunk_t));
2859 	}
2860 	chunks = new_chunks;
2861 	nchunks = new_nchunks;
2862 	iosram_init_hashtab();
2863 
2864 	mutex_exit(&iosram_mutex);
2865 	return (0);
2866 }
2867 
2868 
2869 /*
2870  * iosram_init_hashtab()
2871  *
2872  *	Initialize the hash table and populate it with the IOSRAM
2873  *	chunks previously read from the TOC.  The caller must hold the
2874  *	ioram_mutex lock.
2875  */
2876 static void
2877 iosram_init_hashtab(void)
2878 {
2879 	int		i, bucket;
2880 	iosram_chunk_t	*chunkp;
2881 
2882 	ASSERT(mutex_owned(&iosram_mutex));
2883 
2884 	for (i = 0; i < IOSRAM_HASHSZ; i++) {
2885 		iosram_hashtab[i] = NULL;
2886 	}
2887 
2888 	if (chunks) {
2889 		for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
2890 			/*
2891 			 * Hide the flags chunk by leaving it out of the hash
2892 			 * table.
2893 			 */
2894 			if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) {
2895 				continue;
2896 			}
2897 
2898 			/*
2899 			 * Add the current chunk to the hash table.
2900 			 */
2901 			bucket = IOSRAM_HASH(chunkp->toc_data.key);
2902 			chunkp->hash = iosram_hashtab[bucket];
2903 			iosram_hashtab[bucket] = chunkp;
2904 		}
2905 	}
2906 }
2907 
2908 
2909 /*
2910  * iosram_update_addrs()
2911  *
2912  *	Process the chunk list, updating each chunk's basep, which is a pointer
2913  *	to the beginning of the chunk's memory in kvaddr space.  Record the
2914  *	basep value of the flags chunk to speed up flag access.  The caller
2915  *	must hold the iosram_mutex lock.
2916  */
2917 static void
2918 iosram_update_addrs(struct iosramsoft *softp)
2919 {
2920 	int		i;
2921 	iosram_flags_t	*flagsp;
2922 	iosram_chunk_t	*chunkp;
2923 
2924 	ASSERT(mutex_owned(&iosram_mutex));
2925 
2926 	/*
2927 	 * First go through all of the chunks updating their base pointers and
2928 	 * looking for the flags chunk.
2929 	 */
2930 	for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
2931 		chunkp->basep = softp->iosramp + chunkp->toc_data.off;
2932 		if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) {
2933 			flagsp = (iosram_flags_t *)(chunkp->basep);
2934 			DPRINTF(1,
2935 			    ("iosram_update_addrs flags: o:0x%08x p:%p",
2936 			    chunkp->toc_data.off, (void *)flagsp));
2937 		}
2938 	}
2939 
2940 	/*
2941 	 * Now, go through and update each chunk's flags pointer.  This can't be
2942 	 * done in the first loop because we don't have the address of the flags
2943 	 * chunk yet.
2944 	 */
2945 	for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
2946 		chunkp->flagsp = flagsp++;
2947 		DPRINTF(1, ("iosram_update_addrs: k:0x%x f:%p\n",
2948 		    chunkp->toc_data.key, (void *)chunkp->flagsp));
2949 	}
2950 }
2951 
2952 /*
2953  * iosram_find_chunk(key)
2954  *
2955  *	Return a pointer to iosram_chunk structure corresponding to the
2956  *	"key" IOSRAM chunk.  The caller must hold the iosram_mutex lock.
2957  */
2958 static iosram_chunk_t *
2959 iosram_find_chunk(uint32_t key)
2960 {
2961 	iosram_chunk_t	*chunkp;
2962 	int		index = IOSRAM_HASH(key);
2963 
2964 	ASSERT(mutex_owned(&iosram_mutex));
2965 
2966 	for (chunkp = iosram_hashtab[index]; chunkp; chunkp = chunkp->hash) {
2967 		if (chunkp->toc_data.key == key) {
2968 			break;
2969 		}
2970 	}
2971 
2972 	return (chunkp);
2973 }
2974 
2975 
2976 /*
2977  * iosram_add_intr(iosramsoft_t *)
2978  */
2979 static int
2980 iosram_add_intr(iosramsoft_t *softp)
2981 {
2982 	IOSRAMLOG(2, "ADDINTR: softp:%p  instance:%d\n",
2983 	    softp, softp->instance, NULL, NULL);
2984 
2985 	if (ddi_add_softintr(softp->dip, DDI_SOFTINT_MED,
2986 	    &softp->softintr_id, &softp->soft_iblk, NULL,
2987 	    iosram_softintr, (caddr_t)softp) != DDI_SUCCESS) {
2988 		cmn_err(CE_WARN,
2989 		    "iosram(%d): Can't register softintr.\n",
2990 		    softp->instance);
2991 		return (DDI_FAILURE);
2992 	}
2993 
2994 	if (ddi_add_intr(softp->dip, 0, &softp->real_iblk, NULL,
2995 	    iosram_intr, (caddr_t)softp) != DDI_SUCCESS) {
2996 		cmn_err(CE_WARN,
2997 		    "iosram(%d): Can't register intr"
2998 		    " handler.\n", softp->instance);
2999 		ddi_remove_softintr(softp->softintr_id);
3000 		return (DDI_FAILURE);
3001 	}
3002 
3003 	/*
3004 	 * Enable SBBC interrupts
3005 	 */
3006 	ddi_put32(softp->sbbc_handle, &(softp->sbbc_region->int_enable.reg),
3007 	    IOSRAM_SBBC_INT0|IOSRAM_SBBC_INT1);
3008 
3009 	return (DDI_SUCCESS);
3010 }
3011 
3012 
3013 /*
3014  * iosram_remove_intr(iosramsoft_t *)
3015  */
3016 static int
3017 iosram_remove_intr(iosramsoft_t *softp)
3018 {
3019 	IOSRAMLOG(2, "REMINTR: softp:%p  instance:%d\n",
3020 	    softp, softp->instance, NULL, NULL);
3021 
3022 	/*
3023 	 * Disable SBBC interrupts if SBBC is mapped in
3024 	 */
3025 	if (softp->sbbc_region) {
3026 		ddi_put32(softp->sbbc_handle,
3027 		    &(softp->sbbc_region->int_enable.reg), 0);
3028 	}
3029 
3030 	/*
3031 	 * Remove SBBC interrupt handler
3032 	 */
3033 	ddi_remove_intr(softp->dip, 0, softp->real_iblk);
3034 
3035 	/*
3036 	 * Remove soft interrupt handler
3037 	 */
3038 	mutex_enter(&iosram_mutex);
3039 	if (softp->softintr_id != NULL) {
3040 		ddi_remove_softintr(softp->softintr_id);
3041 		softp->softintr_id = NULL;
3042 	}
3043 	mutex_exit(&iosram_mutex);
3044 
3045 	return (0);
3046 }
3047 
3048 
3049 /*
3050  * iosram_add_instance(iosramsoft_t *)
3051  * Must be called while holding iosram_mutex
3052  */
3053 static void
3054 iosram_add_instance(iosramsoft_t *new_softp)
3055 {
3056 #ifdef DEBUG
3057 	int		instance = new_softp->instance;
3058 	iosramsoft_t	*softp;
3059 #endif
3060 
3061 	ASSERT(mutex_owned(&iosram_mutex));
3062 
3063 #if defined(DEBUG)
3064 	/* Verify that this instance is not in the list */
3065 	for (softp = iosram_instances; softp != NULL; softp = softp->next) {
3066 		ASSERT(softp->instance != instance);
3067 	}
3068 #endif
3069 
3070 	/*
3071 	 * Add this instance to the list
3072 	 */
3073 	if (iosram_instances != NULL) {
3074 		iosram_instances->prev = new_softp;
3075 	}
3076 	new_softp->next = iosram_instances;
3077 	new_softp->prev = NULL;
3078 	iosram_instances = new_softp;
3079 }
3080 
3081 
3082 /*
3083  * iosram_remove_instance(int instance)
3084  * Must be called while holding iosram_mutex
3085  */
3086 static void
3087 iosram_remove_instance(int instance)
3088 {
3089 	iosramsoft_t *softp;
3090 
3091 	/*
3092 	 * Remove specified instance from the iosram_instances list so that
3093 	 * it can't be chosen for tunnel in future.
3094 	 */
3095 	ASSERT(mutex_owned(&iosram_mutex));
3096 
3097 	for (softp = iosram_instances; softp != NULL; softp = softp->next) {
3098 		if (softp->instance == instance) {
3099 			if (softp->next != NULL) {
3100 				softp->next->prev = softp->prev;
3101 			}
3102 			if (softp->prev != NULL) {
3103 				softp->prev->next = softp->next;
3104 			}
3105 			if (iosram_instances == softp) {
3106 				iosram_instances = softp->next;
3107 			}
3108 
3109 			return;
3110 		}
3111 	}
3112 }
3113 
3114 
3115 /*
3116  * iosram_sema_acquire: Acquire hardware semaphore.
3117  * Return 0 if the semaphore could be acquired, or one of the following
3118  * possible values:
3119  * EAGAIN: there is a tunnel switch in progress
3120  * EBUSY: the semaphore was already "held"
3121  * ENXIO:  an IO error occured (e.g. SBBC not mapped)
3122  * If old_value is not NULL, the location it points to will be updated
3123  * with the semaphore value read when attempting to acquire it.
3124  */
3125 int
3126 iosram_sema_acquire(uint32_t *old_value)
3127 {
3128 	struct iosramsoft	*softp;
3129 	int			rv;
3130 	uint32_t		sema_val;
3131 
3132 	DPRINTF(2, ("IOSRAM: in iosram_sema_acquire\n"));
3133 
3134 	mutex_enter(&iosram_mutex);
3135 
3136 	/*
3137 	 * Disallow access if there is a tunnel switch in progress.
3138 	 */
3139 	if (iosram_tswitch_active) {
3140 		mutex_exit(&iosram_mutex);
3141 		return (EAGAIN);
3142 	}
3143 
3144 	/*
3145 	 * Use current master IOSRAM for operation, fail if none is
3146 	 * currently active.
3147 	 */
3148 	if ((softp = iosram_master) == NULL) {
3149 		mutex_exit(&iosram_mutex);
3150 		DPRINTF(1, ("IOSRAM: iosram_sema_acquire: no master\n"));
3151 		return (ENXIO);
3152 	}
3153 
3154 	mutex_enter(&softp->intr_mutex);
3155 
3156 	/*
3157 	 * Fail if SBBC region has not been mapped. This shouldn't
3158 	 * happen if we have a master IOSRAM, but we double-check.
3159 	 */
3160 	if (softp->sbbc_region == NULL) {
3161 		mutex_exit(&softp->intr_mutex);
3162 		mutex_exit(&iosram_mutex);
3163 		DPRINTF(1, ("IOSRAM(%d): iosram_sema_acquire: "
3164 		    "SBBC not mapped\n", softp->instance));
3165 		return (ENXIO);
3166 	}
3167 
3168 	/* read semaphore value */
3169 	sema_val = IOSRAM_SEMA_RD(softp);
3170 	if (old_value != NULL)
3171 		*old_value = sema_val;
3172 
3173 	if (IOSRAM_SEMA_IS_HELD(sema_val)) {
3174 		/* semaphore was held by someone else */
3175 		rv = EBUSY;
3176 	} else {
3177 		/* semaphore was not held, we just acquired it */
3178 		rv = 0;
3179 	}
3180 
3181 	mutex_exit(&softp->intr_mutex);
3182 	mutex_exit(&iosram_mutex);
3183 
3184 	DPRINTF(1, ("IOSRAM(%d): iosram_sema_acquire: "
3185 	    "old value=0x%x rv=%d\n", softp->instance, sema_val, rv));
3186 
3187 	return (rv);
3188 }
3189 
3190 
3191 /*
3192  * iosram_sema_release: Release hardware semaphore.
3193  * This function will "release" the hardware semaphore, and return 0 on
3194  * success. If an error occured, one of the following values will be
3195  * returned:
3196  * EAGAIN: there is a tunnel switch in progress
3197  * ENXIO:  an IO error occured (e.g. SBBC not mapped)
3198  */
3199 int
3200 iosram_sema_release(void)
3201 {
3202 	struct iosramsoft	*softp;
3203 
3204 	DPRINTF(2, ("IOSRAM: in iosram_sema_release\n"));
3205 
3206 	mutex_enter(&iosram_mutex);
3207 
3208 	/*
3209 	 * Disallow access if there is a tunnel switch in progress.
3210 	 */
3211 	if (iosram_tswitch_active) {
3212 		mutex_exit(&iosram_mutex);
3213 		return (EAGAIN);
3214 	}
3215 
3216 	/*
3217 	 * Use current master IOSRAM for operation, fail if none is
3218 	 * currently active.
3219 	 */
3220 	if ((softp = iosram_master) == NULL) {
3221 		mutex_exit(&iosram_mutex);
3222 		DPRINTF(1, ("IOSRAM: iosram_sema_release: no master\n"));
3223 		return (ENXIO);
3224 	}
3225 
3226 	mutex_enter(&softp->intr_mutex);
3227 
3228 	/*
3229 	 * Fail if SBBC region has not been mapped in. This shouldn't
3230 	 * happen if we have a master IOSRAM, but we double-check.
3231 	 */
3232 	if (softp->sbbc_region == NULL) {
3233 		mutex_exit(&softp->intr_mutex);
3234 		mutex_exit(&iosram_mutex);
3235 		DPRINTF(1, ("IOSRAM(%d): iosram_sema_release: "
3236 		    "SBBC not mapped\n", softp->instance));
3237 		return (ENXIO);
3238 	}
3239 
3240 	/* Release semaphore by clearing our semaphore register */
3241 	IOSRAM_SEMA_WR(softp, 0);
3242 
3243 	mutex_exit(&softp->intr_mutex);
3244 	mutex_exit(&iosram_mutex);
3245 
3246 	DPRINTF(1, ("IOSRAM(%d): iosram_sema_release: success\n",
3247 	    softp->instance));
3248 
3249 	return (0);
3250 }
3251 
3252 
3253 #if defined(IOSRAM_LOG)
3254 void
3255 iosram_log(caddr_t fmt, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4)
3256 {
3257 	uint32_t	seq;
3258 	iosram_log_t	*logp;
3259 
3260 	mutex_enter(&iosram_log_mutex);
3261 
3262 	seq = iosram_logseq++;
3263 	logp = &iosram_logbuf[seq % IOSRAM_MAXLOG];
3264 	logp->seq = seq;
3265 	logp->tstamp = ddi_get_lbolt();
3266 	logp->fmt = fmt;
3267 	logp->arg1 = a1;
3268 	logp->arg2 = a2;
3269 	logp->arg3 = a3;
3270 	logp->arg4 = a4;
3271 
3272 	mutex_exit(&iosram_log_mutex);
3273 
3274 	if (iosram_log_print) {
3275 		cmn_err(CE_CONT, "#%x @%lx ", logp->seq, logp->tstamp);
3276 		if (logp->fmt) {
3277 			cmn_err(CE_CONT, logp->fmt, logp->arg1, logp->arg2,
3278 			    logp->arg3, logp->arg4);
3279 			if (logp->fmt[strlen(logp->fmt)-1] != '\n') {
3280 				cmn_err(CE_CONT, "\n");
3281 			}
3282 		} else {
3283 			cmn_err(CE_CONT, "fmt:%p args: %lx %lx %lx %lx\n",
3284 			    (void *)logp->fmt, logp->arg1, logp->arg2,
3285 			    logp->arg3, logp->arg4);
3286 		}
3287 	}
3288 }
3289 #endif /* IOSRAM_LOG */
3290 
3291 
3292 #if defined(DEBUG)
3293 /*
3294  * iosram_get_keys(buf, len)
3295  *	Return IOSRAM TOC in the specified buffer
3296  */
3297 static int
3298 iosram_get_keys(iosram_toc_entry_t *bufp, uint32_t *len)
3299 {
3300 	struct iosram_chunk	*chunkp;
3301 	int			error = 0;
3302 	int			i;
3303 	int			cnt = (*len) / sizeof (iosram_toc_entry_t);
3304 
3305 	IOSRAMLOG(2, "iosram_get_keys(bufp:%p *len:%x)\n", bufp, *len, NULL,
3306 	    NULL);
3307 
3308 	/*
3309 	 * Copy data while holding the lock to prevent any data
3310 	 * corruption or invalid pointer dereferencing.
3311 	 */
3312 	mutex_enter(&iosram_mutex);
3313 
3314 	if (iosram_master == NULL) {
3315 		error = EIO;
3316 	} else {
3317 		for (i = 0, chunkp = chunks; i < nchunks && i < cnt;
3318 		    i++, chunkp++) {
3319 			bufp[i].key = chunkp->toc_data.key;
3320 			bufp[i].off = chunkp->toc_data.off;
3321 			bufp[i].len = chunkp->toc_data.len;
3322 			bufp[i].unused = chunkp->toc_data.unused;
3323 		}
3324 		*len = i * sizeof (iosram_toc_entry_t);
3325 	}
3326 
3327 	mutex_exit(&iosram_mutex);
3328 	return (error);
3329 }
3330 
3331 
3332 /*
3333  * iosram_print_state(instance)
3334  */
3335 static void
3336 iosram_print_state(int instance)
3337 {
3338 	struct iosramsoft	*softp;
3339 	char			pn[MAXNAMELEN];
3340 
3341 	if (instance < 0) {
3342 		softp = iosram_master;
3343 	} else {
3344 		softp = ddi_get_soft_state(iosramsoft_statep, instance);
3345 	}
3346 
3347 	if (softp == NULL) {
3348 		cmn_err(CE_CONT, "iosram_print_state: Can't find instance %d\n",
3349 		    instance);
3350 		return;
3351 	}
3352 	instance = softp->instance;
3353 
3354 	mutex_enter(&iosram_mutex);
3355 	mutex_enter(&softp->intr_mutex);
3356 
3357 	cmn_err(CE_CONT, "iosram_print_state(%d): ... %s\n", instance,
3358 	    ((softp == iosram_master) ? "MASTER" : "SLAVE"));
3359 
3360 	(void) ddi_pathname(softp->dip, pn);
3361 	cmn_err(CE_CONT, "  pathname:%s\n", pn);
3362 	cmn_err(CE_CONT, "  instance:%d  portid:%d iosramlen:0x%x\n",
3363 	    softp->instance, softp->portid, softp->iosramlen);
3364 	cmn_err(CE_CONT, "  softp:%p  handle:%p  iosramp:%p\n", (void *)softp,
3365 	    (void *)softp->handle, (void *)softp->iosramp);
3366 	cmn_err(CE_CONT, "  state:0x%x  tswitch_ok:%x  tswitch_fail:%x\n",
3367 	    softp->state, softp->tswitch_ok, softp->tswitch_fail);
3368 	cmn_err(CE_CONT, "  softintr_id:%p  intr_busy:%x  intr_pending:%x\n",
3369 	    (void *)softp->softintr_id, softp->intr_busy, softp->intr_pending);
3370 
3371 	mutex_exit(&softp->intr_mutex);
3372 	mutex_exit(&iosram_mutex);
3373 }
3374 
3375 
3376 /*
3377  * iosram_print_stats()
3378  */
3379 static void
3380 iosram_print_stats()
3381 {
3382 	uint32_t	calls;
3383 
3384 	cmn_err(CE_CONT, "iosram_stats:\n");
3385 	calls = iosram_stats.read;
3386 	cmn_err(CE_CONT, " read  ... calls:%x  bytes:%lx  avg_sz:%x\n",
3387 	    calls, iosram_stats.bread,
3388 	    (uint32_t)((calls != 0) ? (iosram_stats.bread/calls) : 0));
3389 
3390 	calls = iosram_stats.write;
3391 	cmn_err(CE_CONT, " write ... calls:%x  bytes:%lx  avg_sz:%x\n",
3392 	    calls, iosram_stats.bwrite,
3393 	    (uint32_t)((calls != 0) ? (iosram_stats.bwrite/calls) : 0));
3394 
3395 	cmn_err(CE_CONT, " intr recv (real:%x  soft:%x)  sent:%x  cback:%x\n",
3396 	    iosram_stats.intr_recv, iosram_stats.sintr_recv,
3397 	    iosram_stats.intr_send, iosram_stats.callbacks);
3398 
3399 	cmn_err(CE_CONT, " tswitch: %x  getflag:%x  setflag:%x\n",
3400 	    iosram_stats.tswitch, iosram_stats.getflag,
3401 	    iosram_stats.setflag);
3402 
3403 	cmn_err(CE_CONT, " iosram_rw_active_max: %x\n", iosram_rw_active_max);
3404 }
3405 
3406 
3407 static void
3408 iosram_print_cback()
3409 {
3410 	iosram_chunk_t	*chunkp;
3411 	int		i;
3412 
3413 	/*
3414 	 * Print callback handlers
3415 	 */
3416 	mutex_enter(&iosram_mutex);
3417 
3418 	cmn_err(CE_CONT, "IOSRAM callbacks:\n");
3419 	for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) {
3420 		if (chunkp->cback.handler) {
3421 			cmn_err(CE_CONT, "  %2d: key:0x%x  hdlr:%p  arg:%p "
3422 			    "busy:%d unreg:%d\n", i, chunkp->toc_data.key,
3423 			    (void *)chunkp->cback.handler,
3424 			    (void *)chunkp->cback.arg,
3425 			    chunkp->cback.busy, chunkp->cback.unregister);
3426 		}
3427 	}
3428 	mutex_exit(&iosram_mutex);
3429 }
3430 
3431 
3432 static void
3433 iosram_print_flags()
3434 {
3435 	int		i;
3436 	uint32_t	*keys;
3437 	iosram_flags_t	*flags;
3438 
3439 	mutex_enter(&iosram_mutex);
3440 
3441 	if (iosram_master == NULL) {
3442 		mutex_exit(&iosram_mutex);
3443 		cmn_err(CE_CONT, "IOSRAM Flags: not accessible\n");
3444 		return;
3445 	}
3446 
3447 	keys = kmem_alloc(nchunks * sizeof (uint32_t), KM_SLEEP);
3448 	flags = kmem_alloc(nchunks * sizeof (iosram_flags_t), KM_SLEEP);
3449 
3450 	for (i = 0; i < nchunks; i++) {
3451 		keys[i] = chunks[i].toc_data.key;
3452 		ddi_rep_get8(iosram_handle, (uint8_t *)&(flags[i]),
3453 		    (uint8_t *)(chunks[i].flagsp), sizeof (iosram_flags_t),
3454 		    DDI_DEV_AUTOINCR);
3455 	}
3456 
3457 	mutex_exit(&iosram_mutex);
3458 
3459 	cmn_err(CE_CONT, "IOSRAM Flags:\n");
3460 	for (i = 0; i < nchunks; i++) {
3461 		cmn_err(CE_CONT,
3462 		    "  %2d: key: 0x%x  data_valid:%x  int_pending:%x\n",
3463 		    i, keys[i], flags[i].data_valid, flags[i].int_pending);
3464 	}
3465 
3466 	kmem_free(keys, nchunks * sizeof (uint32_t));
3467 	kmem_free(flags, nchunks * sizeof (iosram_flags_t));
3468 }
3469 
3470 
3471 /*PRINTFLIKE1*/
3472 static void
3473 iosram_dprintf(const char *fmt, ...)
3474 {
3475 	char	msg_buf[256];
3476 	va_list	adx;
3477 
3478 	va_start(adx, fmt);
3479 	(void) vsprintf(msg_buf, fmt, adx);
3480 	va_end(adx);
3481 
3482 	cmn_err(CE_CONT, "%s", msg_buf);
3483 }
3484 #endif /* DEBUG */
3485 
3486 
3487 #if IOSRAM_LOG
3488 /*
3489  * iosram_print_log(int cnt)
3490  *	Print last few entries of the IOSRAM log in reverse order
3491  */
3492 static void
3493 iosram_print_log(int cnt)
3494 {
3495 	int	i;
3496 
3497 	if (cnt <= 0) {
3498 		cnt = 20;
3499 	} else if (cnt > IOSRAM_MAXLOG) {
3500 		cnt = IOSRAM_MAXLOG;
3501 	}
3502 
3503 
3504 	cmn_err(CE_CONT,
3505 	    "\niosram_logseq: 0x%x  lbolt: %lx  iosram_log_level:%x\n",
3506 	    iosram_logseq, ddi_get_lbolt(), iosram_log_level);
3507 	cmn_err(CE_CONT, "iosram_logbuf: %p  max entries:0x%x\n",
3508 	    (void *)iosram_logbuf, IOSRAM_MAXLOG);
3509 	for (i = iosram_logseq;  --i >= 0 && --cnt >= 0; ) {
3510 		iosram_log_t	*logp;
3511 
3512 		mutex_enter(&iosram_log_mutex);
3513 
3514 		logp = &iosram_logbuf[i %IOSRAM_MAXLOG];
3515 		cmn_err(CE_CONT, "#%x @%lx ", logp->seq, logp->tstamp);
3516 
3517 		if (logp->fmt) {
3518 			cmn_err(CE_CONT, logp->fmt, logp->arg1, logp->arg2,
3519 			    logp->arg3, logp->arg4);
3520 			if (logp->fmt[strlen(logp->fmt)-1] != '\n') {
3521 				cmn_err(CE_CONT, "\n");
3522 			}
3523 		} else {
3524 			cmn_err(CE_CONT, "fmt:%p args: %lx %lx %lx %lx\n",
3525 			    (void *)logp->fmt, logp->arg1, logp->arg2,
3526 			    logp->arg3, logp->arg4);
3527 		}
3528 
3529 		mutex_exit(&iosram_log_mutex);
3530 	}
3531 }
3532 #endif	/* IOSRAM_LOG */
3533