xref: /titanic_44/usr/src/uts/common/io/bofi.c (revision 5c46c6a053defc1bf25f2e08df2653bc7717ed0b)
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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/sysmacros.h>
30 #include <sys/buf.h>
31 #include <sys/errno.h>
32 #include <sys/modctl.h>
33 #include <sys/conf.h>
34 #include <sys/stat.h>
35 #include <sys/kmem.h>
36 #include <sys/proc.h>
37 #include <sys/cpuvar.h>
38 #include <sys/ddi_impldefs.h>
39 #include <sys/ddi.h>
40 #include <sys/fm/protocol.h>
41 #include <sys/fm/util.h>
42 #include <sys/fm/io/ddi.h>
43 #include <sys/sysevent/eventdefs.h>
44 #include <sys/sunddi.h>
45 #include <sys/sunndi.h>
46 #include <sys/debug.h>
47 #include <sys/bofi.h>
48 #include <sys/dvma.h>
49 #include <sys/bofi_impl.h>
50 
51 /*
52  * Testing the resilience of a hardened device driver requires a suitably wide
53  * range of different types of "typical" hardware faults to be injected,
54  * preferably in a controlled and repeatable fashion. This is not in general
55  * possible via hardware, so the "fault injection test harness" is provided.
56  * This works by intercepting calls from the driver to various DDI routines,
57  * and then corrupting the result of those DDI routine calls as if the
58  * hardware had caused the corruption.
59  *
60  * Conceptually, the bofi driver consists of two parts:
61  *
62  * A driver interface that supports a number of ioctls which allow error
63  * definitions ("errdefs") to be defined and subsequently managed. The
64  * driver is a clone driver, so each open will create a separate
65  * invocation. Any errdefs created by using ioctls to that invocation
66  * will automatically be deleted when that invocation is closed.
67  *
68  * Intercept routines: When the bofi driver is attached, it edits the
69  * bus_ops structure of the bus nexus specified by the "bofi-nexus"
70  * field in the "bofi.conf" file, thus allowing the
71  * bofi driver to intercept various ddi functions. These intercept
72  * routines primarily carry out fault injections based on the errdefs
73  * created for that device.
74  *
75  * Faults can be injected into:
76  *
77  * DMA (corrupting data for DMA to/from memory areas defined by
78  * ddi_dma_setup(), ddi_dma_bind_handle(), etc)
79  *
80  * Physical IO (corrupting data sent/received via ddi_get8(), ddi_put8(),
81  * etc),
82  *
83  * Interrupts (generating spurious interrupts, losing interrupts,
84  * delaying interrupts).
85  *
86  * By default, ddi routines called from all drivers will be intercepted
87  * and faults potentially injected. However, the "bofi-to-test" field in
88  * the "bofi.conf" file can be set to a space-separated list of drivers to
89  * test (or by preceding each driver name in the list with an "!", a list
90  * of drivers not to test).
91  *
92  * In addition to fault injection, the bofi driver does a number of static
93  * checks which are controlled by properties in the "bofi.conf" file.
94  *
95  * "bofi-ddi-check" - if set will validate that there are no PIO access
96  * other than those using the DDI routines (ddi_get8(), ddi_put8(), etc).
97  *
98  * "bofi-range-check" - if set to values 1 (warning) or 2 (panic), will
99  * validate that calls to ddi_get8(), ddi_put8(), etc are not made
100  * specifying addresses outside the range of the access_handle.
101  *
102  * "bofi-sync-check" - if set will validate that calls to ddi_dma_sync()
103  * are being made correctly.
104  */
105 
106 extern void *bp_mapin_common(struct buf *, int);
107 
108 static int bofi_ddi_check;
109 static int bofi_sync_check;
110 static int bofi_range_check;
111 
112 static struct bofi_link bofi_link_array[BOFI_NLINKS], *bofi_link_freelist;
113 
114 #define	LLSZMASK (sizeof (uint64_t)-1)
115 
116 #define	HDL_HASH_TBL_SIZE 64
117 static struct bofi_shadow hhash_table[HDL_HASH_TBL_SIZE];
118 static struct bofi_shadow dhash_table[HDL_HASH_TBL_SIZE];
119 #define	HDL_DHASH(x) \
120 	(&dhash_table[((uintptr_t)(x) >> 3) & (HDL_HASH_TBL_SIZE-1)])
121 #define	HDL_HHASH(x) \
122 	(&hhash_table[((uintptr_t)(x) >> 5) & (HDL_HASH_TBL_SIZE-1)])
123 
124 static struct bofi_shadow shadow_list;
125 static struct bofi_errent *errent_listp;
126 
127 static char driver_list[NAMESIZE];
128 static int driver_list_size;
129 static int driver_list_neg;
130 static char nexus_name[NAMESIZE];
131 
132 static int initialized = 0;
133 
134 #define	NCLONES 256
135 static int clone_tab[NCLONES];
136 
137 static dev_info_t *our_dip;
138 
139 static kmutex_t bofi_mutex;
140 static kmutex_t clone_tab_mutex;
141 static kmutex_t bofi_low_mutex;
142 static ddi_iblock_cookie_t bofi_low_cookie;
143 static uint_t	bofi_signal(caddr_t arg);
144 static int	bofi_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
145 static int	bofi_attach(dev_info_t *, ddi_attach_cmd_t);
146 static int	bofi_detach(dev_info_t *, ddi_detach_cmd_t);
147 static int	bofi_open(dev_t *, int, int, cred_t *);
148 static int	bofi_close(dev_t, int, int, cred_t *);
149 static int	bofi_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
150 static int	bofi_errdef_alloc(struct bofi_errdef *, char *,
151 		    struct bofi_errent *);
152 static int	bofi_errdef_free(struct bofi_errent *);
153 static void	bofi_start(struct bofi_errctl *, char *);
154 static void	bofi_stop(struct bofi_errctl *, char *);
155 static void	bofi_broadcast(struct bofi_errctl *, char *);
156 static void	bofi_clear_acc_chk(struct bofi_errctl *, char *);
157 static void	bofi_clear_errors(struct bofi_errctl *, char *);
158 static void	bofi_clear_errdefs(struct bofi_errctl *, char *);
159 static int	bofi_errdef_check(struct bofi_errstate *,
160 		    struct acc_log_elem **);
161 static int	bofi_errdef_check_w(struct bofi_errstate *,
162 		    struct acc_log_elem **);
163 static int	bofi_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
164 		    off_t, off_t, caddr_t *);
165 static int	bofi_dma_map(dev_info_t *, dev_info_t *,
166 		    struct ddi_dma_req *, ddi_dma_handle_t *);
167 static int	bofi_dma_allochdl(dev_info_t *, dev_info_t *,
168 		    ddi_dma_attr_t *, int (*)(caddr_t), caddr_t,
169 		    ddi_dma_handle_t *);
170 static int	bofi_dma_freehdl(dev_info_t *, dev_info_t *,
171 		    ddi_dma_handle_t);
172 static int	bofi_dma_bindhdl(dev_info_t *, dev_info_t *,
173 		    ddi_dma_handle_t, struct ddi_dma_req *, ddi_dma_cookie_t *,
174 		    uint_t *);
175 static int	bofi_dma_unbindhdl(dev_info_t *, dev_info_t *,
176 		    ddi_dma_handle_t);
177 static int	bofi_dma_flush(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
178 		    off_t, size_t, uint_t);
179 static int	bofi_dma_ctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
180 		    enum ddi_dma_ctlops, off_t *, size_t *, caddr_t *, uint_t);
181 static int	bofi_dma_win(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
182 		    uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *);
183 static int	bofi_intr_ops(dev_info_t *dip, dev_info_t *rdip,
184 		    ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp,
185 		    void *result);
186 static int	bofi_fm_ereport_callback(sysevent_t *ev, void *cookie);
187 
188 evchan_t *bofi_error_chan;
189 
190 #define	FM_SIMULATED_DMA "simulated.dma"
191 #define	FM_SIMULATED_PIO "simulated.pio"
192 
193 #if defined(__sparc)
194 static void	bofi_dvma_kaddr_load(ddi_dma_handle_t, caddr_t, uint_t,
195 		    uint_t, ddi_dma_cookie_t *);
196 static void	bofi_dvma_unload(ddi_dma_handle_t, uint_t, uint_t);
197 static void	bofi_dvma_sync(ddi_dma_handle_t, uint_t, uint_t);
198 static void	bofi_dvma_reserve(dev_info_t *, ddi_dma_handle_t);
199 #endif
200 static int	driver_under_test(dev_info_t *);
201 static int	bofi_check_acc_hdl(ddi_acc_impl_t *);
202 static int	bofi_check_dma_hdl(ddi_dma_impl_t *);
203 static int	bofi_post_event(dev_info_t *dip, dev_info_t *rdip,
204 		    ddi_eventcookie_t eventhdl, void *impl_data);
205 
206 static struct bus_ops bofi_bus_ops = {
207 	BUSO_REV,
208 	bofi_map,
209 	NULL,
210 	NULL,
211 	NULL,
212 	i_ddi_map_fault,
213 	bofi_dma_map,
214 	bofi_dma_allochdl,
215 	bofi_dma_freehdl,
216 	bofi_dma_bindhdl,
217 	bofi_dma_unbindhdl,
218 	bofi_dma_flush,
219 	bofi_dma_win,
220 	bofi_dma_ctl,
221 	NULL,
222 	ddi_bus_prop_op,
223 	ndi_busop_get_eventcookie,
224 	ndi_busop_add_eventcall,
225 	ndi_busop_remove_eventcall,
226 	bofi_post_event,
227 	NULL,
228 	0,
229 	0,
230 	0,
231 	0,
232 	0,
233 	0,
234 	0,
235 	bofi_intr_ops
236 };
237 
238 static struct cb_ops bofi_cb_ops = {
239 	bofi_open,		/* open */
240 	bofi_close,		/* close */
241 	nodev,			/* strategy */
242 	nodev,			/* print */
243 	nodev,			/* dump */
244 	nodev,			/* read */
245 	nodev,			/* write */
246 	bofi_ioctl,		/* ioctl */
247 	nodev,			/* devmap */
248 	nodev,			/* mmap */
249 	nodev,			/* segmap */
250 	nochpoll,		/* chpoll */
251 	ddi_prop_op,		/* prop_op */
252 	NULL,			/* for STREAMS drivers */
253 	D_MP,			/* driver compatibility flag */
254 	CB_REV,			/* cb_ops revision */
255 	nodev,			/* aread */
256 	nodev			/* awrite */
257 };
258 
259 static struct dev_ops bofi_ops = {
260 	DEVO_REV,		/* driver build version */
261 	0,			/* device reference count */
262 	bofi_getinfo,
263 	nulldev,
264 	nulldev,		/* probe */
265 	bofi_attach,
266 	bofi_detach,
267 	nulldev,		/* reset */
268 	&bofi_cb_ops,
269 	(struct bus_ops *)NULL,
270 	nulldev			/* power */
271 };
272 
273 /* module configuration stuff */
274 static void    *statep;
275 
276 static struct modldrv modldrv = {
277 	&mod_driverops,
278 	"bofi driver %I%",
279 	&bofi_ops
280 };
281 
282 static struct modlinkage modlinkage = {
283 	MODREV_1,
284 	&modldrv,
285 	0
286 };
287 
288 static struct bus_ops save_bus_ops;
289 
290 #if defined(__sparc)
291 static struct dvma_ops bofi_dvma_ops = {
292 	DVMAO_REV,
293 	bofi_dvma_kaddr_load,
294 	bofi_dvma_unload,
295 	bofi_dvma_sync
296 };
297 #endif
298 
299 /*
300  * support routine - map user page into kernel virtual
301  */
302 static caddr_t
303 dmareq_mapin(offset_t len, caddr_t addr, struct as *as, int flag)
304 {
305 	struct buf buf;
306 	struct proc proc;
307 
308 	/*
309 	 * mock up a buf structure so we can call bp_mapin_common()
310 	 */
311 	buf.b_flags = B_PHYS;
312 	buf.b_un.b_addr = (caddr_t)addr;
313 	buf.b_bcount = (size_t)len;
314 	proc.p_as = as;
315 	buf.b_proc = &proc;
316 	return (bp_mapin_common(&buf, flag));
317 }
318 
319 
320 /*
321  * support routine - map page chain into kernel virtual
322  */
323 static caddr_t
324 dmareq_pp_mapin(offset_t len, uint_t offset, page_t *pp, int flag)
325 {
326 	struct buf buf;
327 
328 	/*
329 	 * mock up a buf structure so we can call bp_mapin_common()
330 	 */
331 	buf.b_flags = B_PAGEIO;
332 	buf.b_un.b_addr = (caddr_t)(uintptr_t)offset;
333 	buf.b_bcount = (size_t)len;
334 	buf.b_pages = pp;
335 	return (bp_mapin_common(&buf, flag));
336 }
337 
338 
339 /*
340  * support routine - map page array into kernel virtual
341  */
342 static caddr_t
343 dmareq_pplist_mapin(uint_t len, caddr_t addr, page_t **pplist, struct as *as,
344     int flag)
345 {
346 	struct buf buf;
347 	struct proc proc;
348 
349 	/*
350 	 * mock up a buf structure so we can call bp_mapin_common()
351 	 */
352 	buf.b_flags = B_PHYS|B_SHADOW;
353 	buf.b_un.b_addr = addr;
354 	buf.b_bcount = len;
355 	buf.b_shadow = pplist;
356 	proc.p_as = as;
357 	buf.b_proc = &proc;
358 	return (bp_mapin_common(&buf, flag));
359 }
360 
361 
362 /*
363  * support routine - map dmareq into kernel virtual if not already
364  * fills in *lenp with length
365  * *mapaddr will be new kernel virtual address - or null if no mapping needed
366  */
367 static caddr_t
368 ddi_dmareq_mapin(struct ddi_dma_req *dmareqp, caddr_t *mapaddrp,
369 	offset_t *lenp)
370 {
371 	int sleep = (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? VM_SLEEP: VM_NOSLEEP;
372 
373 	*lenp = dmareqp->dmar_object.dmao_size;
374 	if (dmareqp->dmar_object.dmao_type == DMA_OTYP_PAGES) {
375 		*mapaddrp = dmareq_pp_mapin(dmareqp->dmar_object.dmao_size,
376 		    dmareqp->dmar_object.dmao_obj.pp_obj.pp_offset,
377 		    dmareqp->dmar_object.dmao_obj.pp_obj.pp_pp, sleep);
378 		return (*mapaddrp);
379 	} else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_priv != NULL) {
380 		*mapaddrp = dmareq_pplist_mapin(dmareqp->dmar_object.dmao_size,
381 		    dmareqp->dmar_object.dmao_obj.virt_obj.v_addr,
382 		    dmareqp->dmar_object.dmao_obj.virt_obj.v_priv,
383 		    dmareqp->dmar_object.dmao_obj.virt_obj.v_as, sleep);
384 		return (*mapaddrp);
385 	} else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_as == &kas) {
386 		*mapaddrp = NULL;
387 		return (dmareqp->dmar_object.dmao_obj.virt_obj.v_addr);
388 	} else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_as == NULL) {
389 		*mapaddrp = NULL;
390 		return (dmareqp->dmar_object.dmao_obj.virt_obj.v_addr);
391 	} else {
392 		*mapaddrp = dmareq_mapin(dmareqp->dmar_object.dmao_size,
393 		    dmareqp->dmar_object.dmao_obj.virt_obj.v_addr,
394 		    dmareqp->dmar_object.dmao_obj.virt_obj.v_as, sleep);
395 		return (*mapaddrp);
396 	}
397 }
398 
399 
400 /*
401  * support routine - free off kernel virtual mapping as allocated by
402  * ddi_dmareq_mapin()
403  */
404 static void
405 ddi_dmareq_mapout(caddr_t addr, offset_t len)
406 {
407 	struct buf buf;
408 
409 	if (addr == NULL)
410 		return;
411 	/*
412 	 * mock up a buf structure
413 	 */
414 	buf.b_flags = B_REMAPPED;
415 	buf.b_un.b_addr = addr;
416 	buf.b_bcount = (size_t)len;
417 	bp_mapout(&buf);
418 }
419 
420 static time_t
421 bofi_gettime()
422 {
423 	timestruc_t ts;
424 
425 	gethrestime(&ts);
426 	return (ts.tv_sec);
427 }
428 
429 /*
430  * reset the bus_ops structure of the specified nexus to point to
431  * the original values in the save_bus_ops structure.
432  *
433  * Note that both this routine and modify_bus_ops() rely on the current
434  * behavior of the framework in that nexus drivers are not unloadable
435  *
436  */
437 
438 static int
439 reset_bus_ops(char *name, struct bus_ops *bop)
440 {
441 	struct modctl *modp;
442 	struct modldrv *mp;
443 	struct bus_ops *bp;
444 	struct dev_ops *ops;
445 
446 	mutex_enter(&mod_lock);
447 	/*
448 	 * find specified module
449 	 */
450 	modp = &modules;
451 	do {
452 		if (strcmp(name, modp->mod_modname) == 0) {
453 			if (!modp->mod_linkage) {
454 				mutex_exit(&mod_lock);
455 				return (0);
456 			}
457 			mp = modp->mod_linkage->ml_linkage[0];
458 			if (!mp || !mp->drv_dev_ops) {
459 				mutex_exit(&mod_lock);
460 				return (0);
461 			}
462 			ops = mp->drv_dev_ops;
463 			bp = ops->devo_bus_ops;
464 			if (!bp) {
465 				mutex_exit(&mod_lock);
466 				return (0);
467 			}
468 			if (ops->devo_refcnt > 0) {
469 				/*
470 				 * As long as devices are active with modified
471 				 * bus ops bofi must not go away. There may be
472 				 * drivers with modified access or dma handles.
473 				 */
474 				mutex_exit(&mod_lock);
475 				return (0);
476 			}
477 			cmn_err(CE_NOTE, "bofi reset bus_ops for %s",
478 			    mp->drv_linkinfo);
479 			bp->bus_intr_op = bop->bus_intr_op;
480 			bp->bus_post_event = bop->bus_post_event;
481 			bp->bus_map = bop->bus_map;
482 			bp->bus_dma_map = bop->bus_dma_map;
483 			bp->bus_dma_allochdl = bop->bus_dma_allochdl;
484 			bp->bus_dma_freehdl = bop->bus_dma_freehdl;
485 			bp->bus_dma_bindhdl = bop->bus_dma_bindhdl;
486 			bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl;
487 			bp->bus_dma_flush = bop->bus_dma_flush;
488 			bp->bus_dma_win = bop->bus_dma_win;
489 			bp->bus_dma_ctl = bop->bus_dma_ctl;
490 			mutex_exit(&mod_lock);
491 			return (1);
492 		}
493 	} while ((modp = modp->mod_next) != &modules);
494 	mutex_exit(&mod_lock);
495 	return (0);
496 }
497 
498 /*
499  * modify the bus_ops structure of the specified nexus to point to bofi
500  * routines, saving the original values in the save_bus_ops structure
501  */
502 
503 static int
504 modify_bus_ops(char *name, struct bus_ops *bop)
505 {
506 	struct modctl *modp;
507 	struct modldrv *mp;
508 	struct bus_ops *bp;
509 	struct dev_ops *ops;
510 
511 	if (ddi_name_to_major(name) == -1)
512 		return (0);
513 
514 	mutex_enter(&mod_lock);
515 	/*
516 	 * find specified module
517 	 */
518 	modp = &modules;
519 	do {
520 		if (strcmp(name, modp->mod_modname) == 0) {
521 			if (!modp->mod_linkage) {
522 				mutex_exit(&mod_lock);
523 				return (0);
524 			}
525 			mp = modp->mod_linkage->ml_linkage[0];
526 			if (!mp || !mp->drv_dev_ops) {
527 				mutex_exit(&mod_lock);
528 				return (0);
529 			}
530 			ops = mp->drv_dev_ops;
531 			bp = ops->devo_bus_ops;
532 			if (!bp) {
533 				mutex_exit(&mod_lock);
534 				return (0);
535 			}
536 			if (ops->devo_refcnt == 0) {
537 				/*
538 				 * If there is no device active for this
539 				 * module then there is nothing to do for bofi.
540 				 */
541 				mutex_exit(&mod_lock);
542 				return (0);
543 			}
544 			cmn_err(CE_NOTE, "bofi modify bus_ops for %s",
545 			    mp->drv_linkinfo);
546 			save_bus_ops = *bp;
547 			bp->bus_intr_op = bop->bus_intr_op;
548 			bp->bus_post_event = bop->bus_post_event;
549 			bp->bus_map = bop->bus_map;
550 			bp->bus_dma_map = bop->bus_dma_map;
551 			bp->bus_dma_allochdl = bop->bus_dma_allochdl;
552 			bp->bus_dma_freehdl = bop->bus_dma_freehdl;
553 			bp->bus_dma_bindhdl = bop->bus_dma_bindhdl;
554 			bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl;
555 			bp->bus_dma_flush = bop->bus_dma_flush;
556 			bp->bus_dma_win = bop->bus_dma_win;
557 			bp->bus_dma_ctl = bop->bus_dma_ctl;
558 			mutex_exit(&mod_lock);
559 			return (1);
560 		}
561 	} while ((modp = modp->mod_next) != &modules);
562 	mutex_exit(&mod_lock);
563 	return (0);
564 }
565 
566 
567 int
568 _init(void)
569 {
570 	int    e;
571 
572 	e = ddi_soft_state_init(&statep, sizeof (struct bofi_errent), 1);
573 	if (e != 0)
574 		return (e);
575 	if ((e = mod_install(&modlinkage)) != 0)
576 		ddi_soft_state_fini(&statep);
577 	return (e);
578 }
579 
580 
581 int
582 _fini(void)
583 {
584 	int e;
585 
586 	if ((e = mod_remove(&modlinkage)) != 0)
587 		return (e);
588 	ddi_soft_state_fini(&statep);
589 	return (e);
590 }
591 
592 
593 int
594 _info(struct modinfo *modinfop)
595 {
596 	return (mod_info(&modlinkage, modinfop));
597 }
598 
599 
600 static int
601 bofi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
602 {
603 	char *name;
604 	char buf[80];
605 	int i;
606 	int s, ss;
607 	int size = NAMESIZE;
608 	int new_string;
609 	char *ptr;
610 
611 	if (cmd != DDI_ATTACH)
612 		return (DDI_FAILURE);
613 	/*
614 	 * only one instance - but we clone using the open routine
615 	 */
616 	if (ddi_get_instance(dip) > 0)
617 		return (DDI_FAILURE);
618 
619 	if (!initialized) {
620 		if ((name = ddi_get_name(dip)) == NULL)
621 			return (DDI_FAILURE);
622 		(void) snprintf(buf, sizeof (buf), "%s,ctl", name);
623 		if (ddi_create_minor_node(dip, buf, S_IFCHR, 0,
624 		    DDI_PSEUDO, NULL) == DDI_FAILURE)
625 			return (DDI_FAILURE);
626 
627 		if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_MED,
628 		    &bofi_low_cookie) != DDI_SUCCESS) {
629 			ddi_remove_minor_node(dip, buf);
630 			return (DDI_FAILURE); /* fail attach */
631 		}
632 		/*
633 		 * get nexus name (from conf file)
634 		 */
635 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0,
636 		    "bofi-nexus", nexus_name, &size) != DDI_PROP_SUCCESS) {
637 			ddi_remove_minor_node(dip, buf);
638 			return (DDI_FAILURE);
639 		}
640 		/*
641 		 * get whether to do dma map kmem private checking
642 		 */
643 		if ((bofi_range_check = ddi_prop_lookup_string(DDI_DEV_T_ANY,
644 		    dip, 0, "bofi-range-check", &ptr)) != DDI_PROP_SUCCESS)
645 			bofi_range_check = 0;
646 		else if (strcmp(ptr, "panic") == 0)
647 			bofi_range_check = 2;
648 		else if (strcmp(ptr, "warn") == 0)
649 			bofi_range_check = 1;
650 		else
651 			bofi_range_check = 0;
652 		ddi_prop_free(ptr);
653 
654 		/*
655 		 * get whether to prevent direct access to register
656 		 */
657 		if ((bofi_ddi_check = ddi_prop_lookup_string(DDI_DEV_T_ANY,
658 		    dip, 0, "bofi-ddi-check", &ptr)) != DDI_PROP_SUCCESS)
659 			bofi_ddi_check = 0;
660 		else if (strcmp(ptr, "on") == 0)
661 			bofi_ddi_check = 1;
662 		else
663 			bofi_ddi_check = 0;
664 		ddi_prop_free(ptr);
665 
666 		/*
667 		 * get whether to do copy on ddi_dma_sync
668 		 */
669 		if ((bofi_sync_check = ddi_prop_lookup_string(DDI_DEV_T_ANY,
670 		    dip, 0, "bofi-sync-check", &ptr)) != DDI_PROP_SUCCESS)
671 			bofi_sync_check = 0;
672 		else if (strcmp(ptr, "on") == 0)
673 			bofi_sync_check = 1;
674 		else
675 			bofi_sync_check = 0;
676 		ddi_prop_free(ptr);
677 
678 		/*
679 		 * get driver-under-test names (from conf file)
680 		 */
681 		size = NAMESIZE;
682 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0,
683 		    "bofi-to-test", driver_list, &size) != DDI_PROP_SUCCESS)
684 			driver_list[0] = 0;
685 		/*
686 		 * and convert into a sequence of strings
687 		 */
688 		driver_list_neg = 1;
689 		new_string = 1;
690 		driver_list_size = strlen(driver_list);
691 		for (i = 0; i < driver_list_size; i++) {
692 			if (driver_list[i] == ' ') {
693 				driver_list[i] = '\0';
694 				new_string = 1;
695 			} else if (new_string) {
696 				if (driver_list[i] != '!')
697 					driver_list_neg = 0;
698 				new_string = 0;
699 			}
700 		}
701 		/*
702 		 * initialize mutex, lists
703 		 */
704 		mutex_init(&clone_tab_mutex, NULL, MUTEX_DRIVER,
705 		    NULL);
706 		/*
707 		 * fake up iblock cookie - need to protect outselves
708 		 * against drivers that use hilevel interrupts
709 		 */
710 		ss = spl8();
711 		s = spl8();
712 		splx(ss);
713 		mutex_init(&bofi_mutex, NULL, MUTEX_SPIN, (void *)(uintptr_t)s);
714 		mutex_init(&bofi_low_mutex, NULL, MUTEX_DRIVER,
715 		    (void *)bofi_low_cookie);
716 		shadow_list.next = &shadow_list;
717 		shadow_list.prev = &shadow_list;
718 		for (i = 0; i < HDL_HASH_TBL_SIZE; i++) {
719 			hhash_table[i].hnext = &hhash_table[i];
720 			hhash_table[i].hprev = &hhash_table[i];
721 			dhash_table[i].dnext = &dhash_table[i];
722 			dhash_table[i].dprev = &dhash_table[i];
723 		}
724 		for (i = 1; i < BOFI_NLINKS; i++)
725 			bofi_link_array[i].link = &bofi_link_array[i-1];
726 		bofi_link_freelist = &bofi_link_array[BOFI_NLINKS - 1];
727 		/*
728 		 * overlay bus_ops structure
729 		 */
730 		if (modify_bus_ops(nexus_name, &bofi_bus_ops) == 0) {
731 			ddi_remove_minor_node(dip, buf);
732 			mutex_destroy(&clone_tab_mutex);
733 			mutex_destroy(&bofi_mutex);
734 			mutex_destroy(&bofi_low_mutex);
735 			return (DDI_FAILURE);
736 		}
737 		if (sysevent_evc_bind(FM_ERROR_CHAN, &bofi_error_chan, 0) == 0)
738 			(void) sysevent_evc_subscribe(bofi_error_chan, "bofi",
739 			    EC_FM, bofi_fm_ereport_callback, NULL, 0);
740 
741 		/*
742 		 * save dip for getinfo
743 		 */
744 		our_dip = dip;
745 		ddi_report_dev(dip);
746 		initialized = 1;
747 	}
748 	return (DDI_SUCCESS);
749 }
750 
751 
752 static int
753 bofi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
754 {
755 	char *name;
756 	char buf[80];
757 
758 	if (cmd != DDI_DETACH)
759 		return (DDI_FAILURE);
760 	if (ddi_get_instance(dip) > 0)
761 		return (DDI_FAILURE);
762 	if ((name = ddi_get_name(dip)) == NULL)
763 		return (DDI_FAILURE);
764 	(void) snprintf(buf, sizeof (buf), "%s,ctl", name);
765 	mutex_enter(&bofi_low_mutex);
766 	mutex_enter(&bofi_mutex);
767 	/*
768 	 * make sure test bofi is no longer in use
769 	 */
770 	if (shadow_list.next != &shadow_list || errent_listp != NULL) {
771 		mutex_exit(&bofi_mutex);
772 		mutex_exit(&bofi_low_mutex);
773 		return (DDI_FAILURE);
774 	}
775 	mutex_exit(&bofi_mutex);
776 	mutex_exit(&bofi_low_mutex);
777 
778 	/*
779 	 * restore bus_ops structure
780 	 */
781 	if (reset_bus_ops(nexus_name, &save_bus_ops) == 0)
782 		return (DDI_FAILURE);
783 
784 	sysevent_evc_unbind(bofi_error_chan);
785 
786 	mutex_destroy(&clone_tab_mutex);
787 	mutex_destroy(&bofi_mutex);
788 	mutex_destroy(&bofi_low_mutex);
789 	ddi_remove_minor_node(dip, buf);
790 	our_dip = NULL;
791 	initialized = 0;
792 	return (DDI_SUCCESS);
793 }
794 
795 
796 /* ARGSUSED */
797 static int
798 bofi_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
799 {
800 	dev_t	dev = (dev_t)arg;
801 	int	minor = (int)getminor(dev);
802 	int	retval;
803 
804 	switch (cmd) {
805 	case DDI_INFO_DEVT2DEVINFO:
806 		if (minor != 0 || our_dip == NULL) {
807 			*result = (void *)NULL;
808 			retval = DDI_FAILURE;
809 		} else {
810 			*result = (void *)our_dip;
811 			retval = DDI_SUCCESS;
812 		}
813 		break;
814 	case DDI_INFO_DEVT2INSTANCE:
815 		*result = (void *)0;
816 		retval = DDI_SUCCESS;
817 		break;
818 	default:
819 		retval = DDI_FAILURE;
820 	}
821 	return (retval);
822 }
823 
824 
825 /* ARGSUSED */
826 static int
827 bofi_open(dev_t *devp, int flag, int otyp, cred_t *credp)
828 {
829 	int	minor = (int)getminor(*devp);
830 	struct bofi_errent *softc;
831 
832 	/*
833 	 * only allow open on minor=0 - the clone device
834 	 */
835 	if (minor != 0)
836 		return (ENXIO);
837 	/*
838 	 * fail if not attached
839 	 */
840 	if (!initialized)
841 		return (ENXIO);
842 	/*
843 	 * find a free slot and grab it
844 	 */
845 	mutex_enter(&clone_tab_mutex);
846 	for (minor = 1; minor < NCLONES; minor++) {
847 		if (clone_tab[minor] == 0) {
848 			clone_tab[minor] = 1;
849 			break;
850 		}
851 	}
852 	mutex_exit(&clone_tab_mutex);
853 	if (minor == NCLONES)
854 		return (EAGAIN);
855 	/*
856 	 * soft state structure for this clone is used to maintain a list
857 	 * of allocated errdefs so they can be freed on close
858 	 */
859 	if (ddi_soft_state_zalloc(statep, minor) != DDI_SUCCESS) {
860 		mutex_enter(&clone_tab_mutex);
861 		clone_tab[minor] = 0;
862 		mutex_exit(&clone_tab_mutex);
863 		return (EAGAIN);
864 	}
865 	softc = ddi_get_soft_state(statep, minor);
866 	softc->cnext = softc;
867 	softc->cprev = softc;
868 
869 	*devp = makedevice(getmajor(*devp), minor);
870 	return (0);
871 }
872 
873 
874 /* ARGSUSED */
875 static int
876 bofi_close(dev_t dev, int flag, int otyp, cred_t *credp)
877 {
878 	int	minor = (int)getminor(dev);
879 	struct bofi_errent *softc;
880 	struct bofi_errent *ep, *next_ep;
881 
882 	softc = ddi_get_soft_state(statep, minor);
883 	if (softc == NULL)
884 		return (ENXIO);
885 	/*
886 	 * find list of errdefs and free them off
887 	 */
888 	for (ep = softc->cnext; ep != softc; ) {
889 		next_ep = ep->cnext;
890 		(void) bofi_errdef_free(ep);
891 		ep = next_ep;
892 	}
893 	/*
894 	 * free clone tab slot
895 	 */
896 	mutex_enter(&clone_tab_mutex);
897 	clone_tab[minor] = 0;
898 	mutex_exit(&clone_tab_mutex);
899 
900 	ddi_soft_state_free(statep, minor);
901 	return (0);
902 }
903 
904 
905 /* ARGSUSED */
906 static int
907 bofi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
908 	int *rvalp)
909 {
910 	struct bofi_errent *softc;
911 	int	minor = (int)getminor(dev);
912 	struct bofi_errdef errdef;
913 	struct bofi_errctl errctl;
914 	struct bofi_errstate errstate;
915 	void *ed_handle;
916 	struct bofi_get_handles get_handles;
917 	struct bofi_get_hdl_info hdl_info;
918 	struct handle_info *hdlip;
919 	struct handle_info *hib;
920 
921 	char *buffer;
922 	char *bufptr;
923 	char *endbuf;
924 	int req_count, count, err;
925 	char *namep;
926 	struct bofi_shadow *hp;
927 	int retval;
928 	struct bofi_shadow *hhashp;
929 	int i;
930 
931 	switch (cmd) {
932 	case BOFI_ADD_DEF:
933 		/*
934 		 * add a new error definition
935 		 */
936 #ifdef _MULTI_DATAMODEL
937 		switch (ddi_model_convert_from(mode & FMODELS)) {
938 		case DDI_MODEL_ILP32:
939 		{
940 			/*
941 			 * For use when a 32 bit app makes a call into a
942 			 * 64 bit ioctl
943 			 */
944 			struct bofi_errdef32	errdef_32;
945 
946 			if (ddi_copyin((void *)arg, &errdef_32,
947 			    sizeof (struct bofi_errdef32), mode)) {
948 				return (EFAULT);
949 			}
950 			errdef.namesize = errdef_32.namesize;
951 			(void) strncpy(errdef.name, errdef_32.name, NAMESIZE);
952 			errdef.instance = errdef_32.instance;
953 			errdef.rnumber = errdef_32.rnumber;
954 			errdef.offset = errdef_32.offset;
955 			errdef.len = errdef_32.len;
956 			errdef.access_type = errdef_32.access_type;
957 			errdef.access_count = errdef_32.access_count;
958 			errdef.fail_count = errdef_32.fail_count;
959 			errdef.acc_chk = errdef_32.acc_chk;
960 			errdef.optype = errdef_32.optype;
961 			errdef.operand = errdef_32.operand;
962 			errdef.log.logsize = errdef_32.log.logsize;
963 			errdef.log.entries = errdef_32.log.entries;
964 			errdef.log.flags = errdef_32.log.flags;
965 			errdef.log.wrapcnt = errdef_32.log.wrapcnt;
966 			errdef.log.start_time = errdef_32.log.start_time;
967 			errdef.log.stop_time = errdef_32.log.stop_time;
968 			errdef.log.logbase =
969 			    (caddr_t)(uintptr_t)errdef_32.log.logbase;
970 			errdef.errdef_handle = errdef_32.errdef_handle;
971 			break;
972 		}
973 		case DDI_MODEL_NONE:
974 			if (ddi_copyin((void *)arg, &errdef,
975 			    sizeof (struct bofi_errdef), mode))
976 				return (EFAULT);
977 			break;
978 		}
979 #else /* ! _MULTI_DATAMODEL */
980 		if (ddi_copyin((void *)arg, &errdef,
981 		    sizeof (struct bofi_errdef), mode) != 0)
982 			return (EFAULT);
983 #endif /* _MULTI_DATAMODEL */
984 		/*
985 		 * do some validation
986 		 */
987 		if (errdef.fail_count == 0)
988 			errdef.optype = 0;
989 		if (errdef.optype != 0) {
990 			if (errdef.access_type & BOFI_INTR &&
991 			    errdef.optype != BOFI_DELAY_INTR &&
992 			    errdef.optype != BOFI_LOSE_INTR &&
993 			    errdef.optype != BOFI_EXTRA_INTR)
994 				return (EINVAL);
995 			if ((errdef.access_type & (BOFI_DMA_RW|BOFI_PIO_R)) &&
996 			    errdef.optype == BOFI_NO_TRANSFER)
997 				return (EINVAL);
998 			if ((errdef.access_type & (BOFI_PIO_RW)) &&
999 			    errdef.optype != BOFI_EQUAL &&
1000 			    errdef.optype != BOFI_OR &&
1001 			    errdef.optype != BOFI_XOR &&
1002 			    errdef.optype != BOFI_AND &&
1003 			    errdef.optype != BOFI_NO_TRANSFER)
1004 				return (EINVAL);
1005 		}
1006 		/*
1007 		 * find softstate for this clone, so we can tag
1008 		 * new errdef on to it
1009 		 */
1010 		softc = ddi_get_soft_state(statep, minor);
1011 		if (softc == NULL)
1012 			return (ENXIO);
1013 		/*
1014 		 * read in name
1015 		 */
1016 		if (errdef.namesize > NAMESIZE)
1017 			return (EINVAL);
1018 		namep = kmem_zalloc(errdef.namesize+1, KM_SLEEP);
1019 		(void) strncpy(namep, errdef.name, errdef.namesize);
1020 
1021 		if (bofi_errdef_alloc(&errdef, namep, softc) != DDI_SUCCESS) {
1022 			(void) bofi_errdef_free((struct bofi_errent *)
1023 			    (uintptr_t)errdef.errdef_handle);
1024 			kmem_free(namep, errdef.namesize+1);
1025 			return (EINVAL);
1026 		}
1027 		/*
1028 		 * copy out errdef again, including filled in errdef_handle
1029 		 */
1030 #ifdef _MULTI_DATAMODEL
1031 		switch (ddi_model_convert_from(mode & FMODELS)) {
1032 		case DDI_MODEL_ILP32:
1033 		{
1034 			/*
1035 			 * For use when a 32 bit app makes a call into a
1036 			 * 64 bit ioctl
1037 			 */
1038 			struct bofi_errdef32	errdef_32;
1039 
1040 			errdef_32.namesize = errdef.namesize;
1041 			(void) strncpy(errdef_32.name, errdef.name, NAMESIZE);
1042 			errdef_32.instance = errdef.instance;
1043 			errdef_32.rnumber = errdef.rnumber;
1044 			errdef_32.offset = errdef.offset;
1045 			errdef_32.len = errdef.len;
1046 			errdef_32.access_type = errdef.access_type;
1047 			errdef_32.access_count = errdef.access_count;
1048 			errdef_32.fail_count = errdef.fail_count;
1049 			errdef_32.acc_chk = errdef.acc_chk;
1050 			errdef_32.optype = errdef.optype;
1051 			errdef_32.operand = errdef.operand;
1052 			errdef_32.log.logsize = errdef.log.logsize;
1053 			errdef_32.log.entries = errdef.log.entries;
1054 			errdef_32.log.flags = errdef.log.flags;
1055 			errdef_32.log.wrapcnt = errdef.log.wrapcnt;
1056 			errdef_32.log.start_time = errdef.log.start_time;
1057 			errdef_32.log.stop_time = errdef.log.stop_time;
1058 			errdef_32.log.logbase =
1059 			    (caddr32_t)(uintptr_t)errdef.log.logbase;
1060 			errdef_32.errdef_handle = errdef.errdef_handle;
1061 			if (ddi_copyout(&errdef_32, (void *)arg,
1062 			    sizeof (struct bofi_errdef32), mode) != 0) {
1063 				(void) bofi_errdef_free((struct bofi_errent *)
1064 				    errdef.errdef_handle);
1065 				kmem_free(namep, errdef.namesize+1);
1066 				return (EFAULT);
1067 			}
1068 			break;
1069 		}
1070 		case DDI_MODEL_NONE:
1071 			if (ddi_copyout(&errdef, (void *)arg,
1072 			    sizeof (struct bofi_errdef), mode) != 0) {
1073 				(void) bofi_errdef_free((struct bofi_errent *)
1074 				    errdef.errdef_handle);
1075 				kmem_free(namep, errdef.namesize+1);
1076 				return (EFAULT);
1077 			}
1078 			break;
1079 		}
1080 #else /* ! _MULTI_DATAMODEL */
1081 		if (ddi_copyout(&errdef, (void *)arg,
1082 		    sizeof (struct bofi_errdef), mode) != 0) {
1083 			(void) bofi_errdef_free((struct bofi_errent *)
1084 			    (uintptr_t)errdef.errdef_handle);
1085 			kmem_free(namep, errdef.namesize+1);
1086 			return (EFAULT);
1087 		}
1088 #endif /* _MULTI_DATAMODEL */
1089 		return (0);
1090 	case BOFI_DEL_DEF:
1091 		/*
1092 		 * delete existing errdef
1093 		 */
1094 		if (ddi_copyin((void *)arg, &ed_handle,
1095 		    sizeof (void *), mode) != 0)
1096 			return (EFAULT);
1097 		return (bofi_errdef_free((struct bofi_errent *)ed_handle));
1098 	case BOFI_START:
1099 		/*
1100 		 * start all errdefs corresponding to
1101 		 * this name and instance
1102 		 */
1103 		if (ddi_copyin((void *)arg, &errctl,
1104 		    sizeof (struct bofi_errctl), mode) != 0)
1105 			return (EFAULT);
1106 		/*
1107 		 * copy in name
1108 		 */
1109 		if (errctl.namesize > NAMESIZE)
1110 			return (EINVAL);
1111 		namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1112 		(void) strncpy(namep, errctl.name, errctl.namesize);
1113 		bofi_start(&errctl, namep);
1114 		kmem_free(namep, errctl.namesize+1);
1115 		return (0);
1116 	case BOFI_STOP:
1117 		/*
1118 		 * stop all errdefs corresponding to
1119 		 * this name and instance
1120 		 */
1121 		if (ddi_copyin((void *)arg, &errctl,
1122 		    sizeof (struct bofi_errctl), mode) != 0)
1123 			return (EFAULT);
1124 		/*
1125 		 * copy in name
1126 		 */
1127 		if (errctl.namesize > NAMESIZE)
1128 			return (EINVAL);
1129 		namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1130 		(void) strncpy(namep, errctl.name, errctl.namesize);
1131 		bofi_stop(&errctl, namep);
1132 		kmem_free(namep, errctl.namesize+1);
1133 		return (0);
1134 	case BOFI_BROADCAST:
1135 		/*
1136 		 * wakeup all errdefs corresponding to
1137 		 * this name and instance
1138 		 */
1139 		if (ddi_copyin((void *)arg, &errctl,
1140 		    sizeof (struct bofi_errctl), mode) != 0)
1141 			return (EFAULT);
1142 		/*
1143 		 * copy in name
1144 		 */
1145 		if (errctl.namesize > NAMESIZE)
1146 			return (EINVAL);
1147 		namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1148 		(void) strncpy(namep, errctl.name, errctl.namesize);
1149 		bofi_broadcast(&errctl, namep);
1150 		kmem_free(namep, errctl.namesize+1);
1151 		return (0);
1152 	case BOFI_CLEAR_ACC_CHK:
1153 		/*
1154 		 * clear "acc_chk" for all errdefs corresponding to
1155 		 * this name and instance
1156 		 */
1157 		if (ddi_copyin((void *)arg, &errctl,
1158 		    sizeof (struct bofi_errctl), mode) != 0)
1159 			return (EFAULT);
1160 		/*
1161 		 * copy in name
1162 		 */
1163 		if (errctl.namesize > NAMESIZE)
1164 			return (EINVAL);
1165 		namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1166 		(void) strncpy(namep, errctl.name, errctl.namesize);
1167 		bofi_clear_acc_chk(&errctl, namep);
1168 		kmem_free(namep, errctl.namesize+1);
1169 		return (0);
1170 	case BOFI_CLEAR_ERRORS:
1171 		/*
1172 		 * set "fail_count" to 0 for all errdefs corresponding to
1173 		 * this name and instance whose "access_count"
1174 		 * has expired.
1175 		 */
1176 		if (ddi_copyin((void *)arg, &errctl,
1177 		    sizeof (struct bofi_errctl), mode) != 0)
1178 			return (EFAULT);
1179 		/*
1180 		 * copy in name
1181 		 */
1182 		if (errctl.namesize > NAMESIZE)
1183 			return (EINVAL);
1184 		namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1185 		(void) strncpy(namep, errctl.name, errctl.namesize);
1186 		bofi_clear_errors(&errctl, namep);
1187 		kmem_free(namep, errctl.namesize+1);
1188 		return (0);
1189 	case BOFI_CLEAR_ERRDEFS:
1190 		/*
1191 		 * set "access_count" and "fail_count" to 0 for all errdefs
1192 		 * corresponding to this name and instance
1193 		 */
1194 		if (ddi_copyin((void *)arg, &errctl,
1195 		    sizeof (struct bofi_errctl), mode) != 0)
1196 			return (EFAULT);
1197 		/*
1198 		 * copy in name
1199 		 */
1200 		if (errctl.namesize > NAMESIZE)
1201 			return (EINVAL);
1202 		namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1203 		(void) strncpy(namep, errctl.name, errctl.namesize);
1204 		bofi_clear_errdefs(&errctl, namep);
1205 		kmem_free(namep, errctl.namesize+1);
1206 		return (0);
1207 	case BOFI_CHK_STATE:
1208 	{
1209 		struct acc_log_elem *klg;
1210 		size_t uls;
1211 		/*
1212 		 * get state for this errdef - read in dummy errstate
1213 		 * with just the errdef_handle filled in
1214 		 */
1215 #ifdef _MULTI_DATAMODEL
1216 		switch (ddi_model_convert_from(mode & FMODELS)) {
1217 		case DDI_MODEL_ILP32:
1218 		{
1219 			/*
1220 			 * For use when a 32 bit app makes a call into a
1221 			 * 64 bit ioctl
1222 			 */
1223 			struct bofi_errstate32	errstate_32;
1224 
1225 			if (ddi_copyin((void *)arg, &errstate_32,
1226 			    sizeof (struct bofi_errstate32), mode) != 0) {
1227 				return (EFAULT);
1228 			}
1229 			errstate.fail_time = errstate_32.fail_time;
1230 			errstate.msg_time = errstate_32.msg_time;
1231 			errstate.access_count = errstate_32.access_count;
1232 			errstate.fail_count = errstate_32.fail_count;
1233 			errstate.acc_chk = errstate_32.acc_chk;
1234 			errstate.errmsg_count = errstate_32.errmsg_count;
1235 			(void) strncpy(errstate.buffer, errstate_32.buffer,
1236 			    ERRMSGSIZE);
1237 			errstate.severity = errstate_32.severity;
1238 			errstate.log.logsize = errstate_32.log.logsize;
1239 			errstate.log.entries = errstate_32.log.entries;
1240 			errstate.log.flags = errstate_32.log.flags;
1241 			errstate.log.wrapcnt = errstate_32.log.wrapcnt;
1242 			errstate.log.start_time = errstate_32.log.start_time;
1243 			errstate.log.stop_time = errstate_32.log.stop_time;
1244 			errstate.log.logbase =
1245 			    (caddr_t)(uintptr_t)errstate_32.log.logbase;
1246 			errstate.errdef_handle = errstate_32.errdef_handle;
1247 			break;
1248 		}
1249 		case DDI_MODEL_NONE:
1250 			if (ddi_copyin((void *)arg, &errstate,
1251 			    sizeof (struct bofi_errstate), mode) != 0)
1252 				return (EFAULT);
1253 			break;
1254 		}
1255 #else /* ! _MULTI_DATAMODEL */
1256 		if (ddi_copyin((void *)arg, &errstate,
1257 		    sizeof (struct bofi_errstate), mode) != 0)
1258 			return (EFAULT);
1259 #endif /* _MULTI_DATAMODEL */
1260 		if ((retval = bofi_errdef_check(&errstate, &klg)) == EINVAL)
1261 			return (EINVAL);
1262 		/*
1263 		 * copy out real errstate structure
1264 		 */
1265 		uls = errstate.log.logsize;
1266 		if (errstate.log.entries > uls && uls)
1267 			/* insufficient user memory */
1268 			errstate.log.entries = uls;
1269 		/* always pass back a time */
1270 		if (errstate.log.stop_time == 0ul)
1271 			(void) drv_getparm(TIME, &(errstate.log.stop_time));
1272 
1273 #ifdef _MULTI_DATAMODEL
1274 		switch (ddi_model_convert_from(mode & FMODELS)) {
1275 		case DDI_MODEL_ILP32:
1276 		{
1277 			/*
1278 			 * For use when a 32 bit app makes a call into a
1279 			 * 64 bit ioctl
1280 			 */
1281 			struct bofi_errstate32	errstate_32;
1282 
1283 			errstate_32.fail_time = errstate.fail_time;
1284 			errstate_32.msg_time = errstate.msg_time;
1285 			errstate_32.access_count = errstate.access_count;
1286 			errstate_32.fail_count = errstate.fail_count;
1287 			errstate_32.acc_chk = errstate.acc_chk;
1288 			errstate_32.errmsg_count = errstate.errmsg_count;
1289 			(void) strncpy(errstate_32.buffer, errstate.buffer,
1290 			    ERRMSGSIZE);
1291 			errstate_32.severity = errstate.severity;
1292 			errstate_32.log.logsize = errstate.log.logsize;
1293 			errstate_32.log.entries = errstate.log.entries;
1294 			errstate_32.log.flags = errstate.log.flags;
1295 			errstate_32.log.wrapcnt = errstate.log.wrapcnt;
1296 			errstate_32.log.start_time = errstate.log.start_time;
1297 			errstate_32.log.stop_time = errstate.log.stop_time;
1298 			errstate_32.log.logbase =
1299 			    (caddr32_t)(uintptr_t)errstate.log.logbase;
1300 			errstate_32.errdef_handle = errstate.errdef_handle;
1301 			if (ddi_copyout(&errstate_32, (void *)arg,
1302 			    sizeof (struct bofi_errstate32), mode) != 0)
1303 				return (EFAULT);
1304 			break;
1305 		}
1306 		case DDI_MODEL_NONE:
1307 			if (ddi_copyout(&errstate, (void *)arg,
1308 			    sizeof (struct bofi_errstate), mode) != 0)
1309 				return (EFAULT);
1310 			break;
1311 		}
1312 #else /* ! _MULTI_DATAMODEL */
1313 		if (ddi_copyout(&errstate, (void *)arg,
1314 		    sizeof (struct bofi_errstate), mode) != 0)
1315 			return (EFAULT);
1316 #endif /* _MULTI_DATAMODEL */
1317 		if (uls && errstate.log.entries &&
1318 		    ddi_copyout(klg, errstate.log.logbase,
1319 		    errstate.log.entries * sizeof (struct acc_log_elem),
1320 		    mode) != 0) {
1321 			return (EFAULT);
1322 		}
1323 		return (retval);
1324 	}
1325 	case BOFI_CHK_STATE_W:
1326 	{
1327 		struct acc_log_elem *klg;
1328 		size_t uls;
1329 		/*
1330 		 * get state for this errdef - read in dummy errstate
1331 		 * with just the errdef_handle filled in. Then wait for
1332 		 * a ddi_report_fault message to come back
1333 		 */
1334 #ifdef _MULTI_DATAMODEL
1335 		switch (ddi_model_convert_from(mode & FMODELS)) {
1336 		case DDI_MODEL_ILP32:
1337 		{
1338 			/*
1339 			 * For use when a 32 bit app makes a call into a
1340 			 * 64 bit ioctl
1341 			 */
1342 			struct bofi_errstate32	errstate_32;
1343 
1344 			if (ddi_copyin((void *)arg, &errstate_32,
1345 			    sizeof (struct bofi_errstate32), mode) != 0) {
1346 				return (EFAULT);
1347 			}
1348 			errstate.fail_time = errstate_32.fail_time;
1349 			errstate.msg_time = errstate_32.msg_time;
1350 			errstate.access_count = errstate_32.access_count;
1351 			errstate.fail_count = errstate_32.fail_count;
1352 			errstate.acc_chk = errstate_32.acc_chk;
1353 			errstate.errmsg_count = errstate_32.errmsg_count;
1354 			(void) strncpy(errstate.buffer, errstate_32.buffer,
1355 			    ERRMSGSIZE);
1356 			errstate.severity = errstate_32.severity;
1357 			errstate.log.logsize = errstate_32.log.logsize;
1358 			errstate.log.entries = errstate_32.log.entries;
1359 			errstate.log.flags = errstate_32.log.flags;
1360 			errstate.log.wrapcnt = errstate_32.log.wrapcnt;
1361 			errstate.log.start_time = errstate_32.log.start_time;
1362 			errstate.log.stop_time = errstate_32.log.stop_time;
1363 			errstate.log.logbase =
1364 			    (caddr_t)(uintptr_t)errstate_32.log.logbase;
1365 			errstate.errdef_handle = errstate_32.errdef_handle;
1366 			break;
1367 		}
1368 		case DDI_MODEL_NONE:
1369 			if (ddi_copyin((void *)arg, &errstate,
1370 			    sizeof (struct bofi_errstate), mode) != 0)
1371 				return (EFAULT);
1372 			break;
1373 		}
1374 #else /* ! _MULTI_DATAMODEL */
1375 		if (ddi_copyin((void *)arg, &errstate,
1376 		    sizeof (struct bofi_errstate), mode) != 0)
1377 			return (EFAULT);
1378 #endif /* _MULTI_DATAMODEL */
1379 		if ((retval = bofi_errdef_check_w(&errstate, &klg)) == EINVAL)
1380 			return (EINVAL);
1381 		/*
1382 		 * copy out real errstate structure
1383 		 */
1384 		uls = errstate.log.logsize;
1385 		uls = errstate.log.logsize;
1386 		if (errstate.log.entries > uls && uls)
1387 			/* insufficient user memory */
1388 			errstate.log.entries = uls;
1389 		/* always pass back a time */
1390 		if (errstate.log.stop_time == 0ul)
1391 			(void) drv_getparm(TIME, &(errstate.log.stop_time));
1392 
1393 #ifdef _MULTI_DATAMODEL
1394 		switch (ddi_model_convert_from(mode & FMODELS)) {
1395 		case DDI_MODEL_ILP32:
1396 		{
1397 			/*
1398 			 * For use when a 32 bit app makes a call into a
1399 			 * 64 bit ioctl
1400 			 */
1401 			struct bofi_errstate32	errstate_32;
1402 
1403 			errstate_32.fail_time = errstate.fail_time;
1404 			errstate_32.msg_time = errstate.msg_time;
1405 			errstate_32.access_count = errstate.access_count;
1406 			errstate_32.fail_count = errstate.fail_count;
1407 			errstate_32.acc_chk = errstate.acc_chk;
1408 			errstate_32.errmsg_count = errstate.errmsg_count;
1409 			(void) strncpy(errstate_32.buffer, errstate.buffer,
1410 			    ERRMSGSIZE);
1411 			errstate_32.severity = errstate.severity;
1412 			errstate_32.log.logsize = errstate.log.logsize;
1413 			errstate_32.log.entries = errstate.log.entries;
1414 			errstate_32.log.flags = errstate.log.flags;
1415 			errstate_32.log.wrapcnt = errstate.log.wrapcnt;
1416 			errstate_32.log.start_time = errstate.log.start_time;
1417 			errstate_32.log.stop_time = errstate.log.stop_time;
1418 			errstate_32.log.logbase =
1419 			    (caddr32_t)(uintptr_t)errstate.log.logbase;
1420 			errstate_32.errdef_handle = errstate.errdef_handle;
1421 			if (ddi_copyout(&errstate_32, (void *)arg,
1422 			    sizeof (struct bofi_errstate32), mode) != 0)
1423 				return (EFAULT);
1424 			break;
1425 		}
1426 		case DDI_MODEL_NONE:
1427 			if (ddi_copyout(&errstate, (void *)arg,
1428 			    sizeof (struct bofi_errstate), mode) != 0)
1429 				return (EFAULT);
1430 			break;
1431 		}
1432 #else /* ! _MULTI_DATAMODEL */
1433 		if (ddi_copyout(&errstate, (void *)arg,
1434 		    sizeof (struct bofi_errstate), mode) != 0)
1435 			return (EFAULT);
1436 #endif /* _MULTI_DATAMODEL */
1437 
1438 		if (uls && errstate.log.entries &&
1439 		    ddi_copyout(klg, errstate.log.logbase,
1440 		    errstate.log.entries * sizeof (struct acc_log_elem),
1441 		    mode) != 0) {
1442 			return (EFAULT);
1443 		}
1444 		return (retval);
1445 	}
1446 	case BOFI_GET_HANDLES:
1447 		/*
1448 		 * display existing handles
1449 		 */
1450 #ifdef _MULTI_DATAMODEL
1451 		switch (ddi_model_convert_from(mode & FMODELS)) {
1452 		case DDI_MODEL_ILP32:
1453 		{
1454 			/*
1455 			 * For use when a 32 bit app makes a call into a
1456 			 * 64 bit ioctl
1457 			 */
1458 			struct bofi_get_handles32	get_handles_32;
1459 
1460 			if (ddi_copyin((void *)arg, &get_handles_32,
1461 			    sizeof (get_handles_32), mode) != 0) {
1462 				return (EFAULT);
1463 			}
1464 			get_handles.namesize = get_handles_32.namesize;
1465 			(void) strncpy(get_handles.name, get_handles_32.name,
1466 			    NAMESIZE);
1467 			get_handles.instance = get_handles_32.instance;
1468 			get_handles.count = get_handles_32.count;
1469 			get_handles.buffer =
1470 			    (caddr_t)(uintptr_t)get_handles_32.buffer;
1471 			break;
1472 		}
1473 		case DDI_MODEL_NONE:
1474 			if (ddi_copyin((void *)arg, &get_handles,
1475 			    sizeof (get_handles), mode) != 0)
1476 				return (EFAULT);
1477 			break;
1478 		}
1479 #else /* ! _MULTI_DATAMODEL */
1480 		if (ddi_copyin((void *)arg, &get_handles,
1481 		    sizeof (get_handles), mode) != 0)
1482 			return (EFAULT);
1483 #endif /* _MULTI_DATAMODEL */
1484 		/*
1485 		 * read in name
1486 		 */
1487 		if (get_handles.namesize > NAMESIZE)
1488 			return (EINVAL);
1489 		namep = kmem_zalloc(get_handles.namesize+1, KM_SLEEP);
1490 		(void) strncpy(namep, get_handles.name, get_handles.namesize);
1491 		req_count = get_handles.count;
1492 		bufptr = buffer = kmem_zalloc(req_count, KM_SLEEP);
1493 		endbuf = bufptr + req_count;
1494 		/*
1495 		 * display existing handles
1496 		 */
1497 		mutex_enter(&bofi_low_mutex);
1498 		mutex_enter(&bofi_mutex);
1499 		for (i = 0; i < HDL_HASH_TBL_SIZE; i++) {
1500 			hhashp = &hhash_table[i];
1501 			for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) {
1502 				if (!driver_under_test(hp->dip))
1503 					continue;
1504 				if (ddi_name_to_major(ddi_get_name(hp->dip)) !=
1505 				    ddi_name_to_major(namep))
1506 					continue;
1507 				if (hp->instance != get_handles.instance)
1508 					continue;
1509 				/*
1510 				 * print information per handle - note that
1511 				 * DMA* means an unbound DMA handle
1512 				 */
1513 				(void) snprintf(bufptr, (size_t)(endbuf-bufptr),
1514 				    "  %s %d %s ", hp->name, hp->instance,
1515 				    (hp->type == BOFI_INT_HDL) ? "INTR" :
1516 				    (hp->type == BOFI_ACC_HDL) ? "PIO" :
1517 				    (hp->type == BOFI_DMA_HDL) ? "DMA" :
1518 				    (hp->hparrayp != NULL) ? "DVMA" : "DMA*");
1519 				bufptr += strlen(bufptr);
1520 				if (hp->type == BOFI_ACC_HDL) {
1521 					if (hp->len == INT_MAX - hp->offset)
1522 						(void) snprintf(bufptr,
1523 						    (size_t)(endbuf-bufptr),
1524 						    "reg set %d off 0x%llx\n",
1525 						    hp->rnumber, hp->offset);
1526 					else
1527 						(void) snprintf(bufptr,
1528 						    (size_t)(endbuf-bufptr),
1529 						    "reg set %d off 0x%llx"
1530 						    " len 0x%llx\n",
1531 						    hp->rnumber, hp->offset,
1532 						    hp->len);
1533 				} else if (hp->type == BOFI_DMA_HDL)
1534 					(void) snprintf(bufptr,
1535 					    (size_t)(endbuf-bufptr),
1536 					    "handle no %d len 0x%llx"
1537 					    " addr 0x%p\n", hp->rnumber,
1538 					    hp->len, (void *)hp->addr);
1539 				else if (hp->type == BOFI_NULL &&
1540 				    hp->hparrayp == NULL)
1541 					(void) snprintf(bufptr,
1542 					    (size_t)(endbuf-bufptr),
1543 					    "handle no %d\n", hp->rnumber);
1544 				else
1545 					(void) snprintf(bufptr,
1546 					    (size_t)(endbuf-bufptr), "\n");
1547 				bufptr += strlen(bufptr);
1548 			}
1549 		}
1550 		mutex_exit(&bofi_mutex);
1551 		mutex_exit(&bofi_low_mutex);
1552 		err = ddi_copyout(buffer, get_handles.buffer, req_count, mode);
1553 		kmem_free(namep, get_handles.namesize+1);
1554 		kmem_free(buffer, req_count);
1555 		if (err != 0)
1556 			return (EFAULT);
1557 		else
1558 			return (0);
1559 	case BOFI_GET_HANDLE_INFO:
1560 		/*
1561 		 * display existing handles
1562 		 */
1563 #ifdef _MULTI_DATAMODEL
1564 		switch (ddi_model_convert_from(mode & FMODELS)) {
1565 		case DDI_MODEL_ILP32:
1566 		{
1567 			/*
1568 			 * For use when a 32 bit app makes a call into a
1569 			 * 64 bit ioctl
1570 			 */
1571 			struct bofi_get_hdl_info32	hdl_info_32;
1572 
1573 			if (ddi_copyin((void *)arg, &hdl_info_32,
1574 			    sizeof (hdl_info_32), mode)) {
1575 				return (EFAULT);
1576 			}
1577 			hdl_info.namesize = hdl_info_32.namesize;
1578 			(void) strncpy(hdl_info.name, hdl_info_32.name,
1579 			    NAMESIZE);
1580 			hdl_info.count = hdl_info_32.count;
1581 			hdl_info.hdli = (caddr_t)(uintptr_t)hdl_info_32.hdli;
1582 			break;
1583 		}
1584 		case DDI_MODEL_NONE:
1585 			if (ddi_copyin((void *)arg, &hdl_info,
1586 			    sizeof (hdl_info), mode))
1587 				return (EFAULT);
1588 			break;
1589 		}
1590 #else /* ! _MULTI_DATAMODEL */
1591 		if (ddi_copyin((void *)arg, &hdl_info,
1592 		    sizeof (hdl_info), mode))
1593 			return (EFAULT);
1594 #endif /* _MULTI_DATAMODEL */
1595 		if (hdl_info.namesize > NAMESIZE)
1596 			return (EINVAL);
1597 		namep = kmem_zalloc(hdl_info.namesize + 1, KM_SLEEP);
1598 		(void) strncpy(namep, hdl_info.name, hdl_info.namesize);
1599 		req_count = hdl_info.count;
1600 		count = hdl_info.count = 0; /* the actual no of handles */
1601 		if (req_count > 0) {
1602 			hib = hdlip =
1603 			    kmem_zalloc(req_count * sizeof (struct handle_info),
1604 			    KM_SLEEP);
1605 		} else {
1606 			hib = hdlip = 0;
1607 			req_count = hdl_info.count = 0;
1608 		}
1609 
1610 		/*
1611 		 * display existing handles
1612 		 */
1613 		mutex_enter(&bofi_low_mutex);
1614 		mutex_enter(&bofi_mutex);
1615 		for (i = 0; i < HDL_HASH_TBL_SIZE; i++) {
1616 			hhashp = &hhash_table[i];
1617 			for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) {
1618 				if (!driver_under_test(hp->dip) ||
1619 				    ddi_name_to_major(ddi_get_name(hp->dip)) !=
1620 				    ddi_name_to_major(namep) ||
1621 				    ++(hdl_info.count) > req_count ||
1622 				    count == req_count)
1623 					continue;
1624 
1625 				hdlip->instance = hp->instance;
1626 				hdlip->rnumber = hp->rnumber;
1627 				switch (hp->type) {
1628 				case BOFI_ACC_HDL:
1629 					hdlip->access_type = BOFI_PIO_RW;
1630 					hdlip->offset = hp->offset;
1631 					hdlip->len = hp->len;
1632 					break;
1633 				case BOFI_DMA_HDL:
1634 					hdlip->access_type = 0;
1635 					if (hp->flags & DDI_DMA_WRITE)
1636 						hdlip->access_type |=
1637 						    BOFI_DMA_W;
1638 					if (hp->flags & DDI_DMA_READ)
1639 						hdlip->access_type |=
1640 						    BOFI_DMA_R;
1641 					hdlip->len = hp->len;
1642 					hdlip->addr_cookie =
1643 					    (uint64_t)(uintptr_t)hp->addr;
1644 					break;
1645 				case BOFI_INT_HDL:
1646 					hdlip->access_type = BOFI_INTR;
1647 					break;
1648 				default:
1649 					hdlip->access_type = 0;
1650 					break;
1651 				}
1652 				hdlip++;
1653 				count++;
1654 			}
1655 		}
1656 		mutex_exit(&bofi_mutex);
1657 		mutex_exit(&bofi_low_mutex);
1658 		err = 0;
1659 #ifdef _MULTI_DATAMODEL
1660 		switch (ddi_model_convert_from(mode & FMODELS)) {
1661 		case DDI_MODEL_ILP32:
1662 		{
1663 			/*
1664 			 * For use when a 32 bit app makes a call into a
1665 			 * 64 bit ioctl
1666 			 */
1667 			struct bofi_get_hdl_info32	hdl_info_32;
1668 
1669 			hdl_info_32.namesize = hdl_info.namesize;
1670 			(void) strncpy(hdl_info_32.name, hdl_info.name,
1671 			    NAMESIZE);
1672 			hdl_info_32.count = hdl_info.count;
1673 			hdl_info_32.hdli = (caddr32_t)(uintptr_t)hdl_info.hdli;
1674 			if (ddi_copyout(&hdl_info_32, (void *)arg,
1675 			    sizeof (hdl_info_32), mode) != 0) {
1676 				kmem_free(namep, hdl_info.namesize+1);
1677 				if (req_count > 0)
1678 					kmem_free(hib,
1679 					    req_count * sizeof (*hib));
1680 				return (EFAULT);
1681 			}
1682 			break;
1683 		}
1684 		case DDI_MODEL_NONE:
1685 			if (ddi_copyout(&hdl_info, (void *)arg,
1686 			    sizeof (hdl_info), mode) != 0) {
1687 				kmem_free(namep, hdl_info.namesize+1);
1688 				if (req_count > 0)
1689 					kmem_free(hib,
1690 					    req_count * sizeof (*hib));
1691 				return (EFAULT);
1692 			}
1693 			break;
1694 		}
1695 #else /* ! _MULTI_DATAMODEL */
1696 		if (ddi_copyout(&hdl_info, (void *)arg,
1697 		    sizeof (hdl_info), mode) != 0) {
1698 			kmem_free(namep, hdl_info.namesize+1);
1699 			if (req_count > 0)
1700 				kmem_free(hib, req_count * sizeof (*hib));
1701 			return (EFAULT);
1702 		}
1703 #endif /* ! _MULTI_DATAMODEL */
1704 		if (count > 0) {
1705 			if (ddi_copyout(hib, hdl_info.hdli,
1706 			    count * sizeof (*hib), mode) != 0) {
1707 				kmem_free(namep, hdl_info.namesize+1);
1708 				if (req_count > 0)
1709 					kmem_free(hib,
1710 					    req_count * sizeof (*hib));
1711 				return (EFAULT);
1712 			}
1713 		}
1714 		kmem_free(namep, hdl_info.namesize+1);
1715 		if (req_count > 0)
1716 			kmem_free(hib, req_count * sizeof (*hib));
1717 		return (err);
1718 	default:
1719 		return (ENOTTY);
1720 	}
1721 }
1722 
1723 
1724 /*
1725  * add a new error definition
1726  */
1727 static int
1728 bofi_errdef_alloc(struct bofi_errdef *errdefp, char *namep,
1729 	struct bofi_errent *softc)
1730 {
1731 	struct bofi_errent *ep;
1732 	struct bofi_shadow *hp;
1733 	struct bofi_link   *lp;
1734 
1735 	/*
1736 	 * allocate errdef structure and put on in-use list
1737 	 */
1738 	ep = kmem_zalloc(sizeof (struct bofi_errent), KM_SLEEP);
1739 	ep->errdef = *errdefp;
1740 	ep->name = namep;
1741 	ep->errdef.errdef_handle = (uint64_t)(uintptr_t)ep;
1742 	ep->errstate.severity = DDI_SERVICE_RESTORED;
1743 	ep->errstate.errdef_handle = (uint64_t)(uintptr_t)ep;
1744 	cv_init(&ep->cv, NULL, CV_DRIVER, NULL);
1745 	/*
1746 	 * allocate space for logging
1747 	 */
1748 	ep->errdef.log.entries = 0;
1749 	ep->errdef.log.wrapcnt = 0;
1750 	if (ep->errdef.access_type & BOFI_LOG)
1751 		ep->logbase = kmem_alloc(sizeof (struct acc_log_elem) *
1752 		    ep->errdef.log.logsize, KM_SLEEP);
1753 	else
1754 		ep->logbase = NULL;
1755 	/*
1756 	 * put on in-use list
1757 	 */
1758 	mutex_enter(&bofi_low_mutex);
1759 	mutex_enter(&bofi_mutex);
1760 	ep->next = errent_listp;
1761 	errent_listp = ep;
1762 	/*
1763 	 * and add it to the per-clone list
1764 	 */
1765 	ep->cnext = softc->cnext;
1766 	softc->cnext->cprev = ep;
1767 	ep->cprev = softc;
1768 	softc->cnext = ep;
1769 
1770 	/*
1771 	 * look for corresponding shadow handle structures and if we find any
1772 	 * tag this errdef structure on to their link lists.
1773 	 */
1774 	for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) {
1775 		if (ddi_name_to_major(hp->name) == ddi_name_to_major(namep) &&
1776 		    hp->instance == errdefp->instance &&
1777 		    (((errdefp->access_type & BOFI_DMA_RW) &&
1778 		    (ep->errdef.rnumber == -1 ||
1779 		    hp->rnumber == ep->errdef.rnumber) &&
1780 		    hp->type == BOFI_DMA_HDL &&
1781 		    (((uintptr_t)(hp->addr + ep->errdef.offset +
1782 		    ep->errdef.len) & ~LLSZMASK) >
1783 		    ((uintptr_t)((hp->addr + ep->errdef.offset) +
1784 		    LLSZMASK) & ~LLSZMASK))) ||
1785 		    ((errdefp->access_type & BOFI_INTR) &&
1786 		    hp->type == BOFI_INT_HDL) ||
1787 		    ((errdefp->access_type & BOFI_PIO_RW) &&
1788 		    hp->type == BOFI_ACC_HDL &&
1789 		    (errdefp->rnumber == -1 ||
1790 		    hp->rnumber == errdefp->rnumber) &&
1791 		    (errdefp->len == 0 ||
1792 		    hp->offset < errdefp->offset + errdefp->len) &&
1793 		    hp->offset + hp->len > errdefp->offset))) {
1794 			lp = bofi_link_freelist;
1795 			if (lp != NULL) {
1796 				bofi_link_freelist = lp->link;
1797 				lp->errentp = ep;
1798 				lp->link = hp->link;
1799 				hp->link = lp;
1800 			}
1801 		}
1802 	}
1803 	errdefp->errdef_handle = (uint64_t)(uintptr_t)ep;
1804 	mutex_exit(&bofi_mutex);
1805 	mutex_exit(&bofi_low_mutex);
1806 	ep->softintr_id = NULL;
1807 	return (ddi_add_softintr(our_dip, DDI_SOFTINT_MED, &ep->softintr_id,
1808 	    NULL, NULL, bofi_signal, (caddr_t)&ep->errdef));
1809 }
1810 
1811 
1812 /*
1813  * delete existing errdef
1814  */
1815 static int
1816 bofi_errdef_free(struct bofi_errent *ep)
1817 {
1818 	struct bofi_errent *hep, *prev_hep;
1819 	struct bofi_link *lp, *prev_lp, *next_lp;
1820 	struct bofi_shadow *hp;
1821 
1822 	mutex_enter(&bofi_low_mutex);
1823 	mutex_enter(&bofi_mutex);
1824 	/*
1825 	 * don't just assume its a valid ep - check that its on the
1826 	 * in-use list
1827 	 */
1828 	prev_hep = NULL;
1829 	for (hep = errent_listp; hep != NULL; ) {
1830 		if (hep == ep)
1831 			break;
1832 		prev_hep = hep;
1833 		hep = hep->next;
1834 	}
1835 	if (hep == NULL) {
1836 		mutex_exit(&bofi_mutex);
1837 		mutex_exit(&bofi_low_mutex);
1838 		return (EINVAL);
1839 	}
1840 	/*
1841 	 * found it - delete from in-use list
1842 	 */
1843 
1844 	if (prev_hep)
1845 		prev_hep->next = hep->next;
1846 	else
1847 		errent_listp = hep->next;
1848 	/*
1849 	 * and take it off the per-clone list
1850 	 */
1851 	hep->cnext->cprev = hep->cprev;
1852 	hep->cprev->cnext = hep->cnext;
1853 	/*
1854 	 * see if we are on any shadow handle link lists - and if we
1855 	 * are then take us off
1856 	 */
1857 	for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) {
1858 		prev_lp = NULL;
1859 		for (lp = hp->link; lp != NULL; ) {
1860 			if (lp->errentp == ep) {
1861 				if (prev_lp)
1862 					prev_lp->link = lp->link;
1863 				else
1864 					hp->link = lp->link;
1865 				next_lp = lp->link;
1866 				lp->link = bofi_link_freelist;
1867 				bofi_link_freelist = lp;
1868 				lp = next_lp;
1869 			} else {
1870 				prev_lp = lp;
1871 				lp = lp->link;
1872 			}
1873 		}
1874 	}
1875 	mutex_exit(&bofi_mutex);
1876 	mutex_exit(&bofi_low_mutex);
1877 
1878 	cv_destroy(&ep->cv);
1879 	kmem_free(ep->name, ep->errdef.namesize+1);
1880 	if ((ep->errdef.access_type & BOFI_LOG) &&
1881 		ep->errdef.log.logsize && ep->logbase) /* double check */
1882 		kmem_free(ep->logbase,
1883 		    sizeof (struct acc_log_elem) * ep->errdef.log.logsize);
1884 
1885 	if (ep->softintr_id)
1886 		ddi_remove_softintr(ep->softintr_id);
1887 	kmem_free(ep, sizeof (struct bofi_errent));
1888 	return (0);
1889 }
1890 
1891 
1892 /*
1893  * start all errdefs corresponding to this name and instance
1894  */
1895 static void
1896 bofi_start(struct bofi_errctl *errctlp, char *namep)
1897 {
1898 	struct bofi_errent *ep;
1899 
1900 	/*
1901 	 * look for any errdefs with matching name and instance
1902 	 */
1903 	mutex_enter(&bofi_low_mutex);
1904 	for (ep = errent_listp; ep != NULL; ep = ep->next)
1905 		if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
1906 		    errctlp->instance == ep->errdef.instance) {
1907 			ep->state |= BOFI_DEV_ACTIVE;
1908 			(void) drv_getparm(TIME, &(ep->errdef.log.start_time));
1909 			ep->errdef.log.stop_time = 0ul;
1910 		}
1911 	mutex_exit(&bofi_low_mutex);
1912 }
1913 
1914 
1915 /*
1916  * stop all errdefs corresponding to this name and instance
1917  */
1918 static void
1919 bofi_stop(struct bofi_errctl *errctlp, char *namep)
1920 {
1921 	struct bofi_errent *ep;
1922 
1923 	/*
1924 	 * look for any errdefs with matching name and instance
1925 	 */
1926 	mutex_enter(&bofi_low_mutex);
1927 	for (ep = errent_listp; ep != NULL; ep = ep->next)
1928 		if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
1929 		    errctlp->instance == ep->errdef.instance) {
1930 			ep->state &= ~BOFI_DEV_ACTIVE;
1931 			if (ep->errdef.log.stop_time == 0ul)
1932 				(void) drv_getparm(TIME,
1933 				    &(ep->errdef.log.stop_time));
1934 		}
1935 	mutex_exit(&bofi_low_mutex);
1936 }
1937 
1938 
1939 /*
1940  * wake up any thread waiting on this errdefs
1941  */
1942 static uint_t
1943 bofi_signal(caddr_t arg)
1944 {
1945 	struct bofi_errdef *edp = (struct bofi_errdef *)arg;
1946 	struct bofi_errent *hep;
1947 	struct bofi_errent *ep =
1948 	    (struct bofi_errent *)(uintptr_t)edp->errdef_handle;
1949 
1950 	mutex_enter(&bofi_low_mutex);
1951 	for (hep = errent_listp; hep != NULL; ) {
1952 		if (hep == ep)
1953 			break;
1954 		hep = hep->next;
1955 	}
1956 	if (hep == NULL) {
1957 		mutex_exit(&bofi_low_mutex);
1958 		return (DDI_INTR_UNCLAIMED);
1959 	}
1960 	if ((ep->errdef.access_type & BOFI_LOG) &&
1961 	    (edp->log.flags & BOFI_LOG_FULL)) {
1962 		edp->log.stop_time = bofi_gettime();
1963 		ep->state |= BOFI_NEW_MESSAGE;
1964 		if (ep->state & BOFI_MESSAGE_WAIT)
1965 			cv_broadcast(&ep->cv);
1966 		ep->state &= ~BOFI_MESSAGE_WAIT;
1967 	}
1968 	if (ep->errstate.msg_time != 0) {
1969 		ep->state |= BOFI_NEW_MESSAGE;
1970 		if (ep->state & BOFI_MESSAGE_WAIT)
1971 			cv_broadcast(&ep->cv);
1972 		ep->state &= ~BOFI_MESSAGE_WAIT;
1973 	}
1974 	mutex_exit(&bofi_low_mutex);
1975 	return (DDI_INTR_CLAIMED);
1976 }
1977 
1978 
1979 /*
1980  * wake up all errdefs corresponding to this name and instance
1981  */
1982 static void
1983 bofi_broadcast(struct bofi_errctl *errctlp, char *namep)
1984 {
1985 	struct bofi_errent *ep;
1986 
1987 	/*
1988 	 * look for any errdefs with matching name and instance
1989 	 */
1990 	mutex_enter(&bofi_low_mutex);
1991 	for (ep = errent_listp; ep != NULL; ep = ep->next)
1992 		if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
1993 		    errctlp->instance == ep->errdef.instance) {
1994 			/*
1995 			 * wake up sleepers
1996 			 */
1997 			ep->state |= BOFI_NEW_MESSAGE;
1998 			if (ep->state & BOFI_MESSAGE_WAIT)
1999 				cv_broadcast(&ep->cv);
2000 			ep->state &= ~BOFI_MESSAGE_WAIT;
2001 		}
2002 	mutex_exit(&bofi_low_mutex);
2003 }
2004 
2005 
2006 /*
2007  * clear "acc_chk" for all errdefs corresponding to this name and instance
2008  * and wake them up.
2009  */
2010 static void
2011 bofi_clear_acc_chk(struct bofi_errctl *errctlp, char *namep)
2012 {
2013 	struct bofi_errent *ep;
2014 
2015 	/*
2016 	 * look for any errdefs with matching name and instance
2017 	 */
2018 	mutex_enter(&bofi_low_mutex);
2019 	for (ep = errent_listp; ep != NULL; ep = ep->next)
2020 		if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
2021 		    errctlp->instance == ep->errdef.instance) {
2022 			mutex_enter(&bofi_mutex);
2023 			if (ep->errdef.access_count == 0 &&
2024 			    ep->errdef.fail_count == 0)
2025 				ep->errdef.acc_chk = 0;
2026 			mutex_exit(&bofi_mutex);
2027 			/*
2028 			 * wake up sleepers
2029 			 */
2030 			ep->state |= BOFI_NEW_MESSAGE;
2031 			if (ep->state & BOFI_MESSAGE_WAIT)
2032 				cv_broadcast(&ep->cv);
2033 			ep->state &= ~BOFI_MESSAGE_WAIT;
2034 		}
2035 	mutex_exit(&bofi_low_mutex);
2036 }
2037 
2038 
2039 /*
2040  * set "fail_count" to 0 for all errdefs corresponding to this name and instance
2041  * whose "access_count" has expired, set "acc_chk" to 0 and wake them up.
2042  */
2043 static void
2044 bofi_clear_errors(struct bofi_errctl *errctlp, char *namep)
2045 {
2046 	struct bofi_errent *ep;
2047 
2048 	/*
2049 	 * look for any errdefs with matching name and instance
2050 	 */
2051 	mutex_enter(&bofi_low_mutex);
2052 	for (ep = errent_listp; ep != NULL; ep = ep->next)
2053 		if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
2054 		    errctlp->instance == ep->errdef.instance) {
2055 			mutex_enter(&bofi_mutex);
2056 			if (ep->errdef.access_count == 0) {
2057 				ep->errdef.acc_chk = 0;
2058 				ep->errdef.fail_count = 0;
2059 				mutex_exit(&bofi_mutex);
2060 				if (ep->errdef.log.stop_time == 0ul)
2061 					(void) drv_getparm(TIME,
2062 					    &(ep->errdef.log.stop_time));
2063 			} else
2064 				mutex_exit(&bofi_mutex);
2065 			/*
2066 			 * wake up sleepers
2067 			 */
2068 			ep->state |= BOFI_NEW_MESSAGE;
2069 			if (ep->state & BOFI_MESSAGE_WAIT)
2070 				cv_broadcast(&ep->cv);
2071 			ep->state &= ~BOFI_MESSAGE_WAIT;
2072 		}
2073 	mutex_exit(&bofi_low_mutex);
2074 }
2075 
2076 
2077 /*
2078  * set "access_count" and "fail_count" to 0 for all errdefs corresponding to
2079  * this name and instance, set "acc_chk" to 0, and wake them up.
2080  */
2081 static void
2082 bofi_clear_errdefs(struct bofi_errctl *errctlp, char *namep)
2083 {
2084 	struct bofi_errent *ep;
2085 
2086 	/*
2087 	 * look for any errdefs with matching name and instance
2088 	 */
2089 	mutex_enter(&bofi_low_mutex);
2090 	for (ep = errent_listp; ep != NULL; ep = ep->next)
2091 		if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
2092 		    errctlp->instance == ep->errdef.instance) {
2093 			mutex_enter(&bofi_mutex);
2094 			ep->errdef.acc_chk = 0;
2095 			ep->errdef.access_count = 0;
2096 			ep->errdef.fail_count = 0;
2097 			mutex_exit(&bofi_mutex);
2098 			if (ep->errdef.log.stop_time == 0ul)
2099 				(void) drv_getparm(TIME,
2100 				    &(ep->errdef.log.stop_time));
2101 			/*
2102 			 * wake up sleepers
2103 			 */
2104 			ep->state |= BOFI_NEW_MESSAGE;
2105 			if (ep->state & BOFI_MESSAGE_WAIT)
2106 				cv_broadcast(&ep->cv);
2107 			ep->state &= ~BOFI_MESSAGE_WAIT;
2108 		}
2109 	mutex_exit(&bofi_low_mutex);
2110 }
2111 
2112 
2113 /*
2114  * get state for this errdef
2115  */
2116 static int
2117 bofi_errdef_check(struct bofi_errstate *errstatep, struct acc_log_elem **logpp)
2118 {
2119 	struct bofi_errent *hep;
2120 	struct bofi_errent *ep;
2121 
2122 	ep = (struct bofi_errent *)(uintptr_t)errstatep->errdef_handle;
2123 	mutex_enter(&bofi_low_mutex);
2124 	/*
2125 	 * don't just assume its a valid ep - check that its on the
2126 	 * in-use list
2127 	 */
2128 	for (hep = errent_listp; hep != NULL; hep = hep->next)
2129 		if (hep == ep)
2130 			break;
2131 	if (hep == NULL) {
2132 		mutex_exit(&bofi_low_mutex);
2133 		return (EINVAL);
2134 	}
2135 	mutex_enter(&bofi_mutex);
2136 	ep->errstate.access_count = ep->errdef.access_count;
2137 	ep->errstate.fail_count = ep->errdef.fail_count;
2138 	ep->errstate.acc_chk = ep->errdef.acc_chk;
2139 	ep->errstate.log = ep->errdef.log;
2140 	*logpp = ep->logbase;
2141 	*errstatep = ep->errstate;
2142 	mutex_exit(&bofi_mutex);
2143 	mutex_exit(&bofi_low_mutex);
2144 	return (0);
2145 }
2146 
2147 
2148 /*
2149  * Wait for a ddi_report_fault message to come back for this errdef
2150  * Then return state for this errdef.
2151  * fault report is intercepted by bofi_post_event, which triggers
2152  * bofi_signal via a softint, which will wake up this routine if
2153  * we are waiting
2154  */
2155 static int
2156 bofi_errdef_check_w(struct bofi_errstate *errstatep,
2157     struct acc_log_elem **logpp)
2158 {
2159 	struct bofi_errent *hep;
2160 	struct bofi_errent *ep;
2161 	int rval = 0;
2162 
2163 	ep = (struct bofi_errent *)(uintptr_t)errstatep->errdef_handle;
2164 	mutex_enter(&bofi_low_mutex);
2165 retry:
2166 	/*
2167 	 * don't just assume its a valid ep - check that its on the
2168 	 * in-use list
2169 	 */
2170 	for (hep = errent_listp; hep != NULL; hep = hep->next)
2171 		if (hep == ep)
2172 			break;
2173 	if (hep == NULL) {
2174 		mutex_exit(&bofi_low_mutex);
2175 		return (EINVAL);
2176 	}
2177 	/*
2178 	 * wait for ddi_report_fault for the devinfo corresponding
2179 	 * to this errdef
2180 	 */
2181 	if (rval == 0 && !(ep->state & BOFI_NEW_MESSAGE)) {
2182 		ep->state |= BOFI_MESSAGE_WAIT;
2183 		if (cv_wait_sig(&ep->cv, &bofi_low_mutex) == 0) {
2184 			if (!(ep->state & BOFI_NEW_MESSAGE))
2185 				rval = EINTR;
2186 		}
2187 		goto retry;
2188 	}
2189 	ep->state &= ~BOFI_NEW_MESSAGE;
2190 	/*
2191 	 * we either didn't need to sleep, we've been woken up or we've been
2192 	 * signaled - either way return state now
2193 	 */
2194 	mutex_enter(&bofi_mutex);
2195 	ep->errstate.access_count = ep->errdef.access_count;
2196 	ep->errstate.fail_count = ep->errdef.fail_count;
2197 	ep->errstate.acc_chk = ep->errdef.acc_chk;
2198 	ep->errstate.log = ep->errdef.log;
2199 	*logpp = ep->logbase;
2200 	*errstatep = ep->errstate;
2201 	mutex_exit(&bofi_mutex);
2202 	mutex_exit(&bofi_low_mutex);
2203 	return (rval);
2204 }
2205 
2206 
2207 /*
2208  * support routine - check if requested driver is defined as under test in the
2209  * conf file.
2210  */
2211 static int
2212 driver_under_test(dev_info_t *rdip)
2213 {
2214 	int i;
2215 	char	*rname;
2216 	major_t rmaj;
2217 
2218 	rname = ddi_get_name(rdip);
2219 	rmaj = ddi_name_to_major(rname);
2220 
2221 	/*
2222 	 * Enforce the user to specifically request the following drivers.
2223 	 */
2224 	for (i = 0; i < driver_list_size; i += (1 + strlen(&driver_list[i]))) {
2225 		if (driver_list_neg == 0) {
2226 			if (rmaj == ddi_name_to_major(&driver_list[i]))
2227 				return (1);
2228 		} else {
2229 			if (rmaj == ddi_name_to_major(&driver_list[i+1]))
2230 				return (0);
2231 		}
2232 	}
2233 	if (driver_list_neg == 0)
2234 		return (0);
2235 	else
2236 		return (1);
2237 
2238 }
2239 
2240 
2241 static void
2242 log_acc_event(struct bofi_errent *ep, uint_t at, offset_t offset, off_t len,
2243     size_t repcount, uint64_t *valuep)
2244 {
2245 	struct bofi_errdef *edp = &(ep->errdef);
2246 	struct acc_log *log = &edp->log;
2247 
2248 	ASSERT(log != NULL);
2249 	ASSERT(MUTEX_HELD(&bofi_mutex));
2250 
2251 	if (log->flags & BOFI_LOG_REPIO)
2252 		repcount = 1;
2253 	else if (repcount == 0 && edp->access_count > 0 &&
2254 				(log->flags & BOFI_LOG_FULL) == 0)
2255 		edp->access_count += 1;
2256 
2257 	if (repcount && log->entries < log->logsize) {
2258 		struct acc_log_elem *elem = ep->logbase + log->entries;
2259 
2260 		if (log->flags & BOFI_LOG_TIMESTAMP)
2261 			elem->access_time = bofi_gettime();
2262 		elem->access_type = at;
2263 		elem->offset = offset;
2264 		elem->value = valuep ? *valuep : 0ll;
2265 		elem->size = len;
2266 		elem->repcount = repcount;
2267 		++log->entries;
2268 		if (log->entries == log->logsize) {
2269 			log->flags |= BOFI_LOG_FULL;
2270 			ddi_trigger_softintr(((struct bofi_errent *)
2271 			    (uintptr_t)edp->errdef_handle)->softintr_id);
2272 		}
2273 	}
2274 	if ((log->flags & BOFI_LOG_WRAP) && edp->access_count <= 1) {
2275 		log->wrapcnt++;
2276 		edp->access_count = log->logsize;
2277 		log->entries = 0;	/* wrap back to the start */
2278 	}
2279 }
2280 
2281 
2282 /*
2283  * got a condition match on dma read/write - check counts and corrupt
2284  * data if necessary
2285  *
2286  * bofi_mutex always held when this is called.
2287  */
2288 static void
2289 do_dma_corrupt(struct bofi_shadow *hp, struct bofi_errent *ep,
2290 	uint_t synctype, off_t off, off_t length)
2291 {
2292 	uint64_t operand;
2293 	int i;
2294 	off_t len;
2295 	caddr_t logaddr;
2296 	uint64_t *addr;
2297 	uint64_t *endaddr;
2298 	ddi_dma_impl_t *hdlp;
2299 	ndi_err_t *errp;
2300 
2301 	ASSERT(MUTEX_HELD(&bofi_mutex));
2302 	if ((ep->errdef.access_count ||
2303 		ep->errdef.fail_count) &&
2304 		(ep->errdef.access_type & BOFI_LOG)) {
2305 		uint_t atype;
2306 
2307 		if (synctype == DDI_DMA_SYNC_FORDEV)
2308 			atype = BOFI_DMA_W;
2309 		else if (synctype == DDI_DMA_SYNC_FORCPU ||
2310 			synctype == DDI_DMA_SYNC_FORKERNEL)
2311 			atype = BOFI_DMA_R;
2312 		else
2313 			atype = 0;
2314 		if ((off <= ep->errdef.offset &&
2315 			off + length > ep->errdef.offset) ||
2316 			(off > ep->errdef.offset &&
2317 			off < ep->errdef.offset + ep->errdef.len)) {
2318 			logaddr = (caddr_t)((uintptr_t)(hp->addr +
2319 			    off + LLSZMASK) & ~LLSZMASK);
2320 
2321 			log_acc_event(ep, atype, logaddr - hp->addr,
2322 			    length, 1, 0);
2323 		}
2324 	}
2325 	if (ep->errdef.access_count > 1) {
2326 		ep->errdef.access_count--;
2327 	} else if (ep->errdef.fail_count > 0) {
2328 		ep->errdef.fail_count--;
2329 		ep->errdef.access_count = 0;
2330 		/*
2331 		 * OK do the corruption
2332 		 */
2333 		if (ep->errstate.fail_time == 0)
2334 			ep->errstate.fail_time = bofi_gettime();
2335 		/*
2336 		 * work out how much to corrupt
2337 		 *
2338 		 * Make sure endaddr isn't greater than hp->addr + hp->len.
2339 		 * If endaddr becomes less than addr len becomes negative
2340 		 * and the following loop isn't entered.
2341 		 */
2342 		addr = (uint64_t *)((uintptr_t)((hp->addr +
2343 		    ep->errdef.offset) + LLSZMASK) & ~LLSZMASK);
2344 		endaddr = (uint64_t *)((uintptr_t)(hp->addr + min(hp->len,
2345 		    ep->errdef.offset + ep->errdef.len)) & ~LLSZMASK);
2346 		len = endaddr - addr;
2347 		operand = ep->errdef.operand;
2348 		hdlp = (ddi_dma_impl_t *)(hp->hdl.dma_handle);
2349 		errp = &hdlp->dmai_error;
2350 		if (ep->errdef.acc_chk & 2) {
2351 			uint64_t ena;
2352 			char buf[FM_MAX_CLASS];
2353 
2354 			errp->err_status = DDI_FM_NONFATAL;
2355 			(void) snprintf(buf, FM_MAX_CLASS, FM_SIMULATED_DMA);
2356 			ena = fm_ena_generate(0, FM_ENA_FMT1);
2357 			ddi_fm_ereport_post(hp->dip, buf, ena,
2358 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8,
2359 			    FM_EREPORT_VERS0, NULL);
2360 		}
2361 		switch (ep->errdef.optype) {
2362 		case BOFI_EQUAL :
2363 			for (i = 0; i < len; i++)
2364 				*(addr + i) = operand;
2365 			break;
2366 		case BOFI_AND :
2367 			for (i = 0; i < len; i++)
2368 				*(addr + i) &= operand;
2369 			break;
2370 		case BOFI_OR :
2371 			for (i = 0; i < len; i++)
2372 				*(addr + i) |= operand;
2373 			break;
2374 		case BOFI_XOR :
2375 			for (i = 0; i < len; i++)
2376 				*(addr + i) ^= operand;
2377 			break;
2378 		default:
2379 			/* do nothing */
2380 			break;
2381 		}
2382 	}
2383 }
2384 
2385 
2386 static uint64_t do_bofi_rd8(struct bofi_shadow *, caddr_t);
2387 static uint64_t do_bofi_rd16(struct bofi_shadow *, caddr_t);
2388 static uint64_t do_bofi_rd32(struct bofi_shadow *, caddr_t);
2389 static uint64_t do_bofi_rd64(struct bofi_shadow *, caddr_t);
2390 
2391 
2392 /*
2393  * check all errdefs linked to this shadow handle. If we've got a condition
2394  * match check counts and corrupt data if necessary
2395  *
2396  * bofi_mutex always held when this is called.
2397  *
2398  * because of possibility of BOFI_NO_TRANSFER, we couldn't get data
2399  * from io-space before calling this, so we pass in the func to do the
2400  * transfer as a parameter.
2401  */
2402 static uint64_t
2403 do_pior_corrupt(struct bofi_shadow *hp, caddr_t addr,
2404 	uint64_t (*func)(), size_t repcount, size_t accsize)
2405 {
2406 	struct bofi_errent *ep;
2407 	struct bofi_link   *lp;
2408 	uint64_t operand;
2409 	uintptr_t minlen;
2410 	intptr_t base;
2411 	int done_get = 0;
2412 	uint64_t get_val, gv;
2413 	ddi_acc_impl_t *hdlp;
2414 	ndi_err_t *errp;
2415 
2416 	ASSERT(MUTEX_HELD(&bofi_mutex));
2417 	/*
2418 	 * check through all errdefs associated with this shadow handle
2419 	 */
2420 	for (lp = hp->link; lp != NULL; lp = lp->link) {
2421 		ep = lp->errentp;
2422 		if (ep->errdef.len == 0)
2423 			minlen = hp->len;
2424 		else
2425 			minlen = min(hp->len, ep->errdef.len);
2426 		base = addr - hp->addr - ep->errdef.offset + hp->offset;
2427 		if ((ep->errdef.access_type & BOFI_PIO_R) &&
2428 		    (ep->state & BOFI_DEV_ACTIVE) &&
2429 		    base >= 0 && base < minlen) {
2430 			/*
2431 			 * condition match for pio read
2432 			 */
2433 			if (ep->errdef.access_count > 1) {
2434 				ep->errdef.access_count--;
2435 				if (done_get == 0) {
2436 					done_get = 1;
2437 					gv = get_val = func(hp, addr);
2438 				}
2439 				if (ep->errdef.access_type & BOFI_LOG) {
2440 					log_acc_event(ep, BOFI_PIO_R,
2441 					    addr - hp->addr,
2442 					    accsize, repcount, &gv);
2443 				}
2444 			} else if (ep->errdef.fail_count > 0) {
2445 				ep->errdef.fail_count--;
2446 				ep->errdef.access_count = 0;
2447 				/*
2448 				 * OK do corruption
2449 				 */
2450 				if (ep->errstate.fail_time == 0)
2451 					ep->errstate.fail_time = bofi_gettime();
2452 				operand = ep->errdef.operand;
2453 				if (done_get == 0) {
2454 					if (ep->errdef.optype ==
2455 					    BOFI_NO_TRANSFER)
2456 						/*
2457 						 * no transfer - bomb out
2458 						 */
2459 						return (operand);
2460 					done_get = 1;
2461 					gv = get_val = func(hp, addr);
2462 
2463 				}
2464 				if (ep->errdef.access_type & BOFI_LOG) {
2465 					log_acc_event(ep, BOFI_PIO_R,
2466 					    addr - hp->addr,
2467 					    accsize, repcount, &gv);
2468 				}
2469 				hdlp = (ddi_acc_impl_t *)(hp->hdl.acc_handle);
2470 				errp = hdlp->ahi_err;
2471 				if (ep->errdef.acc_chk & 1) {
2472 					uint64_t ena;
2473 					char buf[FM_MAX_CLASS];
2474 
2475 					errp->err_status = DDI_FM_NONFATAL;
2476 					(void) snprintf(buf, FM_MAX_CLASS,
2477 					    FM_SIMULATED_PIO);
2478 					ena = fm_ena_generate(0, FM_ENA_FMT1);
2479 					ddi_fm_ereport_post(hp->dip, buf, ena,
2480 					    DDI_NOSLEEP, FM_VERSION,
2481 					    DATA_TYPE_UINT8, FM_EREPORT_VERS0,
2482 					    NULL);
2483 				}
2484 				switch (ep->errdef.optype) {
2485 				case BOFI_EQUAL :
2486 					get_val = operand;
2487 					break;
2488 				case BOFI_AND :
2489 					get_val &= operand;
2490 					break;
2491 				case BOFI_OR :
2492 					get_val |= operand;
2493 					break;
2494 				case BOFI_XOR :
2495 					get_val ^= operand;
2496 					break;
2497 				default:
2498 					/* do nothing */
2499 					break;
2500 				}
2501 			}
2502 		}
2503 	}
2504 	if (done_get == 0)
2505 		return (func(hp, addr));
2506 	else
2507 		return (get_val);
2508 }
2509 
2510 
2511 /*
2512  * check all errdefs linked to this shadow handle. If we've got a condition
2513  * match check counts and corrupt data if necessary
2514  *
2515  * bofi_mutex always held when this is called.
2516  *
2517  * because of possibility of BOFI_NO_TRANSFER, we return 0 if no data
2518  * is to be written out to io-space, 1 otherwise
2519  */
2520 static int
2521 do_piow_corrupt(struct bofi_shadow *hp, caddr_t addr, uint64_t *valuep,
2522 				size_t size, size_t repcount)
2523 {
2524 	struct bofi_errent *ep;
2525 	struct bofi_link   *lp;
2526 	uintptr_t minlen;
2527 	intptr_t base;
2528 	uint64_t v = *valuep;
2529 	ddi_acc_impl_t *hdlp;
2530 	ndi_err_t *errp;
2531 
2532 	ASSERT(MUTEX_HELD(&bofi_mutex));
2533 	/*
2534 	 * check through all errdefs associated with this shadow handle
2535 	 */
2536 	for (lp = hp->link; lp != NULL; lp = lp->link) {
2537 		ep = lp->errentp;
2538 		if (ep->errdef.len == 0)
2539 			minlen = hp->len;
2540 		else
2541 			minlen = min(hp->len, ep->errdef.len);
2542 		base = (caddr_t)addr - hp->addr - ep->errdef.offset +hp->offset;
2543 		if ((ep->errdef.access_type & BOFI_PIO_W) &&
2544 		    (ep->state & BOFI_DEV_ACTIVE) &&
2545 		    base >= 0 && base < minlen) {
2546 			/*
2547 			 * condition match for pio write
2548 			 */
2549 
2550 			if (ep->errdef.access_count > 1) {
2551 				ep->errdef.access_count--;
2552 				if (ep->errdef.access_type & BOFI_LOG)
2553 					log_acc_event(ep, BOFI_PIO_W,
2554 					    addr - hp->addr, size,
2555 					    repcount, &v);
2556 			} else if (ep->errdef.fail_count > 0) {
2557 				ep->errdef.fail_count--;
2558 				ep->errdef.access_count = 0;
2559 				if (ep->errdef.access_type & BOFI_LOG)
2560 					log_acc_event(ep, BOFI_PIO_W,
2561 					    addr - hp->addr, size,
2562 					    repcount, &v);
2563 				/*
2564 				 * OK do corruption
2565 				 */
2566 				if (ep->errstate.fail_time == 0)
2567 					ep->errstate.fail_time = bofi_gettime();
2568 				hdlp = (ddi_acc_impl_t *)(hp->hdl.acc_handle);
2569 				errp = hdlp->ahi_err;
2570 				if (ep->errdef.acc_chk & 1) {
2571 					uint64_t ena;
2572 					char buf[FM_MAX_CLASS];
2573 
2574 					errp->err_status = DDI_FM_NONFATAL;
2575 					(void) snprintf(buf, FM_MAX_CLASS,
2576 					    FM_SIMULATED_PIO);
2577 					ena = fm_ena_generate(0, FM_ENA_FMT1);
2578 					ddi_fm_ereport_post(hp->dip, buf, ena,
2579 					    DDI_NOSLEEP, FM_VERSION,
2580 					    DATA_TYPE_UINT8, FM_EREPORT_VERS0,
2581 					    NULL);
2582 				}
2583 				switch (ep->errdef.optype) {
2584 				case BOFI_EQUAL :
2585 					*valuep = ep->errdef.operand;
2586 					break;
2587 				case BOFI_AND :
2588 					*valuep &= ep->errdef.operand;
2589 					break;
2590 				case BOFI_OR :
2591 					*valuep |= ep->errdef.operand;
2592 					break;
2593 				case BOFI_XOR :
2594 					*valuep ^= ep->errdef.operand;
2595 					break;
2596 				case BOFI_NO_TRANSFER :
2597 					/*
2598 					 * no transfer - bomb out
2599 					 */
2600 					return (0);
2601 				default:
2602 					/* do nothing */
2603 					break;
2604 				}
2605 			}
2606 		}
2607 	}
2608 	return (1);
2609 }
2610 
2611 
2612 static uint64_t
2613 do_bofi_rd8(struct bofi_shadow *hp, caddr_t addr)
2614 {
2615 	return (hp->save.acc.ahi_get8(&hp->save.acc, (uint8_t *)addr));
2616 }
2617 
2618 #define	BOFI_READ_CHECKS(type) \
2619 	if (bofi_ddi_check) \
2620 		addr = (type *)((uintptr_t)addr - 64 + hp->addr); \
2621 	if (bofi_range_check && ((caddr_t)addr < hp->addr || \
2622 	    (caddr_t)addr - hp->addr >= hp->len)) { \
2623 		cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \
2624 		    "ddi_get() out of range addr %p not in %p/%llx", \
2625 		    (void *)addr, (void *)hp->addr, hp->len); \
2626 		return (0); \
2627 	}
2628 
2629 /*
2630  * our getb() routine - use tryenter
2631  */
2632 static uint8_t
2633 bofi_rd8(ddi_acc_impl_t *handle, uint8_t *addr)
2634 {
2635 	struct bofi_shadow *hp;
2636 	uint8_t retval;
2637 
2638 	hp = handle->ahi_common.ah_bus_private;
2639 	BOFI_READ_CHECKS(uint8_t)
2640 	if (!hp->link || !mutex_tryenter(&bofi_mutex))
2641 		return (hp->save.acc.ahi_get8(&hp->save.acc, addr));
2642 	retval = (uint8_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd8, 1,
2643 	    1);
2644 	mutex_exit(&bofi_mutex);
2645 	return (retval);
2646 }
2647 
2648 
2649 static uint64_t
2650 do_bofi_rd16(struct bofi_shadow *hp, caddr_t addr)
2651 {
2652 	return (hp->save.acc.ahi_get16(&hp->save.acc, (uint16_t *)addr));
2653 }
2654 
2655 
2656 /*
2657  * our getw() routine - use tryenter
2658  */
2659 static uint16_t
2660 bofi_rd16(ddi_acc_impl_t *handle, uint16_t *addr)
2661 {
2662 	struct bofi_shadow *hp;
2663 	uint16_t retval;
2664 
2665 	hp = handle->ahi_common.ah_bus_private;
2666 	BOFI_READ_CHECKS(uint16_t)
2667 	if (!hp->link || !mutex_tryenter(&bofi_mutex))
2668 		return (hp->save.acc.ahi_get16(&hp->save.acc, addr));
2669 	retval = (uint16_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd16, 1,
2670 	    2);
2671 	mutex_exit(&bofi_mutex);
2672 	return (retval);
2673 }
2674 
2675 
2676 static uint64_t
2677 do_bofi_rd32(struct bofi_shadow *hp, caddr_t addr)
2678 {
2679 	return (hp->save.acc.ahi_get32(&hp->save.acc, (uint32_t *)addr));
2680 }
2681 
2682 
2683 /*
2684  * our getl() routine - use tryenter
2685  */
2686 static uint32_t
2687 bofi_rd32(ddi_acc_impl_t *handle, uint32_t *addr)
2688 {
2689 	struct bofi_shadow *hp;
2690 	uint32_t retval;
2691 
2692 	hp = handle->ahi_common.ah_bus_private;
2693 	BOFI_READ_CHECKS(uint32_t)
2694 	if (!hp->link || !mutex_tryenter(&bofi_mutex))
2695 		return (hp->save.acc.ahi_get32(&hp->save.acc, addr));
2696 	retval = (uint32_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd32, 1,
2697 	    4);
2698 	mutex_exit(&bofi_mutex);
2699 	return (retval);
2700 }
2701 
2702 
2703 static uint64_t
2704 do_bofi_rd64(struct bofi_shadow *hp, caddr_t addr)
2705 {
2706 	return (hp->save.acc.ahi_get64(&hp->save.acc, (uint64_t *)addr));
2707 }
2708 
2709 
2710 /*
2711  * our getll() routine - use tryenter
2712  */
2713 static uint64_t
2714 bofi_rd64(ddi_acc_impl_t *handle, uint64_t *addr)
2715 {
2716 	struct bofi_shadow *hp;
2717 	uint64_t retval;
2718 
2719 	hp = handle->ahi_common.ah_bus_private;
2720 	BOFI_READ_CHECKS(uint64_t)
2721 	if (!hp->link || !mutex_tryenter(&bofi_mutex))
2722 		return (hp->save.acc.ahi_get64(&hp->save.acc, addr));
2723 	retval = (uint64_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd64, 1,
2724 	    8);
2725 	mutex_exit(&bofi_mutex);
2726 	return (retval);
2727 }
2728 
2729 #define	BOFI_WRITE_TESTS(type) \
2730 	if (bofi_ddi_check) \
2731 		addr = (type *)((uintptr_t)addr - 64 + hp->addr); \
2732 	if (bofi_range_check && ((caddr_t)addr < hp->addr || \
2733 	    (caddr_t)addr - hp->addr >= hp->len)) { \
2734 		cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \
2735 		    "ddi_put() out of range addr %p not in %p/%llx\n", \
2736 		    (void *)addr, (void *)hp->addr, hp->len); \
2737 		return; \
2738 	}
2739 
2740 /*
2741  * our putb() routine - use tryenter
2742  */
2743 static void
2744 bofi_wr8(ddi_acc_impl_t *handle, uint8_t *addr, uint8_t value)
2745 {
2746 	struct bofi_shadow *hp;
2747 	uint64_t llvalue = value;
2748 
2749 	hp = handle->ahi_common.ah_bus_private;
2750 	BOFI_WRITE_TESTS(uint8_t)
2751 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
2752 		hp->save.acc.ahi_put8(&hp->save.acc, addr, (uint8_t)llvalue);
2753 		return;
2754 	}
2755 	if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 1, 1))
2756 		hp->save.acc.ahi_put8(&hp->save.acc, addr, (uint8_t)llvalue);
2757 	mutex_exit(&bofi_mutex);
2758 }
2759 
2760 
2761 /*
2762  * our putw() routine - use tryenter
2763  */
2764 static void
2765 bofi_wr16(ddi_acc_impl_t *handle, uint16_t *addr, uint16_t value)
2766 {
2767 	struct bofi_shadow *hp;
2768 	uint64_t llvalue = value;
2769 
2770 	hp = handle->ahi_common.ah_bus_private;
2771 	BOFI_WRITE_TESTS(uint16_t)
2772 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
2773 		hp->save.acc.ahi_put16(&hp->save.acc, addr, (uint16_t)llvalue);
2774 		return;
2775 	}
2776 	if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 2, 1))
2777 		hp->save.acc.ahi_put16(&hp->save.acc, addr, (uint16_t)llvalue);
2778 	mutex_exit(&bofi_mutex);
2779 }
2780 
2781 
2782 /*
2783  * our putl() routine - use tryenter
2784  */
2785 static void
2786 bofi_wr32(ddi_acc_impl_t *handle, uint32_t *addr, uint32_t value)
2787 {
2788 	struct bofi_shadow *hp;
2789 	uint64_t llvalue = value;
2790 
2791 	hp = handle->ahi_common.ah_bus_private;
2792 	BOFI_WRITE_TESTS(uint32_t)
2793 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
2794 		hp->save.acc.ahi_put32(&hp->save.acc, addr, (uint32_t)llvalue);
2795 		return;
2796 	}
2797 	if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 4, 1))
2798 		hp->save.acc.ahi_put32(&hp->save.acc, addr, (uint32_t)llvalue);
2799 	mutex_exit(&bofi_mutex);
2800 }
2801 
2802 
2803 /*
2804  * our putll() routine - use tryenter
2805  */
2806 static void
2807 bofi_wr64(ddi_acc_impl_t *handle, uint64_t *addr, uint64_t value)
2808 {
2809 	struct bofi_shadow *hp;
2810 	uint64_t llvalue = value;
2811 
2812 	hp = handle->ahi_common.ah_bus_private;
2813 	BOFI_WRITE_TESTS(uint64_t)
2814 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
2815 		hp->save.acc.ahi_put64(&hp->save.acc, addr, (uint64_t)llvalue);
2816 		return;
2817 	}
2818 	if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 8, 1))
2819 		hp->save.acc.ahi_put64(&hp->save.acc, addr, (uint64_t)llvalue);
2820 	mutex_exit(&bofi_mutex);
2821 }
2822 
2823 #define	BOFI_REP_READ_TESTS(type) \
2824 	if (bofi_ddi_check) \
2825 		dev_addr = (type *)((uintptr_t)dev_addr - 64 + hp->addr); \
2826 	if (bofi_range_check && ((caddr_t)dev_addr < hp->addr || \
2827 	    (caddr_t)(dev_addr + repcount) - hp->addr > hp->len)) { \
2828 		cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \
2829 		    "ddi_rep_get() out of range addr %p not in %p/%llx\n", \
2830 		    (void *)dev_addr, (void *)hp->addr, hp->len); \
2831 		if ((caddr_t)dev_addr < hp->addr || \
2832 		    (caddr_t)dev_addr - hp->addr >= hp->len) \
2833 			return; \
2834 		repcount = (type *)(hp->addr + hp->len) - dev_addr; \
2835 	}
2836 
2837 /*
2838  * our rep_getb() routine - use tryenter
2839  */
2840 static void
2841 bofi_rep_rd8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr,
2842 	size_t repcount, uint_t flags)
2843 {
2844 	struct bofi_shadow *hp;
2845 	int i;
2846 	uint8_t *addr;
2847 
2848 	hp = handle->ahi_common.ah_bus_private;
2849 	BOFI_REP_READ_TESTS(uint8_t)
2850 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
2851 		hp->save.acc.ahi_rep_get8(&hp->save.acc, host_addr, dev_addr,
2852 		    repcount, flags);
2853 		return;
2854 	}
2855 	for (i = 0; i < repcount; i++) {
2856 		addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0);
2857 		*(host_addr + i) = (uint8_t)do_pior_corrupt(hp, (caddr_t)addr,
2858 		    do_bofi_rd8, i ? 0 : repcount, 1);
2859 	}
2860 	mutex_exit(&bofi_mutex);
2861 }
2862 
2863 
2864 /*
2865  * our rep_getw() routine - use tryenter
2866  */
2867 static void
2868 bofi_rep_rd16(ddi_acc_impl_t *handle, uint16_t *host_addr,
2869 	uint16_t *dev_addr, size_t repcount, uint_t flags)
2870 {
2871 	struct bofi_shadow *hp;
2872 	int i;
2873 	uint16_t *addr;
2874 
2875 	hp = handle->ahi_common.ah_bus_private;
2876 	BOFI_REP_READ_TESTS(uint16_t)
2877 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
2878 		hp->save.acc.ahi_rep_get16(&hp->save.acc, host_addr, dev_addr,
2879 		    repcount, flags);
2880 		return;
2881 	}
2882 	for (i = 0; i < repcount; i++) {
2883 		addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0);
2884 		*(host_addr + i) = (uint16_t)do_pior_corrupt(hp, (caddr_t)addr,
2885 		    do_bofi_rd16, i ? 0 : repcount, 2);
2886 	}
2887 	mutex_exit(&bofi_mutex);
2888 }
2889 
2890 
2891 /*
2892  * our rep_getl() routine - use tryenter
2893  */
2894 static void
2895 bofi_rep_rd32(ddi_acc_impl_t *handle, uint32_t *host_addr,
2896 	uint32_t *dev_addr, size_t repcount, uint_t flags)
2897 {
2898 	struct bofi_shadow *hp;
2899 	int i;
2900 	uint32_t *addr;
2901 
2902 	hp = handle->ahi_common.ah_bus_private;
2903 	BOFI_REP_READ_TESTS(uint32_t)
2904 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
2905 		hp->save.acc.ahi_rep_get32(&hp->save.acc, host_addr, dev_addr,
2906 		    repcount, flags);
2907 		return;
2908 	}
2909 	for (i = 0; i < repcount; i++) {
2910 		addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0);
2911 		*(host_addr + i) = (uint32_t)do_pior_corrupt(hp, (caddr_t)addr,
2912 		    do_bofi_rd32, i ? 0 : repcount, 4);
2913 	}
2914 	mutex_exit(&bofi_mutex);
2915 }
2916 
2917 
2918 /*
2919  * our rep_getll() routine - use tryenter
2920  */
2921 static void
2922 bofi_rep_rd64(ddi_acc_impl_t *handle, uint64_t *host_addr,
2923 	uint64_t *dev_addr, size_t repcount, uint_t flags)
2924 {
2925 	struct bofi_shadow *hp;
2926 	int i;
2927 	uint64_t *addr;
2928 
2929 	hp = handle->ahi_common.ah_bus_private;
2930 	BOFI_REP_READ_TESTS(uint64_t)
2931 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
2932 		hp->save.acc.ahi_rep_get64(&hp->save.acc, host_addr, dev_addr,
2933 		    repcount, flags);
2934 		return;
2935 	}
2936 	for (i = 0; i < repcount; i++) {
2937 		addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0);
2938 		*(host_addr + i) = (uint64_t)do_pior_corrupt(hp, (caddr_t)addr,
2939 		    do_bofi_rd64, i ? 0 : repcount, 8);
2940 	}
2941 	mutex_exit(&bofi_mutex);
2942 }
2943 
2944 #define	BOFI_REP_WRITE_TESTS(type) \
2945 	if (bofi_ddi_check) \
2946 		dev_addr = (type *)((uintptr_t)dev_addr - 64 + hp->addr); \
2947 	if (bofi_range_check && ((caddr_t)dev_addr < hp->addr || \
2948 	    (caddr_t)(dev_addr + repcount) - hp->addr > hp->len)) { \
2949 		cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \
2950 		    "ddi_rep_put() out of range addr %p not in %p/%llx\n", \
2951 		    (void *)dev_addr, (void *)hp->addr, hp->len); \
2952 		if ((caddr_t)dev_addr < hp->addr || \
2953 		    (caddr_t)dev_addr - hp->addr >= hp->len) \
2954 			return; \
2955 		repcount = (type *)(hp->addr + hp->len) - dev_addr; \
2956 	}
2957 
2958 /*
2959  * our rep_putb() routine - use tryenter
2960  */
2961 static void
2962 bofi_rep_wr8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr,
2963 	size_t repcount, uint_t flags)
2964 {
2965 	struct bofi_shadow *hp;
2966 	int i;
2967 	uint64_t llvalue;
2968 	uint8_t *addr;
2969 
2970 	hp = handle->ahi_common.ah_bus_private;
2971 	BOFI_REP_WRITE_TESTS(uint8_t)
2972 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
2973 		hp->save.acc.ahi_rep_put8(&hp->save.acc, host_addr, dev_addr,
2974 		    repcount, flags);
2975 		return;
2976 	}
2977 	for (i = 0; i < repcount; i++) {
2978 		llvalue = *(host_addr + i);
2979 		addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0);
2980 		if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 1, i ? 0 :
2981 		    repcount))
2982 			hp->save.acc.ahi_put8(&hp->save.acc, addr,
2983 			    (uint8_t)llvalue);
2984 	}
2985 	mutex_exit(&bofi_mutex);
2986 }
2987 
2988 
2989 /*
2990  * our rep_putw() routine - use tryenter
2991  */
2992 static void
2993 bofi_rep_wr16(ddi_acc_impl_t *handle, uint16_t *host_addr,
2994 	uint16_t *dev_addr, size_t repcount, uint_t flags)
2995 {
2996 	struct bofi_shadow *hp;
2997 	int i;
2998 	uint64_t llvalue;
2999 	uint16_t *addr;
3000 
3001 	hp = handle->ahi_common.ah_bus_private;
3002 	BOFI_REP_WRITE_TESTS(uint16_t)
3003 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
3004 		hp->save.acc.ahi_rep_put16(&hp->save.acc, host_addr, dev_addr,
3005 		    repcount, flags);
3006 		return;
3007 	}
3008 	for (i = 0; i < repcount; i++) {
3009 		llvalue = *(host_addr + i);
3010 		addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0);
3011 		if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 2, i ? 0 :
3012 		    repcount))
3013 			hp->save.acc.ahi_put16(&hp->save.acc, addr,
3014 			    (uint16_t)llvalue);
3015 	}
3016 	mutex_exit(&bofi_mutex);
3017 }
3018 
3019 
3020 /*
3021  * our rep_putl() routine - use tryenter
3022  */
3023 static void
3024 bofi_rep_wr32(ddi_acc_impl_t *handle, uint32_t *host_addr,
3025 	uint32_t *dev_addr, size_t repcount, uint_t flags)
3026 {
3027 	struct bofi_shadow *hp;
3028 	int i;
3029 	uint64_t llvalue;
3030 	uint32_t *addr;
3031 
3032 	hp = handle->ahi_common.ah_bus_private;
3033 	BOFI_REP_WRITE_TESTS(uint32_t)
3034 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
3035 		hp->save.acc.ahi_rep_put32(&hp->save.acc, host_addr, dev_addr,
3036 		    repcount, flags);
3037 		return;
3038 	}
3039 	for (i = 0; i < repcount; i++) {
3040 		llvalue = *(host_addr + i);
3041 		addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0);
3042 		if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 4, i ? 0 :
3043 		    repcount))
3044 			hp->save.acc.ahi_put32(&hp->save.acc, addr,
3045 			    (uint32_t)llvalue);
3046 	}
3047 	mutex_exit(&bofi_mutex);
3048 }
3049 
3050 
3051 /*
3052  * our rep_putll() routine - use tryenter
3053  */
3054 static void
3055 bofi_rep_wr64(ddi_acc_impl_t *handle, uint64_t *host_addr,
3056 	uint64_t *dev_addr, size_t repcount, uint_t flags)
3057 {
3058 	struct bofi_shadow *hp;
3059 	int i;
3060 	uint64_t llvalue;
3061 	uint64_t *addr;
3062 
3063 	hp = handle->ahi_common.ah_bus_private;
3064 	BOFI_REP_WRITE_TESTS(uint64_t)
3065 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
3066 		hp->save.acc.ahi_rep_put64(&hp->save.acc, host_addr, dev_addr,
3067 		    repcount, flags);
3068 		return;
3069 	}
3070 	for (i = 0; i < repcount; i++) {
3071 		llvalue = *(host_addr + i);
3072 		addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0);
3073 		if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 8, i ? 0 :
3074 		    repcount))
3075 			hp->save.acc.ahi_put64(&hp->save.acc, addr,
3076 			    (uint64_t)llvalue);
3077 	}
3078 	mutex_exit(&bofi_mutex);
3079 }
3080 
3081 
3082 /*
3083  * our ddi_map routine
3084  */
3085 static int
3086 bofi_map(dev_info_t *dip, dev_info_t *rdip,
3087 	ddi_map_req_t *reqp, off_t offset, off_t len, caddr_t *vaddrp)
3088 {
3089 	ddi_acc_impl_t *ap;
3090 	struct bofi_shadow *hp;
3091 	struct bofi_errent *ep;
3092 	struct bofi_link   *lp, *next_lp;
3093 	int retval;
3094 	struct bofi_shadow *dhashp;
3095 	struct bofi_shadow *hhashp;
3096 
3097 	switch (reqp->map_op) {
3098 	case DDI_MO_MAP_LOCKED:
3099 		/*
3100 		 * for this case get nexus to do real work first
3101 		 */
3102 		retval = save_bus_ops.bus_map(dip, rdip, reqp, offset, len,
3103 		    vaddrp);
3104 		if (retval != DDI_SUCCESS)
3105 			return (retval);
3106 
3107 		ap = (ddi_acc_impl_t *)reqp->map_handlep;
3108 		if (ap == NULL)
3109 			return (DDI_SUCCESS);
3110 		/*
3111 		 * if driver_list is set, only intercept those drivers
3112 		 */
3113 		if (!driver_under_test(ap->ahi_common.ah_dip))
3114 			return (DDI_SUCCESS);
3115 
3116 		/*
3117 		 * support for ddi_regs_map_setup()
3118 		 * - allocate shadow handle structure and fill it in
3119 		 */
3120 		hp = kmem_zalloc(sizeof (struct bofi_shadow), KM_SLEEP);
3121 		(void) strncpy(hp->name, ddi_get_name(ap->ahi_common.ah_dip),
3122 		    NAMESIZE);
3123 		hp->instance = ddi_get_instance(ap->ahi_common.ah_dip);
3124 		hp->dip = ap->ahi_common.ah_dip;
3125 		hp->addr = *vaddrp;
3126 		/*
3127 		 * return spurious value to catch direct access to registers
3128 		 */
3129 		if (bofi_ddi_check)
3130 			*vaddrp = (caddr_t)64;
3131 		hp->rnumber = ((ddi_acc_hdl_t *)ap)->ah_rnumber;
3132 		hp->offset = offset;
3133 		if (len == 0)
3134 			hp->len = INT_MAX - offset;
3135 		else
3136 			hp->len = min(len, INT_MAX - offset);
3137 		hp->hdl.acc_handle = (ddi_acc_handle_t)ap;
3138 		hp->link = NULL;
3139 		hp->type = BOFI_ACC_HDL;
3140 		/*
3141 		 * save existing function pointers and plug in our own
3142 		 */
3143 		hp->save.acc = *ap;
3144 		ap->ahi_get8 = bofi_rd8;
3145 		ap->ahi_get16 = bofi_rd16;
3146 		ap->ahi_get32 = bofi_rd32;
3147 		ap->ahi_get64 = bofi_rd64;
3148 		ap->ahi_put8 = bofi_wr8;
3149 		ap->ahi_put16 = bofi_wr16;
3150 		ap->ahi_put32 = bofi_wr32;
3151 		ap->ahi_put64 = bofi_wr64;
3152 		ap->ahi_rep_get8 = bofi_rep_rd8;
3153 		ap->ahi_rep_get16 = bofi_rep_rd16;
3154 		ap->ahi_rep_get32 = bofi_rep_rd32;
3155 		ap->ahi_rep_get64 = bofi_rep_rd64;
3156 		ap->ahi_rep_put8 = bofi_rep_wr8;
3157 		ap->ahi_rep_put16 = bofi_rep_wr16;
3158 		ap->ahi_rep_put32 = bofi_rep_wr32;
3159 		ap->ahi_rep_put64 = bofi_rep_wr64;
3160 		ap->ahi_fault_check = bofi_check_acc_hdl;
3161 #if defined(__sparc)
3162 #else
3163 		ap->ahi_acc_attr &= ~DDI_ACCATTR_DIRECT;
3164 #endif
3165 		/*
3166 		 * stick in a pointer to our shadow handle
3167 		 */
3168 		ap->ahi_common.ah_bus_private = hp;
3169 		/*
3170 		 * add to dhash, hhash and inuse lists
3171 		 */
3172 		mutex_enter(&bofi_low_mutex);
3173 		mutex_enter(&bofi_mutex);
3174 		hp->next = shadow_list.next;
3175 		shadow_list.next->prev = hp;
3176 		hp->prev = &shadow_list;
3177 		shadow_list.next = hp;
3178 		hhashp = HDL_HHASH(ap);
3179 		hp->hnext = hhashp->hnext;
3180 		hhashp->hnext->hprev = hp;
3181 		hp->hprev = hhashp;
3182 		hhashp->hnext = hp;
3183 		dhashp = HDL_DHASH(hp->dip);
3184 		hp->dnext = dhashp->dnext;
3185 		dhashp->dnext->dprev = hp;
3186 		hp->dprev = dhashp;
3187 		dhashp->dnext = hp;
3188 		/*
3189 		 * chain on any pre-existing errdefs that apply to this
3190 		 * acc_handle
3191 		 */
3192 		for (ep = errent_listp; ep != NULL; ep = ep->next) {
3193 			if (ddi_name_to_major(hp->name) ==
3194 			    ddi_name_to_major(ep->name) &&
3195 			    hp->instance == ep->errdef.instance &&
3196 			    (ep->errdef.access_type & BOFI_PIO_RW) &&
3197 			    (ep->errdef.rnumber == -1 ||
3198 			    hp->rnumber == ep->errdef.rnumber) &&
3199 			    (ep->errdef.len == 0 ||
3200 			    offset < ep->errdef.offset + ep->errdef.len) &&
3201 			    offset + hp->len > ep->errdef.offset) {
3202 				lp = bofi_link_freelist;
3203 				if (lp != NULL) {
3204 					bofi_link_freelist = lp->link;
3205 					lp->errentp = ep;
3206 					lp->link = hp->link;
3207 					hp->link = lp;
3208 				}
3209 			}
3210 		}
3211 		mutex_exit(&bofi_mutex);
3212 		mutex_exit(&bofi_low_mutex);
3213 		return (DDI_SUCCESS);
3214 	case DDI_MO_UNMAP:
3215 
3216 		ap = (ddi_acc_impl_t *)reqp->map_handlep;
3217 		if (ap == NULL)
3218 			break;
3219 		/*
3220 		 * support for ddi_regs_map_free()
3221 		 * - check we really have a shadow handle for this one
3222 		 */
3223 		mutex_enter(&bofi_low_mutex);
3224 		mutex_enter(&bofi_mutex);
3225 		hhashp = HDL_HHASH(ap);
3226 		for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext)
3227 			if (hp->hdl.acc_handle == (ddi_acc_handle_t)ap)
3228 				break;
3229 		if (hp == hhashp) {
3230 			mutex_exit(&bofi_mutex);
3231 			mutex_exit(&bofi_low_mutex);
3232 			break;
3233 		}
3234 		/*
3235 		 * got a shadow handle - restore original pointers
3236 		 */
3237 		*ap = hp->save.acc;
3238 		*vaddrp = hp->addr;
3239 		/*
3240 		 * remove from dhash, hhash and inuse lists
3241 		 */
3242 		hp->hnext->hprev = hp->hprev;
3243 		hp->hprev->hnext = hp->hnext;
3244 		hp->dnext->dprev = hp->dprev;
3245 		hp->dprev->dnext = hp->dnext;
3246 		hp->next->prev = hp->prev;
3247 		hp->prev->next = hp->next;
3248 		/*
3249 		 * free any errdef link structures tagged onto the shadow handle
3250 		 */
3251 		for (lp = hp->link; lp != NULL; ) {
3252 			next_lp = lp->link;
3253 			lp->link = bofi_link_freelist;
3254 			bofi_link_freelist = lp;
3255 			lp = next_lp;
3256 		}
3257 		hp->link = NULL;
3258 		mutex_exit(&bofi_mutex);
3259 		mutex_exit(&bofi_low_mutex);
3260 		/*
3261 		 * finally delete shadow handle
3262 		 */
3263 		kmem_free(hp, sizeof (struct bofi_shadow));
3264 		break;
3265 	default:
3266 		break;
3267 	}
3268 	return (save_bus_ops.bus_map(dip, rdip, reqp, offset, len, vaddrp));
3269 }
3270 
3271 
3272 /*
3273  * chain any pre-existing errdefs on to newly created dma handle
3274  * if required call do_dma_corrupt() to corrupt data
3275  */
3276 static void
3277 chain_on_errdefs(struct bofi_shadow *hp)
3278 {
3279 	struct bofi_errent *ep;
3280 	struct bofi_link   *lp;
3281 
3282 	ASSERT(MUTEX_HELD(&bofi_mutex));
3283 	/*
3284 	 * chain on any pre-existing errdefs that apply to this dma_handle
3285 	 */
3286 	for (ep = errent_listp; ep != NULL; ep = ep->next) {
3287 		if (ddi_name_to_major(hp->name) ==
3288 		    ddi_name_to_major(ep->name) &&
3289 		    hp->instance == ep->errdef.instance &&
3290 		    (ep->errdef.rnumber == -1 ||
3291 		    hp->rnumber == ep->errdef.rnumber) &&
3292 		    ((ep->errdef.access_type & BOFI_DMA_RW) &&
3293 		    (((uintptr_t)(hp->addr + ep->errdef.offset +
3294 		    ep->errdef.len) & ~LLSZMASK) >
3295 		    ((uintptr_t)((hp->addr + ep->errdef.offset) +
3296 		    LLSZMASK) & ~LLSZMASK)))) {
3297 			/*
3298 			 * got a match - link it on
3299 			 */
3300 			lp = bofi_link_freelist;
3301 			if (lp != NULL) {
3302 				bofi_link_freelist = lp->link;
3303 				lp->errentp = ep;
3304 				lp->link = hp->link;
3305 				hp->link = lp;
3306 				if ((ep->errdef.access_type & BOFI_DMA_W) &&
3307 				    (hp->flags & DDI_DMA_WRITE) &&
3308 				    (ep->state & BOFI_DEV_ACTIVE)) {
3309 					do_dma_corrupt(hp, ep,
3310 					    DDI_DMA_SYNC_FORDEV,
3311 					    0, hp->len);
3312 				}
3313 			}
3314 		}
3315 	}
3316 }
3317 
3318 
3319 /*
3320  * need to do copy byte-by-byte in case one of pages is little-endian
3321  */
3322 static void
3323 xbcopy(void *from, void *to, u_longlong_t len)
3324 {
3325 	uchar_t *f = from;
3326 	uchar_t *t = to;
3327 
3328 	while (len--)
3329 		*t++ = *f++;
3330 }
3331 
3332 
3333 /*
3334  * our ddi_dma_map routine
3335  */
3336 static int
3337 bofi_dma_map(dev_info_t *dip, dev_info_t *rdip,
3338 		struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
3339 {
3340 	struct bofi_shadow *hp, *xhp;
3341 	int maxrnumber = 0;
3342 	int retval = DDI_DMA_NORESOURCES;
3343 	auto struct ddi_dma_req dmareq;
3344 	int sleep;
3345 	struct bofi_shadow *dhashp;
3346 	struct bofi_shadow *hhashp;
3347 	ddi_dma_impl_t *mp;
3348 	unsigned long pagemask = ddi_ptob(rdip, 1) - 1;
3349 
3350 	/*
3351 	 * if driver_list is set, only intercept those drivers
3352 	 */
3353 	if (handlep == NULL || !driver_under_test(rdip))
3354 		return (save_bus_ops.bus_dma_map(dip, rdip, dmareqp, handlep));
3355 
3356 	sleep = (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
3357 	/*
3358 	 * allocate shadow handle structure and fill it in
3359 	 */
3360 	hp = kmem_zalloc(sizeof (struct bofi_shadow), sleep);
3361 	if (hp == NULL)
3362 		goto error;
3363 	(void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE);
3364 	hp->instance = ddi_get_instance(rdip);
3365 	hp->dip = rdip;
3366 	hp->flags = dmareqp->dmar_flags;
3367 	hp->link = NULL;
3368 	hp->type = BOFI_DMA_HDL;
3369 	/*
3370 	 * get a kernel virtual mapping
3371 	 */
3372 	hp->addr = ddi_dmareq_mapin(dmareqp, &hp->mapaddr, &hp->len);
3373 	if (hp->addr == NULL)
3374 		goto error;
3375 	if (bofi_sync_check) {
3376 		/*
3377 		 * Take a copy and pass pointers to this up to nexus instead.
3378 		 * Data will be copied from the original on explicit
3379 		 * and implicit ddi_dma_sync()
3380 		 *
3381 		 * - maintain page alignment because some devices assume it.
3382 		 */
3383 		hp->origaddr = hp->addr;
3384 		hp->allocaddr = ddi_umem_alloc(
3385 		    ((uintptr_t)hp->addr & pagemask) + hp->len, sleep,
3386 		    &hp->umem_cookie);
3387 		if (hp->allocaddr == NULL)
3388 			goto error;
3389 		hp->addr = hp->allocaddr + ((uintptr_t)hp->addr & pagemask);
3390 		if (dmareqp->dmar_flags & DDI_DMA_WRITE)
3391 			xbcopy(hp->origaddr, hp->addr, hp->len);
3392 		dmareq = *dmareqp;
3393 		dmareq.dmar_object.dmao_size = hp->len;
3394 		dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR;
3395 		dmareq.dmar_object.dmao_obj.virt_obj.v_as = &kas;
3396 		dmareq.dmar_object.dmao_obj.virt_obj.v_addr = hp->addr;
3397 		dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
3398 		dmareqp = &dmareq;
3399 	}
3400 	/*
3401 	 * call nexus to do the real work
3402 	 */
3403 	retval = save_bus_ops.bus_dma_map(dip, rdip, dmareqp, handlep);
3404 	if (retval != DDI_SUCCESS)
3405 		goto error2;
3406 	/*
3407 	 * now set dma_handle to point to real handle
3408 	 */
3409 	hp->hdl.dma_handle = *handlep;
3410 	/*
3411 	 * unset DMP_NOSYNC
3412 	 */
3413 	mp = (ddi_dma_impl_t *)*handlep;
3414 	mp->dmai_rflags &= ~DMP_NOSYNC;
3415 	mp->dmai_fault_check = bofi_check_dma_hdl;
3416 	/*
3417 	 * bind and unbind are cached in devinfo - must overwrite them
3418 	 * - note that our bind and unbind are quite happy dealing with
3419 	 * any handles for this devinfo that were previously allocated
3420 	 */
3421 	if (save_bus_ops.bus_dma_bindhdl == DEVI(rdip)->devi_bus_dma_bindfunc)
3422 		DEVI(rdip)->devi_bus_dma_bindfunc = bofi_dma_bindhdl;
3423 	if (save_bus_ops.bus_dma_unbindhdl ==
3424 	    DEVI(rdip)->devi_bus_dma_unbindfunc)
3425 		DEVI(rdip)->devi_bus_dma_unbindfunc = bofi_dma_unbindhdl;
3426 	mutex_enter(&bofi_low_mutex);
3427 	mutex_enter(&bofi_mutex);
3428 	/*
3429 	 * get an "rnumber" for this handle - really just seeking to
3430 	 * get a unique number - generally only care for early allocated
3431 	 * handles - so we get as far as INT_MAX, just stay there
3432 	 */
3433 	dhashp = HDL_DHASH(hp->dip);
3434 	for (xhp = dhashp->dnext; xhp != dhashp; xhp = xhp->dnext)
3435 		if (ddi_name_to_major(xhp->name) ==
3436 		    ddi_name_to_major(hp->name) &&
3437 		    xhp->instance == hp->instance &&
3438 		    xhp->type == BOFI_DMA_HDL)
3439 			if (xhp->rnumber >= maxrnumber) {
3440 				if (xhp->rnumber == INT_MAX)
3441 					maxrnumber = INT_MAX;
3442 				else
3443 					maxrnumber = xhp->rnumber + 1;
3444 			}
3445 	hp->rnumber = maxrnumber;
3446 	/*
3447 	 * add to dhash, hhash and inuse lists
3448 	 */
3449 	hp->next = shadow_list.next;
3450 	shadow_list.next->prev = hp;
3451 	hp->prev = &shadow_list;
3452 	shadow_list.next = hp;
3453 	hhashp = HDL_HHASH(*handlep);
3454 	hp->hnext = hhashp->hnext;
3455 	hhashp->hnext->hprev = hp;
3456 	hp->hprev = hhashp;
3457 	hhashp->hnext = hp;
3458 	dhashp = HDL_DHASH(hp->dip);
3459 	hp->dnext = dhashp->dnext;
3460 	dhashp->dnext->dprev = hp;
3461 	hp->dprev = dhashp;
3462 	dhashp->dnext = hp;
3463 	/*
3464 	 * chain on any pre-existing errdefs that apply to this
3465 	 * acc_handle and corrupt if required (as there is an implicit
3466 	 * ddi_dma_sync() in this call)
3467 	 */
3468 	chain_on_errdefs(hp);
3469 	mutex_exit(&bofi_mutex);
3470 	mutex_exit(&bofi_low_mutex);
3471 	return (retval);
3472 error:
3473 	if (dmareqp->dmar_fp != DDI_DMA_DONTWAIT) {
3474 		/*
3475 		 * what to do here? Wait a bit and try again
3476 		 */
3477 		(void) timeout((void (*)())dmareqp->dmar_fp,
3478 		    dmareqp->dmar_arg, 10);
3479 	}
3480 error2:
3481 	if (hp) {
3482 		ddi_dmareq_mapout(hp->mapaddr, hp->len);
3483 		if (bofi_sync_check && hp->allocaddr)
3484 			ddi_umem_free(hp->umem_cookie);
3485 		kmem_free(hp, sizeof (struct bofi_shadow));
3486 	}
3487 	return (retval);
3488 }
3489 
3490 
3491 /*
3492  * our ddi_dma_allochdl routine
3493  */
3494 static int
3495 bofi_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp,
3496 	int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
3497 {
3498 	int retval = DDI_DMA_NORESOURCES;
3499 	struct bofi_shadow *hp, *xhp;
3500 	int maxrnumber = 0;
3501 	struct bofi_shadow *dhashp;
3502 	struct bofi_shadow *hhashp;
3503 	ddi_dma_impl_t *mp;
3504 
3505 	/*
3506 	 * if driver_list is set, only intercept those drivers
3507 	 */
3508 	if (!driver_under_test(rdip))
3509 		return (save_bus_ops.bus_dma_allochdl(dip, rdip, attrp,
3510 		    waitfp, arg, handlep));
3511 
3512 	/*
3513 	 * allocate shadow handle structure and fill it in
3514 	 */
3515 	hp = kmem_zalloc(sizeof (struct bofi_shadow),
3516 	    ((waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP));
3517 	if (hp == NULL) {
3518 		/*
3519 		 * what to do here? Wait a bit and try again
3520 		 */
3521 		if (waitfp != DDI_DMA_DONTWAIT)
3522 			(void) timeout((void (*)())waitfp, arg, 10);
3523 		return (retval);
3524 	}
3525 	(void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE);
3526 	hp->instance = ddi_get_instance(rdip);
3527 	hp->dip = rdip;
3528 	hp->link = NULL;
3529 	hp->type = BOFI_NULL;
3530 	/*
3531 	 * call nexus to do the real work
3532 	 */
3533 	retval = save_bus_ops.bus_dma_allochdl(dip, rdip, attrp, waitfp, arg,
3534 	    handlep);
3535 	if (retval != DDI_SUCCESS) {
3536 		kmem_free(hp, sizeof (struct bofi_shadow));
3537 		return (retval);
3538 	}
3539 	/*
3540 	 * now point set dma_handle to point to real handle
3541 	 */
3542 	hp->hdl.dma_handle = *handlep;
3543 	mp = (ddi_dma_impl_t *)*handlep;
3544 	mp->dmai_fault_check = bofi_check_dma_hdl;
3545 	/*
3546 	 * bind and unbind are cached in devinfo - must overwrite them
3547 	 * - note that our bind and unbind are quite happy dealing with
3548 	 * any handles for this devinfo that were previously allocated
3549 	 */
3550 	if (save_bus_ops.bus_dma_bindhdl == DEVI(rdip)->devi_bus_dma_bindfunc)
3551 		DEVI(rdip)->devi_bus_dma_bindfunc = bofi_dma_bindhdl;
3552 	if (save_bus_ops.bus_dma_unbindhdl ==
3553 	    DEVI(rdip)->devi_bus_dma_unbindfunc)
3554 		DEVI(rdip)->devi_bus_dma_unbindfunc = bofi_dma_unbindhdl;
3555 	mutex_enter(&bofi_low_mutex);
3556 	mutex_enter(&bofi_mutex);
3557 	/*
3558 	 * get an "rnumber" for this handle - really just seeking to
3559 	 * get a unique number - generally only care for early allocated
3560 	 * handles - so we get as far as INT_MAX, just stay there
3561 	 */
3562 	dhashp = HDL_DHASH(hp->dip);
3563 	for (xhp = dhashp->dnext; xhp != dhashp; xhp = xhp->dnext)
3564 		if (ddi_name_to_major(xhp->name) ==
3565 		    ddi_name_to_major(hp->name) &&
3566 		    xhp->instance == hp->instance &&
3567 		    (xhp->type == BOFI_DMA_HDL ||
3568 		    xhp->type == BOFI_NULL))
3569 			if (xhp->rnumber >= maxrnumber) {
3570 				if (xhp->rnumber == INT_MAX)
3571 					maxrnumber = INT_MAX;
3572 				else
3573 					maxrnumber = xhp->rnumber + 1;
3574 			}
3575 	hp->rnumber = maxrnumber;
3576 	/*
3577 	 * add to dhash, hhash and inuse lists
3578 	 */
3579 	hp->next = shadow_list.next;
3580 	shadow_list.next->prev = hp;
3581 	hp->prev = &shadow_list;
3582 	shadow_list.next = hp;
3583 	hhashp = HDL_HHASH(*handlep);
3584 	hp->hnext = hhashp->hnext;
3585 	hhashp->hnext->hprev = hp;
3586 	hp->hprev = hhashp;
3587 	hhashp->hnext = hp;
3588 	dhashp = HDL_DHASH(hp->dip);
3589 	hp->dnext = dhashp->dnext;
3590 	dhashp->dnext->dprev = hp;
3591 	hp->dprev = dhashp;
3592 	dhashp->dnext = hp;
3593 	mutex_exit(&bofi_mutex);
3594 	mutex_exit(&bofi_low_mutex);
3595 	return (retval);
3596 }
3597 
3598 
3599 /*
3600  * our ddi_dma_freehdl routine
3601  */
3602 static int
3603 bofi_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
3604 {
3605 	int retval;
3606 	struct bofi_shadow *hp;
3607 	struct bofi_shadow *hhashp;
3608 
3609 	/*
3610 	 * find shadow for this handle
3611 	 */
3612 	mutex_enter(&bofi_low_mutex);
3613 	mutex_enter(&bofi_mutex);
3614 	hhashp = HDL_HHASH(handle);
3615 	for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext)
3616 		if (hp->hdl.dma_handle == handle)
3617 			break;
3618 	mutex_exit(&bofi_mutex);
3619 	mutex_exit(&bofi_low_mutex);
3620 	/*
3621 	 * call nexus to do the real work
3622 	 */
3623 	retval = save_bus_ops.bus_dma_freehdl(dip, rdip, handle);
3624 	if (retval != DDI_SUCCESS) {
3625 		return (retval);
3626 	}
3627 	/*
3628 	 * did we really have a shadow for this handle
3629 	 */
3630 	if (hp == hhashp)
3631 		return (retval);
3632 	/*
3633 	 * yes we have - see if it's still bound
3634 	 */
3635 	mutex_enter(&bofi_low_mutex);
3636 	mutex_enter(&bofi_mutex);
3637 	if (hp->type != BOFI_NULL)
3638 		panic("driver freeing bound dma_handle");
3639 	/*
3640 	 * remove from dhash, hhash and inuse lists
3641 	 */
3642 	hp->hnext->hprev = hp->hprev;
3643 	hp->hprev->hnext = hp->hnext;
3644 	hp->dnext->dprev = hp->dprev;
3645 	hp->dprev->dnext = hp->dnext;
3646 	hp->next->prev = hp->prev;
3647 	hp->prev->next = hp->next;
3648 	mutex_exit(&bofi_mutex);
3649 	mutex_exit(&bofi_low_mutex);
3650 
3651 	kmem_free(hp, sizeof (struct bofi_shadow));
3652 	return (retval);
3653 }
3654 
3655 
3656 /*
3657  * our ddi_dma_bindhdl routine
3658  */
3659 static int
3660 bofi_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
3661 	ddi_dma_handle_t handle, struct ddi_dma_req *dmareqp,
3662 	ddi_dma_cookie_t *cookiep, uint_t *ccountp)
3663 {
3664 	int retval = DDI_DMA_NORESOURCES;
3665 	auto struct ddi_dma_req dmareq;
3666 	struct bofi_shadow *hp;
3667 	struct bofi_shadow *hhashp;
3668 	ddi_dma_impl_t *mp;
3669 	unsigned long pagemask = ddi_ptob(rdip, 1) - 1;
3670 
3671 	/*
3672 	 * check we really have a shadow for this handle
3673 	 */
3674 	mutex_enter(&bofi_low_mutex);
3675 	mutex_enter(&bofi_mutex);
3676 	hhashp = HDL_HHASH(handle);
3677 	for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext)
3678 		if (hp->hdl.dma_handle == handle)
3679 			break;
3680 	mutex_exit(&bofi_mutex);
3681 	mutex_exit(&bofi_low_mutex);
3682 	if (hp == hhashp) {
3683 		/*
3684 		 * no we don't - just call nexus to do the real work
3685 		 */
3686 		return save_bus_ops.bus_dma_bindhdl(dip, rdip, handle, dmareqp,
3687 		    cookiep, ccountp);
3688 	}
3689 	/*
3690 	 * yes we have - see if it's already bound
3691 	 */
3692 	if (hp->type != BOFI_NULL)
3693 		return (DDI_DMA_INUSE);
3694 
3695 	hp->flags = dmareqp->dmar_flags;
3696 	/*
3697 	 * get a kernel virtual mapping
3698 	 */
3699 	hp->addr = ddi_dmareq_mapin(dmareqp, &hp->mapaddr, &hp->len);
3700 	if (hp->addr == NULL)
3701 		goto error;
3702 	if (bofi_sync_check) {
3703 		/*
3704 		 * Take a copy and pass pointers to this up to nexus instead.
3705 		 * Data will be copied from the original on explicit
3706 		 * and implicit ddi_dma_sync()
3707 		 *
3708 		 * - maintain page alignment because some devices assume it.
3709 		 */
3710 		hp->origaddr = hp->addr;
3711 		hp->allocaddr = ddi_umem_alloc(
3712 		    ((uintptr_t)hp->addr & pagemask) + hp->len,
3713 		    (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP,
3714 		    &hp->umem_cookie);
3715 		if (hp->allocaddr == NULL)
3716 			goto error;
3717 		hp->addr = hp->allocaddr + ((uintptr_t)hp->addr & pagemask);
3718 		if (dmareqp->dmar_flags & DDI_DMA_WRITE)
3719 			xbcopy(hp->origaddr, hp->addr, hp->len);
3720 		dmareq = *dmareqp;
3721 		dmareq.dmar_object.dmao_size = hp->len;
3722 		dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR;
3723 		dmareq.dmar_object.dmao_obj.virt_obj.v_as = &kas;
3724 		dmareq.dmar_object.dmao_obj.virt_obj.v_addr = hp->addr;
3725 		dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
3726 		dmareqp = &dmareq;
3727 	}
3728 	/*
3729 	 * call nexus to do the real work
3730 	 */
3731 	retval = save_bus_ops.bus_dma_bindhdl(dip, rdip, handle, dmareqp,
3732 	    cookiep, ccountp);
3733 	if (retval != DDI_SUCCESS)
3734 		goto error2;
3735 	/*
3736 	 * unset DMP_NOSYNC
3737 	 */
3738 	mp = (ddi_dma_impl_t *)handle;
3739 	mp->dmai_rflags &= ~DMP_NOSYNC;
3740 	/*
3741 	 * chain on any pre-existing errdefs that apply to this
3742 	 * acc_handle and corrupt if required (as there is an implicit
3743 	 * ddi_dma_sync() in this call)
3744 	 */
3745 	mutex_enter(&bofi_low_mutex);
3746 	mutex_enter(&bofi_mutex);
3747 	hp->type = BOFI_DMA_HDL;
3748 	chain_on_errdefs(hp);
3749 	mutex_exit(&bofi_mutex);
3750 	mutex_exit(&bofi_low_mutex);
3751 	return (retval);
3752 
3753 error:
3754 	if (dmareqp->dmar_fp != DDI_DMA_DONTWAIT) {
3755 		/*
3756 		 * what to do here? Wait a bit and try again
3757 		 */
3758 		(void) timeout((void (*)())dmareqp->dmar_fp,
3759 		    dmareqp->dmar_arg, 10);
3760 	}
3761 error2:
3762 	if (hp) {
3763 		ddi_dmareq_mapout(hp->mapaddr, hp->len);
3764 		if (bofi_sync_check && hp->allocaddr)
3765 			ddi_umem_free(hp->umem_cookie);
3766 		hp->mapaddr = NULL;
3767 		hp->allocaddr = NULL;
3768 		hp->origaddr = NULL;
3769 	}
3770 	return (retval);
3771 }
3772 
3773 
3774 /*
3775  * our ddi_dma_unbindhdl routine
3776  */
3777 static int
3778 bofi_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
3779 {
3780 	struct bofi_link *lp, *next_lp;
3781 	struct bofi_errent *ep;
3782 	int retval;
3783 	struct bofi_shadow *hp;
3784 	struct bofi_shadow *hhashp;
3785 
3786 	/*
3787 	 * call nexus to do the real work
3788 	 */
3789 	retval = save_bus_ops.bus_dma_unbindhdl(dip, rdip, handle);
3790 	if (retval != DDI_SUCCESS)
3791 		return (retval);
3792 	/*
3793 	 * check we really have a shadow for this handle
3794 	 */
3795 	mutex_enter(&bofi_low_mutex);
3796 	mutex_enter(&bofi_mutex);
3797 	hhashp = HDL_HHASH(handle);
3798 	for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext)
3799 		if (hp->hdl.dma_handle == handle)
3800 			break;
3801 	if (hp == hhashp) {
3802 		mutex_exit(&bofi_mutex);
3803 		mutex_exit(&bofi_low_mutex);
3804 		return (retval);
3805 	}
3806 	/*
3807 	 * yes we have - see if it's already unbound
3808 	 */
3809 	if (hp->type == BOFI_NULL)
3810 		panic("driver unbinding unbound dma_handle");
3811 	/*
3812 	 * free any errdef link structures tagged on to this
3813 	 * shadow handle
3814 	 */
3815 	for (lp = hp->link; lp != NULL; ) {
3816 		next_lp = lp->link;
3817 		/*
3818 		 * there is an implicit sync_for_cpu on free -
3819 		 * may need to corrupt
3820 		 */
3821 		ep = lp->errentp;
3822 		if ((ep->errdef.access_type & BOFI_DMA_R) &&
3823 		    (hp->flags & DDI_DMA_READ) &&
3824 		    (ep->state & BOFI_DEV_ACTIVE)) {
3825 			do_dma_corrupt(hp, ep, DDI_DMA_SYNC_FORCPU, 0, hp->len);
3826 		}
3827 		lp->link = bofi_link_freelist;
3828 		bofi_link_freelist = lp;
3829 		lp = next_lp;
3830 	}
3831 	hp->link = NULL;
3832 	hp->type = BOFI_NULL;
3833 	mutex_exit(&bofi_mutex);
3834 	mutex_exit(&bofi_low_mutex);
3835 
3836 	if (bofi_sync_check && (hp->flags & DDI_DMA_READ))
3837 		/*
3838 		 * implicit sync_for_cpu - copy data back
3839 		 */
3840 		if (hp->allocaddr)
3841 			xbcopy(hp->addr, hp->origaddr, hp->len);
3842 	ddi_dmareq_mapout(hp->mapaddr, hp->len);
3843 	if (bofi_sync_check && hp->allocaddr)
3844 		ddi_umem_free(hp->umem_cookie);
3845 	hp->mapaddr = NULL;
3846 	hp->allocaddr = NULL;
3847 	hp->origaddr = NULL;
3848 	return (retval);
3849 }
3850 
3851 
3852 /*
3853  * our ddi_dma_sync routine
3854  */
3855 static int
3856 bofi_dma_flush(dev_info_t *dip, dev_info_t *rdip,
3857 		ddi_dma_handle_t handle, off_t off, size_t len, uint_t flags)
3858 {
3859 	struct bofi_link *lp;
3860 	struct bofi_errent *ep;
3861 	struct bofi_shadow *hp;
3862 	struct bofi_shadow *hhashp;
3863 	int retval;
3864 
3865 	if (flags == DDI_DMA_SYNC_FORCPU || flags == DDI_DMA_SYNC_FORKERNEL) {
3866 		/*
3867 		 * in this case get nexus driver to do sync first
3868 		 */
3869 		retval = save_bus_ops.bus_dma_flush(dip, rdip, handle, off,
3870 		    len, flags);
3871 		if (retval != DDI_SUCCESS)
3872 			return (retval);
3873 	}
3874 	/*
3875 	 * check we really have a shadow for this handle
3876 	 */
3877 	mutex_enter(&bofi_low_mutex);
3878 	mutex_enter(&bofi_mutex);
3879 	hhashp = HDL_HHASH(handle);
3880 	for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext)
3881 		if (hp->hdl.dma_handle == handle &&
3882 		    hp->type == BOFI_DMA_HDL)
3883 			break;
3884 	mutex_exit(&bofi_mutex);
3885 	mutex_exit(&bofi_low_mutex);
3886 	if (hp != hhashp) {
3887 		/*
3888 		 * yes - do we need to copy data from original
3889 		 */
3890 		if (bofi_sync_check && flags == DDI_DMA_SYNC_FORDEV)
3891 			if (hp->allocaddr)
3892 				xbcopy(hp->origaddr+off, hp->addr+off,
3893 				    len ? len : (hp->len - off));
3894 		/*
3895 		 * yes - check if we need to corrupt the data
3896 		 */
3897 		mutex_enter(&bofi_low_mutex);
3898 		mutex_enter(&bofi_mutex);
3899 		for (lp = hp->link; lp != NULL; lp = lp->link) {
3900 			ep = lp->errentp;
3901 			if ((((ep->errdef.access_type & BOFI_DMA_R) &&
3902 			    (flags == DDI_DMA_SYNC_FORCPU ||
3903 			    flags == DDI_DMA_SYNC_FORKERNEL)) ||
3904 			    ((ep->errdef.access_type & BOFI_DMA_W) &&
3905 			    (flags == DDI_DMA_SYNC_FORDEV))) &&
3906 			    (ep->state & BOFI_DEV_ACTIVE)) {
3907 				do_dma_corrupt(hp, ep, flags, off,
3908 				    len ? len : (hp->len - off));
3909 			}
3910 		}
3911 		mutex_exit(&bofi_mutex);
3912 		mutex_exit(&bofi_low_mutex);
3913 		/*
3914 		 *  do we need to copy data to original
3915 		 */
3916 		if (bofi_sync_check && (flags == DDI_DMA_SYNC_FORCPU ||
3917 		    flags == DDI_DMA_SYNC_FORKERNEL))
3918 			if (hp->allocaddr)
3919 				xbcopy(hp->addr+off, hp->origaddr+off,
3920 				    len ? len : (hp->len - off));
3921 	}
3922 	if (flags == DDI_DMA_SYNC_FORDEV)
3923 		/*
3924 		 * in this case get nexus driver to do sync last
3925 		 */
3926 		retval = save_bus_ops.bus_dma_flush(dip, rdip, handle, off,
3927 		    len, flags);
3928 	return (retval);
3929 }
3930 
3931 
3932 /*
3933  * our dma_win routine
3934  */
3935 static int
3936 bofi_dma_win(dev_info_t *dip, dev_info_t *rdip,
3937 	ddi_dma_handle_t handle, uint_t win, off_t *offp,
3938 	size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
3939 {
3940 	struct bofi_shadow *hp;
3941 	struct bofi_shadow *hhashp;
3942 	int retval;
3943 	ddi_dma_impl_t *mp;
3944 
3945 	/*
3946 	 * call nexus to do the real work
3947 	 */
3948 	retval = save_bus_ops.bus_dma_win(dip, rdip, handle, win, offp, lenp,
3949 	    cookiep, ccountp);
3950 	if (retval != DDI_SUCCESS)
3951 		return (retval);
3952 	/*
3953 	 * check we really have a shadow for this handle
3954 	 */
3955 	mutex_enter(&bofi_low_mutex);
3956 	mutex_enter(&bofi_mutex);
3957 	hhashp = HDL_HHASH(handle);
3958 	for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext)
3959 		if (hp->hdl.dma_handle == handle)
3960 			break;
3961 	if (hp != hhashp) {
3962 		/*
3963 		 * yes - make sure DMP_NOSYNC is unset
3964 		 */
3965 		mp = (ddi_dma_impl_t *)handle;
3966 		mp->dmai_rflags &= ~DMP_NOSYNC;
3967 	}
3968 	mutex_exit(&bofi_mutex);
3969 	mutex_exit(&bofi_low_mutex);
3970 	return (retval);
3971 }
3972 
3973 
3974 /*
3975  * our dma_ctl routine
3976  */
3977 static int
3978 bofi_dma_ctl(dev_info_t *dip, dev_info_t *rdip,
3979 		ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
3980 		off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
3981 {
3982 	struct bofi_link *lp, *next_lp;
3983 	struct bofi_errent *ep;
3984 	struct bofi_shadow *hp;
3985 	struct bofi_shadow *hhashp;
3986 	int retval;
3987 	int i;
3988 	struct bofi_shadow *dummyhp;
3989 	ddi_dma_impl_t *mp;
3990 
3991 	/*
3992 	 * get nexus to do real work
3993 	 */
3994 	retval = save_bus_ops.bus_dma_ctl(dip, rdip, handle, request, offp,
3995 	    lenp, objp, flags);
3996 	if (retval != DDI_SUCCESS)
3997 		return (retval);
3998 	/*
3999 	 * if driver_list is set, only intercept those drivers
4000 	 */
4001 	if (!driver_under_test(rdip))
4002 		return (DDI_SUCCESS);
4003 
4004 #if defined(__sparc)
4005 	/*
4006 	 * check if this is a dvma_reserve - that one's like a
4007 	 * dma_allochdl and needs to be handled separately
4008 	 */
4009 	if (request == DDI_DMA_RESERVE) {
4010 		bofi_dvma_reserve(rdip, *(ddi_dma_handle_t *)objp);
4011 		return (DDI_SUCCESS);
4012 	}
4013 #endif
4014 	/*
4015 	 * check we really have a shadow for this handle
4016 	 */
4017 	mutex_enter(&bofi_low_mutex);
4018 	mutex_enter(&bofi_mutex);
4019 	hhashp = HDL_HHASH(handle);
4020 	for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext)
4021 		if (hp->hdl.dma_handle == handle)
4022 			break;
4023 	if (hp == hhashp) {
4024 		mutex_exit(&bofi_mutex);
4025 		mutex_exit(&bofi_low_mutex);
4026 		return (retval);
4027 	}
4028 	/*
4029 	 * yes we have - see what kind of command this is
4030 	 */
4031 	switch (request) {
4032 	case DDI_DMA_RELEASE:
4033 		/*
4034 		 * dvma release - release dummy handle and all the index handles
4035 		 */
4036 		dummyhp = hp;
4037 		dummyhp->hnext->hprev = dummyhp->hprev;
4038 		dummyhp->hprev->hnext = dummyhp->hnext;
4039 		mutex_exit(&bofi_mutex);
4040 		mutex_exit(&bofi_low_mutex);
4041 		for (i = 0; i < dummyhp->len; i++) {
4042 			hp = dummyhp->hparrayp[i];
4043 			/*
4044 			 * chek none of the index handles were still loaded
4045 			 */
4046 			if (hp->type != BOFI_NULL)
4047 				panic("driver releasing loaded dvma");
4048 			/*
4049 			 * remove from dhash and inuse lists
4050 			 */
4051 			mutex_enter(&bofi_low_mutex);
4052 			mutex_enter(&bofi_mutex);
4053 			hp->dnext->dprev = hp->dprev;
4054 			hp->dprev->dnext = hp->dnext;
4055 			hp->next->prev = hp->prev;
4056 			hp->prev->next = hp->next;
4057 			mutex_exit(&bofi_mutex);
4058 			mutex_exit(&bofi_low_mutex);
4059 
4060 			if (bofi_sync_check && hp->allocaddr)
4061 				ddi_umem_free(hp->umem_cookie);
4062 			kmem_free(hp, sizeof (struct bofi_shadow));
4063 		}
4064 		kmem_free(dummyhp->hparrayp, dummyhp->len *
4065 		    sizeof (struct bofi_shadow *));
4066 		kmem_free(dummyhp, sizeof (struct bofi_shadow));
4067 		return (retval);
4068 	case DDI_DMA_FREE:
4069 		/*
4070 		 * ddi_dma_free case - remove from dhash, hhash and inuse lists
4071 		 */
4072 		hp->hnext->hprev = hp->hprev;
4073 		hp->hprev->hnext = hp->hnext;
4074 		hp->dnext->dprev = hp->dprev;
4075 		hp->dprev->dnext = hp->dnext;
4076 		hp->next->prev = hp->prev;
4077 		hp->prev->next = hp->next;
4078 		/*
4079 		 * free any errdef link structures tagged on to this
4080 		 * shadow handle
4081 		 */
4082 		for (lp = hp->link; lp != NULL; ) {
4083 			next_lp = lp->link;
4084 			/*
4085 			 * there is an implicit sync_for_cpu on free -
4086 			 * may need to corrupt
4087 			 */
4088 			ep = lp->errentp;
4089 			if ((ep->errdef.access_type & BOFI_DMA_R) &&
4090 			    (hp->flags & DDI_DMA_READ) &&
4091 			    (ep->state & BOFI_DEV_ACTIVE)) {
4092 				do_dma_corrupt(hp, ep, DDI_DMA_SYNC_FORCPU,
4093 				    0, hp->len);
4094 			}
4095 			lp->link = bofi_link_freelist;
4096 			bofi_link_freelist = lp;
4097 			lp = next_lp;
4098 		}
4099 		hp->link = NULL;
4100 		mutex_exit(&bofi_mutex);
4101 		mutex_exit(&bofi_low_mutex);
4102 
4103 		if (bofi_sync_check && (hp->flags & DDI_DMA_READ))
4104 			if (hp->allocaddr)
4105 				xbcopy(hp->addr, hp->origaddr, hp->len);
4106 		ddi_dmareq_mapout(hp->mapaddr, hp->len);
4107 		if (bofi_sync_check && hp->allocaddr)
4108 			ddi_umem_free(hp->umem_cookie);
4109 		kmem_free(hp, sizeof (struct bofi_shadow));
4110 		return (retval);
4111 	case DDI_DMA_MOVWIN:
4112 		mp = (ddi_dma_impl_t *)handle;
4113 		mp->dmai_rflags &= ~DMP_NOSYNC;
4114 		break;
4115 	case DDI_DMA_NEXTWIN:
4116 		mp = (ddi_dma_impl_t *)handle;
4117 		mp->dmai_rflags &= ~DMP_NOSYNC;
4118 		break;
4119 	default:
4120 		break;
4121 	}
4122 	mutex_exit(&bofi_mutex);
4123 	mutex_exit(&bofi_low_mutex);
4124 	return (retval);
4125 }
4126 
4127 #if defined(__sparc)
4128 /*
4129  * dvma reserve case from bofi_dma_ctl()
4130  */
4131 static void
4132 bofi_dvma_reserve(dev_info_t *rdip, ddi_dma_handle_t handle)
4133 {
4134 	struct bofi_shadow *hp;
4135 	struct bofi_shadow *dummyhp;
4136 	struct bofi_shadow *dhashp;
4137 	struct bofi_shadow *hhashp;
4138 	ddi_dma_impl_t *mp;
4139 	struct fast_dvma *nexus_private;
4140 	int i, count;
4141 
4142 	mp = (ddi_dma_impl_t *)handle;
4143 	count = mp->dmai_ndvmapages;
4144 	/*
4145 	 * allocate dummy shadow handle structure
4146 	 */
4147 	dummyhp = kmem_zalloc(sizeof (*dummyhp), KM_SLEEP);
4148 	if (mp->dmai_rflags & DMP_BYPASSNEXUS) {
4149 		/*
4150 		 * overlay our routines over the nexus's dvma routines
4151 		 */
4152 		nexus_private = (struct fast_dvma *)mp->dmai_nexus_private;
4153 		dummyhp->save.dvma_ops = *(nexus_private->ops);
4154 		nexus_private->ops = &bofi_dvma_ops;
4155 	}
4156 	/*
4157 	 * now fill in the dummy handle. This just gets put on hhash queue
4158 	 * so our dvma routines can find and index off to the handle they
4159 	 * really want.
4160 	 */
4161 	(void) strncpy(dummyhp->name, ddi_get_name(rdip), NAMESIZE);
4162 	dummyhp->instance = ddi_get_instance(rdip);
4163 	dummyhp->rnumber = -1;
4164 	dummyhp->dip = rdip;
4165 	dummyhp->len = count;
4166 	dummyhp->hdl.dma_handle = handle;
4167 	dummyhp->link = NULL;
4168 	dummyhp->type = BOFI_NULL;
4169 	/*
4170 	 * allocate space for real handles
4171 	 */
4172 	dummyhp->hparrayp = kmem_alloc(count *
4173 	    sizeof (struct bofi_shadow *), KM_SLEEP);
4174 	for (i = 0; i < count; i++) {
4175 		/*
4176 		 * allocate shadow handle structures and fill them in
4177 		 */
4178 		hp = kmem_zalloc(sizeof (*hp), KM_SLEEP);
4179 		(void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE);
4180 		hp->instance = ddi_get_instance(rdip);
4181 		hp->rnumber = -1;
4182 		hp->dip = rdip;
4183 		hp->hdl.dma_handle = 0;
4184 		hp->link = NULL;
4185 		hp->type = BOFI_NULL;
4186 		if (bofi_sync_check) {
4187 			unsigned long pagemask = ddi_ptob(rdip, 1) - 1;
4188 			/*
4189 			 * Take a copy and set this to be hp->addr
4190 			 * Data will be copied to and from the original on
4191 			 * explicit and implicit ddi_dma_sync()
4192 			 *
4193 			 * - maintain page alignment because some devices
4194 			 * assume it.
4195 			 */
4196 			hp->allocaddr = ddi_umem_alloc(
4197 			    ((int)(uintptr_t)hp->addr & pagemask)
4198 				+ pagemask + 1,
4199 			    KM_SLEEP, &hp->umem_cookie);
4200 			hp->addr = hp->allocaddr +
4201 			    ((int)(uintptr_t)hp->addr & pagemask);
4202 		}
4203 		/*
4204 		 * add to dhash and inuse lists.
4205 		 * these don't go on hhash queue.
4206 		 */
4207 		mutex_enter(&bofi_low_mutex);
4208 		mutex_enter(&bofi_mutex);
4209 		hp->next = shadow_list.next;
4210 		shadow_list.next->prev = hp;
4211 		hp->prev = &shadow_list;
4212 		shadow_list.next = hp;
4213 		dhashp = HDL_DHASH(hp->dip);
4214 		hp->dnext = dhashp->dnext;
4215 		dhashp->dnext->dprev = hp;
4216 		hp->dprev = dhashp;
4217 		dhashp->dnext = hp;
4218 		dummyhp->hparrayp[i] = hp;
4219 		mutex_exit(&bofi_mutex);
4220 		mutex_exit(&bofi_low_mutex);
4221 	}
4222 	/*
4223 	 * add dummy handle to hhash list only
4224 	 */
4225 	mutex_enter(&bofi_low_mutex);
4226 	mutex_enter(&bofi_mutex);
4227 	hhashp = HDL_HHASH(handle);
4228 	dummyhp->hnext = hhashp->hnext;
4229 	hhashp->hnext->hprev = dummyhp;
4230 	dummyhp->hprev = hhashp;
4231 	hhashp->hnext = dummyhp;
4232 	mutex_exit(&bofi_mutex);
4233 	mutex_exit(&bofi_low_mutex);
4234 }
4235 
4236 /*
4237  * our dvma_kaddr_load()
4238  */
4239 static void
4240 bofi_dvma_kaddr_load(ddi_dma_handle_t h, caddr_t a, uint_t len, uint_t index,
4241 	ddi_dma_cookie_t *cp)
4242 {
4243 	struct bofi_shadow *dummyhp;
4244 	struct bofi_shadow *hp;
4245 	struct bofi_shadow *hhashp;
4246 	struct bofi_errent *ep;
4247 	struct bofi_link   *lp;
4248 
4249 	/*
4250 	 * check we really have a dummy shadow for this handle
4251 	 */
4252 	mutex_enter(&bofi_low_mutex);
4253 	mutex_enter(&bofi_mutex);
4254 	hhashp = HDL_HHASH(h);
4255 	for (dummyhp = hhashp->hnext; dummyhp != hhashp;
4256 	    dummyhp = dummyhp->hnext)
4257 		if (dummyhp->hdl.dma_handle == h)
4258 			break;
4259 	mutex_exit(&bofi_mutex);
4260 	mutex_exit(&bofi_low_mutex);
4261 	if (dummyhp == hhashp) {
4262 		/*
4263 		 * no dummy shadow - panic
4264 		 */
4265 		panic("driver dvma_kaddr_load with no reserve");
4266 	}
4267 
4268 	/*
4269 	 * find real hp
4270 	 */
4271 	hp = dummyhp->hparrayp[index];
4272 	/*
4273 	 * check its not already loaded
4274 	 */
4275 	if (hp->type != BOFI_NULL)
4276 		panic("driver loading loaded dvma");
4277 	/*
4278 	 * if were doing copying, just need to change origaddr and get
4279 	 * nexus to map hp->addr again
4280 	 * if not, set hp->addr to new address.
4281 	 * - note these are always kernel virtual addresses - no need to map
4282 	 */
4283 	if (bofi_sync_check && hp->allocaddr) {
4284 		hp->origaddr = a;
4285 		a = hp->addr;
4286 	} else
4287 		hp->addr = a;
4288 	hp->len = len;
4289 	/*
4290 	 * get nexus to do the real work
4291 	 */
4292 	dummyhp->save.dvma_ops.dvma_kaddr_load(h, a, len, index, cp);
4293 	/*
4294 	 * chain on any pre-existing errdefs that apply to this dma_handle
4295 	 * no need to corrupt - there's no implicit dma_sync on this one
4296 	 */
4297 	mutex_enter(&bofi_low_mutex);
4298 	mutex_enter(&bofi_mutex);
4299 	hp->type = BOFI_DMA_HDL;
4300 	for (ep = errent_listp; ep != NULL; ep = ep->next) {
4301 		if (ddi_name_to_major(hp->name) ==
4302 		    ddi_name_to_major(ep->name) &&
4303 		    hp->instance == ep->errdef.instance &&
4304 		    (ep->errdef.rnumber == -1 ||
4305 		    hp->rnumber == ep->errdef.rnumber) &&
4306 		    ((ep->errdef.access_type & BOFI_DMA_RW) &&
4307 		    (((uintptr_t)(hp->addr + ep->errdef.offset +
4308 		    ep->errdef.len) & ~LLSZMASK) >
4309 		    ((uintptr_t)((hp->addr + ep->errdef.offset) +
4310 		    LLSZMASK) & ~LLSZMASK)))) {
4311 			lp = bofi_link_freelist;
4312 			if (lp != NULL) {
4313 				bofi_link_freelist = lp->link;
4314 				lp->errentp = ep;
4315 				lp->link = hp->link;
4316 				hp->link = lp;
4317 			}
4318 		}
4319 	}
4320 	mutex_exit(&bofi_mutex);
4321 	mutex_exit(&bofi_low_mutex);
4322 }
4323 
4324 /*
4325  * our dvma_unload()
4326  */
4327 static void
4328 bofi_dvma_unload(ddi_dma_handle_t h, uint_t index, uint_t view)
4329 {
4330 	struct bofi_link *lp, *next_lp;
4331 	struct bofi_errent *ep;
4332 	struct bofi_shadow *dummyhp;
4333 	struct bofi_shadow *hp;
4334 	struct bofi_shadow *hhashp;
4335 
4336 	/*
4337 	 * check we really have a dummy shadow for this handle
4338 	 */
4339 	mutex_enter(&bofi_low_mutex);
4340 	mutex_enter(&bofi_mutex);
4341 	hhashp = HDL_HHASH(h);
4342 	for (dummyhp = hhashp->hnext; dummyhp != hhashp;
4343 	    dummyhp = dummyhp->hnext)
4344 		if (dummyhp->hdl.dma_handle == h)
4345 			break;
4346 	mutex_exit(&bofi_mutex);
4347 	mutex_exit(&bofi_low_mutex);
4348 	if (dummyhp == hhashp) {
4349 		/*
4350 		 * no dummy shadow - panic
4351 		 */
4352 		panic("driver dvma_unload with no reserve");
4353 	}
4354 	dummyhp->save.dvma_ops.dvma_unload(h, index, view);
4355 	/*
4356 	 * find real hp
4357 	 */
4358 	hp = dummyhp->hparrayp[index];
4359 	/*
4360 	 * check its not already unloaded
4361 	 */
4362 	if (hp->type == BOFI_NULL)
4363 		panic("driver unloading unloaded dvma");
4364 	/*
4365 	 * free any errdef link structures tagged on to this
4366 	 * shadow handle - do corruption if necessary
4367 	 */
4368 	mutex_enter(&bofi_low_mutex);
4369 	mutex_enter(&bofi_mutex);
4370 	for (lp = hp->link; lp != NULL; ) {
4371 		next_lp = lp->link;
4372 		ep = lp->errentp;
4373 		if ((ep->errdef.access_type & BOFI_DMA_R) &&
4374 		    (view == DDI_DMA_SYNC_FORCPU ||
4375 		    view == DDI_DMA_SYNC_FORKERNEL) &&
4376 		    (ep->state & BOFI_DEV_ACTIVE)) {
4377 			do_dma_corrupt(hp, ep, view, 0, hp->len);
4378 		}
4379 		lp->link = bofi_link_freelist;
4380 		bofi_link_freelist = lp;
4381 		lp = next_lp;
4382 	}
4383 	hp->link = NULL;
4384 	hp->type = BOFI_NULL;
4385 	mutex_exit(&bofi_mutex);
4386 	mutex_exit(&bofi_low_mutex);
4387 	/*
4388 	 * if there is an explicit sync_for_cpu, then do copy to original
4389 	 */
4390 	if (bofi_sync_check &&
4391 	    (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL))
4392 		if (hp->allocaddr)
4393 			xbcopy(hp->addr, hp->origaddr, hp->len);
4394 }
4395 
4396 /*
4397  * our dvma_unload()
4398  */
4399 static void
4400 bofi_dvma_sync(ddi_dma_handle_t h, uint_t index, uint_t view)
4401 {
4402 	struct bofi_link *lp;
4403 	struct bofi_errent *ep;
4404 	struct bofi_shadow *hp;
4405 	struct bofi_shadow *dummyhp;
4406 	struct bofi_shadow *hhashp;
4407 
4408 	/*
4409 	 * check we really have a dummy shadow for this handle
4410 	 */
4411 	mutex_enter(&bofi_low_mutex);
4412 	mutex_enter(&bofi_mutex);
4413 	hhashp = HDL_HHASH(h);
4414 	for (dummyhp = hhashp->hnext; dummyhp != hhashp;
4415 	    dummyhp = dummyhp->hnext)
4416 		if (dummyhp->hdl.dma_handle == h)
4417 			break;
4418 	mutex_exit(&bofi_mutex);
4419 	mutex_exit(&bofi_low_mutex);
4420 	if (dummyhp == hhashp) {
4421 		/*
4422 		 * no dummy shadow - panic
4423 		 */
4424 		panic("driver dvma_sync with no reserve");
4425 	}
4426 	/*
4427 	 * find real hp
4428 	 */
4429 	hp = dummyhp->hparrayp[index];
4430 	/*
4431 	 * check its already loaded
4432 	 */
4433 	if (hp->type == BOFI_NULL)
4434 		panic("driver syncing unloaded dvma");
4435 	if (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL)
4436 		/*
4437 		 * in this case do sync first
4438 		 */
4439 		dummyhp->save.dvma_ops.dvma_sync(h, index, view);
4440 	/*
4441 	 * if there is an explicit sync_for_dev, then do copy from original
4442 	 */
4443 	if (bofi_sync_check && view == DDI_DMA_SYNC_FORDEV) {
4444 		if (hp->allocaddr)
4445 			xbcopy(hp->origaddr, hp->addr, hp->len);
4446 	}
4447 	/*
4448 	 * do corruption if necessary
4449 	 */
4450 	mutex_enter(&bofi_low_mutex);
4451 	mutex_enter(&bofi_mutex);
4452 	for (lp = hp->link; lp != NULL; lp = lp->link) {
4453 		ep = lp->errentp;
4454 		if ((((ep->errdef.access_type & BOFI_DMA_R) &&
4455 		    (view == DDI_DMA_SYNC_FORCPU ||
4456 		    view == DDI_DMA_SYNC_FORKERNEL)) ||
4457 		    ((ep->errdef.access_type & BOFI_DMA_W) &&
4458 		    (view == DDI_DMA_SYNC_FORDEV))) &&
4459 		    (ep->state & BOFI_DEV_ACTIVE)) {
4460 			do_dma_corrupt(hp, ep, view, 0, hp->len);
4461 		}
4462 	}
4463 	mutex_exit(&bofi_mutex);
4464 	mutex_exit(&bofi_low_mutex);
4465 	/*
4466 	 * if there is an explicit sync_for_cpu, then do copy to original
4467 	 */
4468 	if (bofi_sync_check &&
4469 	    (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL)) {
4470 		if (hp->allocaddr)
4471 			xbcopy(hp->addr, hp->origaddr, hp->len);
4472 	}
4473 	if (view == DDI_DMA_SYNC_FORDEV)
4474 		/*
4475 		 * in this case do sync last
4476 		 */
4477 		dummyhp->save.dvma_ops.dvma_sync(h, index, view);
4478 }
4479 #endif
4480 
4481 /*
4482  * bofi intercept routine - gets called instead of users interrupt routine
4483  */
4484 static uint_t
4485 bofi_intercept_intr(caddr_t xp)
4486 {
4487 	struct bofi_errent *ep;
4488 	struct bofi_link   *lp;
4489 	struct bofi_shadow *hp;
4490 	int intr_count = 1;
4491 	int i;
4492 	uint_t retval = DDI_INTR_UNCLAIMED;
4493 	uint_t result;
4494 	int unclaimed_counter = 0;
4495 	int jabber_detected = 0;
4496 
4497 	hp = (struct bofi_shadow *)xp;
4498 	/*
4499 	 * check if nothing to do
4500 	 */
4501 	if (hp->link == NULL)
4502 		return (hp->save.intr.int_handler
4503 		    (hp->save.intr.int_handler_arg1, NULL));
4504 	mutex_enter(&bofi_mutex);
4505 	/*
4506 	 * look for any errdefs
4507 	 */
4508 	for (lp = hp->link; lp != NULL; lp = lp->link) {
4509 		ep = lp->errentp;
4510 		if (ep->state & BOFI_DEV_ACTIVE) {
4511 			/*
4512 			 * got one
4513 			 */
4514 			if ((ep->errdef.access_count ||
4515 			    ep->errdef.fail_count) &&
4516 			    (ep->errdef.access_type & BOFI_LOG))
4517 				log_acc_event(ep, BOFI_INTR, 0, 0, 1, 0);
4518 			if (ep->errdef.access_count > 1) {
4519 				ep->errdef.access_count--;
4520 			} else if (ep->errdef.fail_count > 0) {
4521 				ep->errdef.fail_count--;
4522 				ep->errdef.access_count = 0;
4523 				/*
4524 				 * OK do "corruption"
4525 				 */
4526 				if (ep->errstate.fail_time == 0)
4527 					ep->errstate.fail_time = bofi_gettime();
4528 				switch (ep->errdef.optype) {
4529 				case BOFI_DELAY_INTR:
4530 					if (!hp->hilevel) {
4531 						drv_usecwait
4532 						    (ep->errdef.operand);
4533 					}
4534 					break;
4535 				case BOFI_LOSE_INTR:
4536 					intr_count = 0;
4537 					break;
4538 				case BOFI_EXTRA_INTR:
4539 					intr_count += ep->errdef.operand;
4540 					break;
4541 				default:
4542 					break;
4543 				}
4544 			}
4545 		}
4546 	}
4547 	mutex_exit(&bofi_mutex);
4548 	/*
4549 	 * send extra or fewer interrupts as requested
4550 	 */
4551 	for (i = 0; i < intr_count; i++) {
4552 		result = hp->save.intr.int_handler
4553 		    (hp->save.intr.int_handler_arg1, NULL);
4554 		if (result == DDI_INTR_CLAIMED)
4555 			unclaimed_counter >>= 1;
4556 		else if (++unclaimed_counter >= 20)
4557 			jabber_detected = 1;
4558 		if (i == 0)
4559 			retval = result;
4560 	}
4561 	/*
4562 	 * if more than 1000 spurious interrupts requested and
4563 	 * jabber not detected - give warning
4564 	 */
4565 	if (intr_count > 1000 && !jabber_detected)
4566 		panic("undetected interrupt jabber: %s%d",
4567 		    hp->name, hp->instance);
4568 	/*
4569 	 * return first response - or "unclaimed" if none
4570 	 */
4571 	return (retval);
4572 }
4573 
4574 
4575 /*
4576  * our ddi_check_acc_hdl
4577  */
4578 /* ARGSUSED */
4579 static int
4580 bofi_check_acc_hdl(ddi_acc_impl_t *handle)
4581 {
4582 	struct bofi_shadow *hp;
4583 	struct bofi_link   *lp;
4584 	uint_t result = 0;
4585 
4586 	hp = handle->ahi_common.ah_bus_private;
4587 	if (!hp->link || !mutex_tryenter(&bofi_mutex)) {
4588 		return (0);
4589 	}
4590 	for (lp = hp->link; lp != NULL; lp = lp->link) {
4591 		/*
4592 		 * OR in error state from all associated
4593 		 * errdef structures
4594 		 */
4595 		if (lp->errentp->errdef.access_count == 0 &&
4596 		    (lp->errentp->state & BOFI_DEV_ACTIVE)) {
4597 			result = (lp->errentp->errdef.acc_chk & 1);
4598 		}
4599 	}
4600 	mutex_exit(&bofi_mutex);
4601 	return (result);
4602 }
4603 
4604 /*
4605  * our ddi_check_dma_hdl
4606  */
4607 /* ARGSUSED */
4608 static int
4609 bofi_check_dma_hdl(ddi_dma_impl_t *handle)
4610 {
4611 	struct bofi_shadow *hp;
4612 	struct bofi_link   *lp;
4613 	struct bofi_shadow *hhashp;
4614 	uint_t result = 0;
4615 
4616 	if (!mutex_tryenter(&bofi_mutex)) {
4617 		return (0);
4618 	}
4619 	hhashp = HDL_HHASH(handle);
4620 	for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext)
4621 		if (hp->hdl.dma_handle == (ddi_dma_handle_t)handle)
4622 			break;
4623 	if (hp == hhashp) {
4624 		mutex_exit(&bofi_mutex);
4625 		return (0);
4626 	}
4627 	if (!hp->link) {
4628 		mutex_exit(&bofi_mutex);
4629 		return (0);
4630 	}
4631 	for (lp = hp->link; lp != NULL; lp = lp->link) {
4632 		/*
4633 		 * OR in error state from all associated
4634 		 * errdef structures
4635 		 */
4636 		if (lp->errentp->errdef.access_count == 0 &&
4637 		    (lp->errentp->state & BOFI_DEV_ACTIVE)) {
4638 			result = ((lp->errentp->errdef.acc_chk & 2) ? 1 : 0);
4639 		}
4640 	}
4641 	mutex_exit(&bofi_mutex);
4642 	return (result);
4643 }
4644 
4645 
4646 /* ARGSUSED */
4647 static int
4648 bofi_post_event(dev_info_t *dip, dev_info_t *rdip,
4649 		    ddi_eventcookie_t eventhdl, void *impl_data)
4650 {
4651 	ddi_eventcookie_t ec;
4652 	struct ddi_fault_event_data *arg;
4653 	struct bofi_errent *ep;
4654 	struct bofi_shadow *hp;
4655 	struct bofi_shadow *dhashp;
4656 	struct bofi_link   *lp;
4657 
4658 	ASSERT(eventhdl);
4659 	if (ddi_get_eventcookie(dip, DDI_DEVI_FAULT_EVENT, &ec) != DDI_SUCCESS)
4660 		return (DDI_FAILURE);
4661 
4662 	if (ec != eventhdl)
4663 		return (save_bus_ops.bus_post_event(dip, rdip, eventhdl,
4664 		    impl_data));
4665 
4666 	arg = (struct ddi_fault_event_data *)impl_data;
4667 	mutex_enter(&bofi_mutex);
4668 	/*
4669 	 * find shadow handles with appropriate dev_infos
4670 	 * and set error reported on all associated errdef structures
4671 	 */
4672 	dhashp = HDL_DHASH(arg->f_dip);
4673 	for (hp = dhashp->dnext; hp != dhashp; hp = hp->dnext) {
4674 		if (hp->dip == arg->f_dip) {
4675 			for (lp = hp->link; lp != NULL; lp = lp->link) {
4676 				ep = lp->errentp;
4677 				ep->errstate.errmsg_count++;
4678 				if ((ep->errstate.msg_time == NULL ||
4679 				    ep->errstate.severity > arg->f_impact) &&
4680 				    (ep->state & BOFI_DEV_ACTIVE)) {
4681 					ep->errstate.msg_time = bofi_gettime();
4682 					ep->errstate.severity = arg->f_impact;
4683 					(void) strncpy(ep->errstate.buffer,
4684 					    arg->f_message, ERRMSGSIZE);
4685 					ddi_trigger_softintr(ep->softintr_id);
4686 				}
4687 			}
4688 		}
4689 	}
4690 	mutex_exit(&bofi_mutex);
4691 	return (save_bus_ops.bus_post_event(dip, rdip, eventhdl, impl_data));
4692 }
4693 
4694 /*ARGSUSED*/
4695 static int
4696 bofi_fm_ereport_callback(sysevent_t *ev, void *cookie)
4697 {
4698 	char *class = "";
4699 	char *path = "";
4700 	char *ptr;
4701 	nvlist_t *nvlist;
4702 	nvlist_t *detector;
4703 	ddi_fault_impact_t impact;
4704 	struct bofi_errent *ep;
4705 	struct bofi_shadow *hp;
4706 	struct bofi_link   *lp;
4707 	char service_class[FM_MAX_CLASS];
4708 	char hppath[MAXPATHLEN];
4709 	int service_ereport = 0;
4710 
4711 	(void) sysevent_get_attr_list(ev, &nvlist);
4712 	(void) nvlist_lookup_string(nvlist, FM_CLASS, &class);
4713 	if (nvlist_lookup_nvlist(nvlist, FM_EREPORT_DETECTOR, &detector) == 0)
4714 		(void) nvlist_lookup_string(detector, FM_FMRI_DEV_PATH, &path);
4715 
4716 	(void) snprintf(service_class, FM_MAX_CLASS, "%s.%s.%s.",
4717 	    FM_EREPORT_CLASS, DDI_IO_CLASS, DDI_FM_SERVICE_IMPACT);
4718 	if (strncmp(class, service_class, strlen(service_class) - 1) == 0)
4719 		service_ereport = 1;
4720 
4721 	mutex_enter(&bofi_mutex);
4722 	/*
4723 	 * find shadow handles with appropriate dev_infos
4724 	 * and set error reported on all associated errdef structures
4725 	 */
4726 	for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) {
4727 		(void) ddi_pathname(hp->dip, hppath);
4728 		if (strcmp(path, hppath) != 0)
4729 			continue;
4730 		for (lp = hp->link; lp != NULL; lp = lp->link) {
4731 			ep = lp->errentp;
4732 			ep->errstate.errmsg_count++;
4733 			if (!(ep->state & BOFI_DEV_ACTIVE))
4734 				continue;
4735 			if (ep->errstate.msg_time != NULL)
4736 				continue;
4737 			if (service_ereport) {
4738 				ptr = class + strlen(service_class);
4739 				if (strcmp(ptr, DDI_FM_SERVICE_LOST) == 0)
4740 					impact = DDI_SERVICE_LOST;
4741 				else if (strcmp(ptr,
4742 				    DDI_FM_SERVICE_DEGRADED) == 0)
4743 					impact = DDI_SERVICE_DEGRADED;
4744 				else if (strcmp(ptr,
4745 				    DDI_FM_SERVICE_RESTORED) == 0)
4746 					impact = DDI_SERVICE_RESTORED;
4747 				else
4748 					impact = DDI_SERVICE_UNAFFECTED;
4749 				if (ep->errstate.severity > impact)
4750 					ep->errstate.severity = impact;
4751 			} else if (ep->errstate.buffer[0] == '\0') {
4752 				(void) strncpy(ep->errstate.buffer, class,
4753 				    ERRMSGSIZE);
4754 			}
4755 			if (ep->errstate.buffer[0] != '\0' &&
4756 			    ep->errstate.severity < DDI_SERVICE_RESTORED) {
4757 				ep->errstate.msg_time = bofi_gettime();
4758 				ddi_trigger_softintr(ep->softintr_id);
4759 			}
4760 		}
4761 	}
4762 	nvlist_free(nvlist);
4763 	mutex_exit(&bofi_mutex);
4764 	return (0);
4765 }
4766 
4767 /*
4768  * our intr_ops routine
4769  */
4770 static int
4771 bofi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
4772     ddi_intr_handle_impl_t *hdlp, void *result)
4773 {
4774 	int retval;
4775 	struct bofi_shadow *hp;
4776 	struct bofi_shadow *dhashp;
4777 	struct bofi_shadow *hhashp;
4778 	struct bofi_errent *ep;
4779 	struct bofi_link   *lp, *next_lp;
4780 
4781 	switch (intr_op) {
4782 	case DDI_INTROP_ADDISR:
4783 		/*
4784 		 * if driver_list is set, only intercept those drivers
4785 		 */
4786 		if (!driver_under_test(rdip))
4787 			return (save_bus_ops.bus_intr_op(dip, rdip,
4788 			    intr_op, hdlp, result));
4789 		/*
4790 		 * allocate shadow handle structure and fill in
4791 		 */
4792 		hp = kmem_zalloc(sizeof (struct bofi_shadow), KM_SLEEP);
4793 		(void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE);
4794 		hp->instance = ddi_get_instance(rdip);
4795 		hp->save.intr.int_handler = hdlp->ih_cb_func;
4796 		hp->save.intr.int_handler_arg1 = hdlp->ih_cb_arg1;
4797 		hdlp->ih_cb_func = (ddi_intr_handler_t *)bofi_intercept_intr;
4798 		hdlp->ih_cb_arg1 = (caddr_t)hp;
4799 		hp->bofi_inum = hdlp->ih_inum;
4800 		hp->dip = rdip;
4801 		hp->link = NULL;
4802 		hp->type = BOFI_INT_HDL;
4803 		/*
4804 		 * save whether hilevel or not
4805 		 */
4806 
4807 		if (hdlp->ih_pri >= ddi_intr_get_hilevel_pri())
4808 			hp->hilevel = 1;
4809 		else
4810 			hp->hilevel = 0;
4811 
4812 		/*
4813 		 * call nexus to do real work, but specifying our handler, and
4814 		 * our shadow handle as argument
4815 		 */
4816 		retval = save_bus_ops.bus_intr_op(dip, rdip,
4817 		    intr_op, hdlp, result);
4818 		if (retval != DDI_SUCCESS) {
4819 			kmem_free(hp, sizeof (struct bofi_shadow));
4820 			return (retval);
4821 		}
4822 		/*
4823 		 * add to dhash, hhash and inuse lists
4824 		 */
4825 		mutex_enter(&bofi_low_mutex);
4826 		mutex_enter(&bofi_mutex);
4827 		hp->next = shadow_list.next;
4828 		shadow_list.next->prev = hp;
4829 		hp->prev = &shadow_list;
4830 		shadow_list.next = hp;
4831 		hhashp = HDL_HHASH(hdlp->ih_inum);
4832 		hp->hnext = hhashp->hnext;
4833 		hhashp->hnext->hprev = hp;
4834 		hp->hprev = hhashp;
4835 		hhashp->hnext = hp;
4836 		dhashp = HDL_DHASH(hp->dip);
4837 		hp->dnext = dhashp->dnext;
4838 		dhashp->dnext->dprev = hp;
4839 		hp->dprev = dhashp;
4840 		dhashp->dnext = hp;
4841 		/*
4842 		 * chain on any pre-existing errdefs that apply to this
4843 		 * acc_handle
4844 		 */
4845 		for (ep = errent_listp; ep != NULL; ep = ep->next) {
4846 			if (ddi_name_to_major(hp->name) ==
4847 			    ddi_name_to_major(ep->name) &&
4848 			    hp->instance == ep->errdef.instance &&
4849 			    (ep->errdef.access_type & BOFI_INTR)) {
4850 				lp = bofi_link_freelist;
4851 				if (lp != NULL) {
4852 					bofi_link_freelist = lp->link;
4853 					lp->errentp = ep;
4854 					lp->link = hp->link;
4855 					hp->link = lp;
4856 				}
4857 			}
4858 		}
4859 		mutex_exit(&bofi_mutex);
4860 		mutex_exit(&bofi_low_mutex);
4861 		return (retval);
4862 	case DDI_INTROP_REMISR:
4863 		/*
4864 		 * call nexus routine first
4865 		 */
4866 		retval = save_bus_ops.bus_intr_op(dip, rdip,
4867 		    intr_op, hdlp, result);
4868 		/*
4869 		 * find shadow handle
4870 		 */
4871 		mutex_enter(&bofi_low_mutex);
4872 		mutex_enter(&bofi_mutex);
4873 		hhashp = HDL_HHASH(hdlp->ih_inum);
4874 		for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) {
4875 			if (hp->dip == rdip &&
4876 			    hp->type == BOFI_INT_HDL &&
4877 			    hp->bofi_inum == hdlp->ih_inum) {
4878 				break;
4879 			}
4880 		}
4881 		if (hp == hhashp) {
4882 			mutex_exit(&bofi_mutex);
4883 			mutex_exit(&bofi_low_mutex);
4884 			return (retval);
4885 		}
4886 		/*
4887 		 * found one - remove from dhash, hhash and inuse lists
4888 		 */
4889 		hp->hnext->hprev = hp->hprev;
4890 		hp->hprev->hnext = hp->hnext;
4891 		hp->dnext->dprev = hp->dprev;
4892 		hp->dprev->dnext = hp->dnext;
4893 		hp->next->prev = hp->prev;
4894 		hp->prev->next = hp->next;
4895 		/*
4896 		 * free any errdef link structures
4897 		 * tagged on to this shadow handle
4898 		 */
4899 		for (lp = hp->link; lp != NULL; ) {
4900 			next_lp = lp->link;
4901 			lp->link = bofi_link_freelist;
4902 			bofi_link_freelist = lp;
4903 			lp = next_lp;
4904 		}
4905 		hp->link = NULL;
4906 		mutex_exit(&bofi_mutex);
4907 		mutex_exit(&bofi_low_mutex);
4908 		kmem_free(hp, sizeof (struct bofi_shadow));
4909 		return (retval);
4910 	default:
4911 		return (save_bus_ops.bus_intr_op(dip, rdip,
4912 		    intr_op, hdlp, result));
4913 	}
4914 }
4915