Home | History | Annotate | Download | only in io
      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 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 #include <sys/types.h>
     28 #include <sys/sysmacros.h>
     29 #include <sys/buf.h>
     30 #include <sys/errno.h>
     31 #include <sys/modctl.h>
     32 #include <sys/conf.h>
     33 #include <sys/stat.h>
     34 #include <sys/kmem.h>
     35 #include <sys/proc.h>
     36 #include <sys/cpuvar.h>
     37 #include <sys/ddi_impldefs.h>
     38 #include <sys/ddi.h>
     39 #include <sys/fm/protocol.h>
     40 #include <sys/fm/util.h>
     41 #include <sys/fm/io/ddi.h>
     42 #include <sys/sysevent/eventdefs.h>
     43 #include <sys/sunddi.h>
     44 #include <sys/sunndi.h>
     45 #include <sys/debug.h>
     46 #include <sys/bofi.h>
     47 #include <sys/dvma.h>
     48 #include <sys/bofi_impl.h>
     49 
     50 /*
     51  * Testing the resilience of a hardened device driver requires a suitably wide
     52  * range of different types of "typical" hardware faults to be injected,
     53  * preferably in a controlled and repeatable fashion. This is not in general
     54  * possible via hardware, so the "fault injection test harness" is provided.
     55  * This works by intercepting calls from the driver to various DDI routines,
     56  * and then corrupting the result of those DDI routine calls as if the
     57  * hardware had caused the corruption.
     58  *
     59  * Conceptually, the bofi driver consists of two parts:
     60  *
     61  * A driver interface that supports a number of ioctls which allow error
     62  * definitions ("errdefs") to be defined and subsequently managed. The
     63  * driver is a clone driver, so each open will create a separate
     64  * invocation. Any errdefs created by using ioctls to that invocation
     65  * will automatically be deleted when that invocation is closed.
     66  *
     67  * Intercept routines: When the bofi driver is attached, it edits the
     68  * bus_ops structure of the bus nexus specified by the "bofi-nexus"
     69  * field in the "bofi.conf" file, thus allowing the
     70  * bofi driver to intercept various ddi functions. These intercept
     71  * routines primarily carry out fault injections based on the errdefs
     72  * created for that device.
     73  *
     74  * Faults can be injected into:
     75  *
     76  * DMA (corrupting data for DMA to/from memory areas defined by
     77  * ddi_dma_setup(), ddi_dma_bind_handle(), etc)
     78  *
     79  * Physical IO (corrupting data sent/received via ddi_get8(), ddi_put8(),
     80  * etc),
     81  *
     82  * Interrupts (generating spurious interrupts, losing interrupts,
     83  * delaying interrupts).
     84  *
     85  * By default, ddi routines called from all drivers will be intercepted
     86  * and faults potentially injected. However, the "bofi-to-test" field in
     87  * the "bofi.conf" file can be set to a space-separated list of drivers to
     88  * test (or by preceding each driver name in the list with an "!", a list
     89  * of drivers not to test).
     90  *
     91  * In addition to fault injection, the bofi driver does a number of static
     92  * checks which are controlled by properties in the "bofi.conf" file.
     93  *
     94  * "bofi-ddi-check" - if set will validate that there are no PIO access
     95  * other than those using the DDI routines (ddi_get8(), ddi_put8(), etc).
     96  *
     97  * "bofi-range-check" - if set to values 1 (warning) or 2 (panic), will
     98  * validate that calls to ddi_get8(), ddi_put8(), etc are not made
     99  * specifying addresses outside the range of the access_handle.
    100  *
    101  * "bofi-sync-check" - if set will validate that calls to ddi_dma_sync()
    102  * are being made correctly.
    103  */
    104 
    105 extern void *bp_mapin_common(struct buf *, int);
    106 
    107 static int bofi_ddi_check;
    108 static int bofi_sync_check;
    109 static int bofi_range_check;
    110 
    111 static struct bofi_link bofi_link_array[BOFI_NLINKS], *bofi_link_freelist;
    112 
    113 #define	LLSZMASK (sizeof (uint64_t)-1)
    114 
    115 #define	HDL_HASH_TBL_SIZE 64
    116 static struct bofi_shadow hhash_table[HDL_HASH_TBL_SIZE];
    117 static struct bofi_shadow dhash_table[HDL_HASH_TBL_SIZE];
    118 #define	HDL_DHASH(x) \
    119 	(&dhash_table[((uintptr_t)(x) >> 3) & (HDL_HASH_TBL_SIZE-1)])
    120 #define	HDL_HHASH(x) \
    121 	(&hhash_table[((uintptr_t)(x) >> 5) & (HDL_HASH_TBL_SIZE-1)])
    122 
    123 static struct bofi_shadow shadow_list;
    124 static struct bofi_errent *errent_listp;
    125 
    126 static char driver_list[NAMESIZE];
    127 static int driver_list_size;
    128 static int driver_list_neg;
    129 static char nexus_name[NAMESIZE];
    130 
    131 static int initialized = 0;
    132 
    133 #define	NCLONES 2560
    134 static int clone_tab[NCLONES];
    135 
    136 static dev_info_t *our_dip;
    137 
    138 static kmutex_t bofi_mutex;
    139 static kmutex_t clone_tab_mutex;
    140 static kmutex_t bofi_low_mutex;
    141 static ddi_iblock_cookie_t bofi_low_cookie;
    142 static uint_t	bofi_signal(caddr_t arg);
    143 static int	bofi_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
    144 static int	bofi_attach(dev_info_t *, ddi_attach_cmd_t);
    145 static int	bofi_detach(dev_info_t *, ddi_detach_cmd_t);
    146 static int	bofi_open(dev_t *, int, int, cred_t *);
    147 static int	bofi_close(dev_t, int, int, cred_t *);
    148 static int	bofi_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
    149 static int	bofi_errdef_alloc(struct bofi_errdef *, char *,
    150 		    struct bofi_errent *);
    151 static int	bofi_errdef_free(struct bofi_errent *);
    152 static void	bofi_start(struct bofi_errctl *, char *);
    153 static void	bofi_stop(struct bofi_errctl *, char *);
    154 static void	bofi_broadcast(struct bofi_errctl *, char *);
    155 static void	bofi_clear_acc_chk(struct bofi_errctl *, char *);
    156 static void	bofi_clear_errors(struct bofi_errctl *, char *);
    157 static void	bofi_clear_errdefs(struct bofi_errctl *, char *);
    158 static int	bofi_errdef_check(struct bofi_errstate *,
    159 		    struct acc_log_elem **);
    160 static int	bofi_errdef_check_w(struct bofi_errstate *,
    161 		    struct acc_log_elem **);
    162 static int	bofi_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
    163 		    off_t, off_t, caddr_t *);
    164 static int	bofi_dma_map(dev_info_t *, dev_info_t *,
    165 		    struct ddi_dma_req *, ddi_dma_handle_t *);
    166 static int	bofi_dma_allochdl(dev_info_t *, dev_info_t *,
    167 		    ddi_dma_attr_t *, int (*)(caddr_t), caddr_t,
    168 		    ddi_dma_handle_t *);
    169 static int	bofi_dma_freehdl(dev_info_t *, dev_info_t *,
    170 		    ddi_dma_handle_t);
    171 static int	bofi_dma_bindhdl(dev_info_t *, dev_info_t *,
    172 		    ddi_dma_handle_t, struct ddi_dma_req *, ddi_dma_cookie_t *,
    173 		    uint_t *);
    174 static int	bofi_dma_unbindhdl(dev_info_t *, dev_info_t *,
    175 		    ddi_dma_handle_t);
    176 static int	bofi_dma_flush(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
    177 		    off_t, size_t, uint_t);
    178 static int	bofi_dma_ctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
    179 		    enum ddi_dma_ctlops, off_t *, size_t *, caddr_t *, uint_t);
    180 static int	bofi_dma_win(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
    181 		    uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *);
    182 static int	bofi_intr_ops(dev_info_t *dip, dev_info_t *rdip,
    183 		    ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp,
    184 		    void *result);
    185 static int	bofi_fm_ereport_callback(sysevent_t *ev, void *cookie);
    186 
    187 evchan_t *bofi_error_chan;
    188 
    189 #define	FM_SIMULATED_DMA "simulated.dma"
    190 #define	FM_SIMULATED_PIO "simulated.pio"
    191 
    192 #if defined(__sparc)
    193 static void	bofi_dvma_kaddr_load(ddi_dma_handle_t, caddr_t, uint_t,
    194 		    uint_t, ddi_dma_cookie_t *);
    195 static void	bofi_dvma_unload(ddi_dma_handle_t, uint_t, uint_t);
    196 static void	bofi_dvma_sync(ddi_dma_handle_t, uint_t, uint_t);
    197 static void	bofi_dvma_reserve(dev_info_t *, ddi_dma_handle_t);
    198 #endif
    199 static int	driver_under_test(dev_info_t *);
    200 static int	bofi_check_acc_hdl(ddi_acc_impl_t *);
    201 static int	bofi_check_dma_hdl(ddi_dma_impl_t *);
    202 static int	bofi_post_event(dev_info_t *dip, dev_info_t *rdip,
    203 		    ddi_eventcookie_t eventhdl, void *impl_data);
    204 
    205 static struct bus_ops bofi_bus_ops = {
    206 	BUSO_REV,
    207 	bofi_map,
    208 	NULL,
    209 	NULL,
    210 	NULL,
    211 	i_ddi_map_fault,
    212 	bofi_dma_map,
    213 	bofi_dma_allochdl,
    214 	bofi_dma_freehdl,
    215 	bofi_dma_bindhdl,
    216 	bofi_dma_unbindhdl,
    217 	bofi_dma_flush,
    218 	bofi_dma_win,
    219 	bofi_dma_ctl,
    220 	NULL,
    221 	ddi_bus_prop_op,
    222 	ndi_busop_get_eventcookie,
    223 	ndi_busop_add_eventcall,
    224 	ndi_busop_remove_eventcall,
    225 	bofi_post_event,
    226 	NULL,
    227 	0,
    228 	0,
    229 	0,
    230 	0,
    231 	0,
    232 	0,
    233 	0,
    234 	bofi_intr_ops
    235 };
    236 
    237 static struct cb_ops bofi_cb_ops = {
    238 	bofi_open,		/* open */
    239 	bofi_close,		/* close */
    240 	nodev,			/* strategy */
    241 	nodev,			/* print */
    242 	nodev,			/* dump */
    243 	nodev,			/* read */
    244 	nodev,			/* write */
    245 	bofi_ioctl,		/* ioctl */
    246 	nodev,			/* devmap */
    247 	nodev,			/* mmap */
    248 	nodev,			/* segmap */
    249 	nochpoll,		/* chpoll */
    250 	ddi_prop_op,		/* prop_op */
    251 	NULL,			/* for STREAMS drivers */
    252 	D_MP,			/* driver compatibility flag */
    253 	CB_REV,			/* cb_ops revision */
    254 	nodev,			/* aread */
    255 	nodev			/* awrite */
    256 };
    257 
    258 static struct dev_ops bofi_ops = {
    259 	DEVO_REV,		/* driver build version */
    260 	0,			/* device reference count */
    261 	bofi_getinfo,
    262 	nulldev,
    263 	nulldev,		/* probe */
    264 	bofi_attach,
    265 	bofi_detach,
    266 	nulldev,		/* reset */
    267 	&bofi_cb_ops,
    268 	(struct bus_ops *)NULL,
    269 	nulldev,		/* power */
    270 	ddi_quiesce_not_needed,		/* quiesce */
    271 };
    272 
    273 /* module configuration stuff */
    274 static void    *statep;
    275 
    276 static struct modldrv modldrv = {
    277 	&mod_driverops,
    278 	"bofi driver",
    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, int map_flags, page_t *pp,
    406     page_t **pplist)
    407 {
    408 	struct buf buf;
    409 
    410 	if (addr == NULL)
    411 		return;
    412 	/*
    413 	 * mock up a buf structure
    414 	 */
    415 	buf.b_flags = B_REMAPPED | map_flags;
    416 	buf.b_un.b_addr = addr;
    417 	buf.b_bcount = (size_t)len;
    418 	buf.b_pages = pp;
    419 	buf.b_shadow = pplist;
    420 	bp_mapout(&buf);
    421 }
    422 
    423 static time_t
    424 bofi_gettime()
    425 {
    426 	timestruc_t ts;
    427 
    428 	gethrestime(&ts);
    429 	return (ts.tv_sec);
    430 }
    431 
    432 /*
    433  * reset the bus_ops structure of the specified nexus to point to
    434  * the original values in the save_bus_ops structure.
    435  *
    436  * Note that both this routine and modify_bus_ops() rely on the current
    437  * behavior of the framework in that nexus drivers are not unloadable
    438  *
    439  */
    440 
    441 static int
    442 reset_bus_ops(char *name, struct bus_ops *bop)
    443 {
    444 	struct modctl *modp;
    445 	struct modldrv *mp;
    446 	struct bus_ops *bp;
    447 	struct dev_ops *ops;
    448 
    449 	mutex_enter(&mod_lock);
    450 	/*
    451 	 * find specified module
    452 	 */
    453 	modp = &modules;
    454 	do {
    455 		if (strcmp(name, modp->mod_modname) == 0) {
    456 			if (!modp->mod_linkage) {
    457 				mutex_exit(&mod_lock);
    458 				return (0);
    459 			}
    460 			mp = modp->mod_linkage->ml_linkage[0];
    461 			if (!mp || !mp->drv_dev_ops) {
    462 				mutex_exit(&mod_lock);
    463 				return (0);
    464 			}
    465 			ops = mp->drv_dev_ops;
    466 			bp = ops->devo_bus_ops;
    467 			if (!bp) {
    468 				mutex_exit(&mod_lock);
    469 				return (0);
    470 			}
    471 			if (ops->devo_refcnt > 0) {
    472 				/*
    473 				 * As long as devices are active with modified
    474 				 * bus ops bofi must not go away. There may be
    475 				 * drivers with modified access or dma handles.
    476 				 */
    477 				mutex_exit(&mod_lock);
    478 				return (0);
    479 			}
    480 			cmn_err(CE_NOTE, "bofi reset bus_ops for %s",
    481 			    mp->drv_linkinfo);
    482 			bp->bus_intr_op = bop->bus_intr_op;
    483 			bp->bus_post_event = bop->bus_post_event;
    484 			bp->bus_map = bop->bus_map;
    485 			bp->bus_dma_map = bop->bus_dma_map;
    486 			bp->bus_dma_allochdl = bop->bus_dma_allochdl;
    487 			bp->bus_dma_freehdl = bop->bus_dma_freehdl;
    488 			bp->bus_dma_bindhdl = bop->bus_dma_bindhdl;
    489 			bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl;
    490 			bp->bus_dma_flush = bop->bus_dma_flush;
    491 			bp->bus_dma_win = bop->bus_dma_win;
    492 			bp->bus_dma_ctl = bop->bus_dma_ctl;
    493 			mutex_exit(&mod_lock);
    494 			return (1);
    495 		}
    496 	} while ((modp = modp->mod_next) != &modules);
    497 	mutex_exit(&mod_lock);
    498 	return (0);
    499 }
    500 
    501 /*
    502  * modify the bus_ops structure of the specified nexus to point to bofi
    503  * routines, saving the original values in the save_bus_ops structure
    504  */
    505 
    506 static int
    507 modify_bus_ops(char *name, struct bus_ops *bop)
    508 {
    509 	struct modctl *modp;
    510 	struct modldrv *mp;
    511 	struct bus_ops *bp;
    512 	struct dev_ops *ops;
    513 
    514 	if (ddi_name_to_major(name) == -1)
    515 		return (0);
    516 
    517 	mutex_enter(&mod_lock);
    518 	/*
    519 	 * find specified module
    520 	 */
    521 	modp = &modules;
    522 	do {
    523 		if (strcmp(name, modp->mod_modname) == 0) {
    524 			if (!modp->mod_linkage) {
    525 				mutex_exit(&mod_lock);
    526 				return (0);
    527 			}
    528 			mp = modp->mod_linkage->ml_linkage[0];
    529 			if (!mp || !mp->drv_dev_ops) {
    530 				mutex_exit(&mod_lock);
    531 				return (0);
    532 			}
    533 			ops = mp->drv_dev_ops;
    534 			bp = ops->devo_bus_ops;
    535 			if (!bp) {
    536 				mutex_exit(&mod_lock);
    537 				return (0);
    538 			}
    539 			if (ops->devo_refcnt == 0) {
    540 				/*
    541 				 * If there is no device active for this
    542 				 * module then there is nothing to do for bofi.
    543 				 */
    544 				mutex_exit(&mod_lock);
    545 				return (0);
    546 			}
    547 			cmn_err(CE_NOTE, "bofi modify bus_ops for %s",
    548 			    mp->drv_linkinfo);
    549 			save_bus_ops = *bp;
    550 			bp->bus_intr_op = bop->bus_intr_op;
    551 			bp->bus_post_event = bop->bus_post_event;
    552 			bp->bus_map = bop->bus_map;
    553 			bp->bus_dma_map = bop->bus_dma_map;
    554 			bp->bus_dma_allochdl = bop->bus_dma_allochdl;
    555 			bp->bus_dma_freehdl = bop->bus_dma_freehdl;
    556 			bp->bus_dma_bindhdl = bop->bus_dma_bindhdl;
    557 			bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl;
    558 			bp->bus_dma_flush = bop->bus_dma_flush;
    559 			bp->bus_dma_win = bop->bus_dma_win;
    560 			bp->bus_dma_ctl = bop->bus_dma_ctl;
    561 			mutex_exit(&mod_lock);
    562 			return (1);
    563 		}
    564 	} while ((modp = modp->mod_next) != &modules);
    565 	mutex_exit(&mod_lock);
    566 	return (0);
    567 }
    568 
    569 
    570 int
    571 _init(void)
    572 {
    573 	int    e;
    574 
    575 	e = ddi_soft_state_init(&statep, sizeof (struct bofi_errent), 1);
    576 	if (e != 0)
    577 		return (e);
    578 	if ((e = mod_install(&modlinkage)) != 0)
    579 		ddi_soft_state_fini(&statep);
    580 	return (e);
    581 }
    582 
    583 
    584 int
    585 _fini(void)
    586 {
    587 	int e;
    588 
    589 	if ((e = mod_remove(&modlinkage)) != 0)
    590 		return (e);
    591 	ddi_soft_state_fini(&statep);
    592 	return (e);
    593 }
    594 
    595 
    596 int
    597 _info(struct modinfo *modinfop)
    598 {
    599 	return (mod_info(&modlinkage, modinfop));
    600 }
    601 
    602 
    603 static int
    604 bofi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    605 {
    606 	char *name;
    607 	char buf[80];
    608 	int i;
    609 	int s, ss;
    610 	int size = NAMESIZE;
    611 	int new_string;
    612 	char *ptr;
    613 
    614 	if (cmd != DDI_ATTACH)
    615 		return (DDI_FAILURE);
    616 	/*
    617 	 * only one instance - but we clone using the open routine
    618 	 */
    619 	if (ddi_get_instance(dip) > 0)
    620 		return (DDI_FAILURE);
    621 
    622 	if (!initialized) {
    623 		if ((name = ddi_get_name(dip)) == NULL)
    624 			return (DDI_FAILURE);
    625 		(void) snprintf(buf, sizeof (buf), "%s,ctl", name);
    626 		if (ddi_create_minor_node(dip, buf, S_IFCHR, 0,
    627 		    DDI_PSEUDO, NULL) == DDI_FAILURE)
    628 			return (DDI_FAILURE);
    629 
    630 		if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_MED,
    631 		    &bofi_low_cookie) != DDI_SUCCESS) {
    632 			ddi_remove_minor_node(dip, buf);
    633 			return (DDI_FAILURE); /* fail attach */
    634 		}
    635 		/*
    636 		 * get nexus name (from conf file)
    637 		 */
    638 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0,
    639 		    "bofi-nexus", nexus_name, &size) != DDI_PROP_SUCCESS) {
    640 			ddi_remove_minor_node(dip, buf);
    641 			return (DDI_FAILURE);
    642 		}
    643 		/*
    644 		 * get whether to do dma map kmem private checking
    645 		 */
    646 		if ((bofi_range_check = ddi_prop_lookup_string(DDI_DEV_T_ANY,
    647 		    dip, 0, "bofi-range-check", &ptr)) != DDI_PROP_SUCCESS)
    648 			bofi_range_check = 0;
    649 		else if (strcmp(ptr, "panic") == 0)
    650 			bofi_range_check = 2;
    651 		else if (strcmp(ptr, "warn") == 0)
    652 			bofi_range_check = 1;
    653 		else
    654 			bofi_range_check = 0;
    655 		ddi_prop_free(ptr);
    656 
    657 		/*
    658 		 * get whether to prevent direct access to register
    659 		 */
    660 		if ((bofi_ddi_check = ddi_prop_lookup_string(DDI_DEV_T_ANY,
    661 		    dip, 0, "bofi-ddi-check", &ptr)) != DDI_PROP_SUCCESS)
    662 			bofi_ddi_check = 0;
    663 		else if (strcmp(ptr, "on") == 0)
    664 			bofi_ddi_check = 1;
    665 		else
    666 			bofi_ddi_check = 0;
    667 		ddi_prop_free(ptr);
    668 
    669 		/*
    670 		 * get whether to do copy on ddi_dma_sync
    671 		 */
    672 		if ((bofi_sync_check = ddi_prop_lookup_string(DDI_DEV_T_ANY,
    673 		    dip, 0, "bofi-sync-check", &ptr)) != DDI_PROP_SUCCESS)
    674 			bofi_sync_check = 0;
    675 		else if (strcmp(ptr, "on") == 0)
    676 			bofi_sync_check = 1;
    677 		else
    678 			bofi_sync_check = 0;
    679 		ddi_prop_free(ptr);
    680 
    681 		/*
    682 		 * get driver-under-test names (from conf file)
    683 		 */
    684 		size = NAMESIZE;
    685 		if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0,
    686 		    "bofi-to-test", driver_list, &size) != DDI_PROP_SUCCESS)
    687 			driver_list[0] = 0;
    688 		/*
    689 		 * and convert into a sequence of strings
    690 		 */
    691 		driver_list_neg = 1;
    692 		new_string = 1;
    693 		driver_list_size = strlen(driver_list);
    694 		for (i = 0; i < driver_list_size; i++) {
    695 			if (driver_list[i] == ' ') {
    696 				driver_list[i] = '\0';
    697 				new_string = 1;
    698 			} else if (new_string) {
    699 				if (driver_list[i] != '!')
    700 					driver_list_neg = 0;
    701 				new_string = 0;
    702 			}
    703 		}
    704 		/*
    705 		 * initialize mutex, lists
    706 		 */
    707 		mutex_init(&clone_tab_mutex, NULL, MUTEX_DRIVER,
    708 		    NULL);
    709 		/*
    710 		 * fake up iblock cookie - need to protect outselves
    711 		 * against drivers that use hilevel interrupts
    712 		 */
    713 		ss = spl8();
    714 		s = spl8();
    715 		splx(ss);
    716 		mutex_init(&bofi_mutex, NULL, MUTEX_SPIN, (void *)(uintptr_t)s);
    717 		mutex_init(&bofi_low_mutex, NULL, MUTEX_DRIVER,
    718 		    (void *)bofi_low_cookie);
    719 		shadow_list.next = &shadow_list;
    720 		shadow_list.prev = &shadow_list;
    721 		for (i = 0; i < HDL_HASH_TBL_SIZE; i++) {
    722 			hhash_table[i].hnext = &hhash_table[i];
    723 			hhash_table[i].hprev = &hhash_table[i];
    724 			dhash_table[i].dnext = &dhash_table[i];
    725 			dhash_table[i].dprev = &dhash_table[i];
    726 		}
    727 		for (i = 1; i < BOFI_NLINKS; i++)
    728 			bofi_link_array[i].link = &bofi_link_array[i-1];
    729 		bofi_link_freelist = &bofi_link_array[BOFI_NLINKS - 1];
    730 		/*
    731 		 * overlay bus_ops structure
    732 		 */
    733 		if (modify_bus_ops(nexus_name, &bofi_bus_ops) == 0) {
    734 			ddi_remove_minor_node(dip, buf);
    735 			mutex_destroy(&clone_tab_mutex);
    736 			mutex_destroy(&bofi_mutex);
    737 			mutex_destroy(&bofi_low_mutex);
    738 			return (DDI_FAILURE);
    739 		}
    740 		if (sysevent_evc_bind(FM_ERROR_CHAN, &bofi_error_chan, 0) == 0)
    741 			(void) sysevent_evc_subscribe(bofi_error_chan, "bofi",
    742 			    EC_FM, bofi_fm_ereport_callback, NULL, 0);
    743 
    744 		/*
    745 		 * save dip for getinfo
    746 		 */
    747 		our_dip = dip;
    748 		ddi_report_dev(dip);
    749 		initialized = 1;
    750 	}
    751 	return (DDI_SUCCESS);
    752 }
    753 
    754 
    755 static int
    756 bofi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    757 {
    758 	char *name;
    759 	char buf[80];
    760 
    761 	if (cmd != DDI_DETACH)
    762 		return (DDI_FAILURE);
    763 	if (ddi_get_instance(dip) > 0)
    764 		return (DDI_FAILURE);
    765 	if ((name = ddi_get_name(dip)) == NULL)
    766 		return (DDI_FAILURE);
    767 	(void) snprintf(buf, sizeof (buf), "%s,ctl", name);
    768 	mutex_enter(&bofi_low_mutex);
    769 	mutex_enter(&bofi_mutex);
    770 	/*
    771 	 * make sure test bofi is no longer in use
    772 	 */
    773 	if (shadow_list.next != &shadow_list || errent_listp != NULL) {
    774 		mutex_exit(&bofi_mutex);
    775 		mutex_exit(&bofi_low_mutex);
    776 		return (DDI_FAILURE);
    777 	}
    778 	mutex_exit(&bofi_mutex);
    779 	mutex_exit(&bofi_low_mutex);
    780 
    781 	/*
    782 	 * restore bus_ops structure
    783 	 */
    784 	if (reset_bus_ops(nexus_name, &save_bus_ops) == 0)
    785 		return (DDI_FAILURE);
    786 
    787 	sysevent_evc_unbind(bofi_error_chan);
    788 
    789 	mutex_destroy(&clone_tab_mutex);
    790 	mutex_destroy(&bofi_mutex);
    791 	mutex_destroy(&bofi_low_mutex);
    792 	ddi_remove_minor_node(dip, buf);
    793 	our_dip = NULL;
    794 	initialized = 0;
    795 	return (DDI_SUCCESS);
    796 }
    797 
    798 
    799 /* ARGSUSED */
    800 static int
    801 bofi_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
    802 {
    803 	dev_t	dev = (dev_t)arg;
    804 	int	minor = (int)getminor(dev);
    805 	int	retval;
    806 
    807 	switch (cmd) {
    808 	case DDI_INFO_DEVT2DEVINFO:
    809 		if (minor != 0 || our_dip == NULL) {
    810 			*result = (void *)NULL;
    811 			retval = DDI_FAILURE;
    812 		} else {
    813 			*result = (void *)our_dip;
    814 			retval = DDI_SUCCESS;
    815 		}
    816 		break;
    817 	case DDI_INFO_DEVT2INSTANCE:
    818 		*result = (void *)0;
    819 		retval = DDI_SUCCESS;
    820 		break;
    821 	default:
    822 		retval = DDI_FAILURE;
    823 	}
    824 	return (retval);
    825 }
    826 
    827 
    828 /* ARGSUSED */
    829 static int
    830 bofi_open(dev_t *devp, int flag, int otyp, cred_t *credp)
    831 {
    832 	int	minor = (int)getminor(*devp);
    833 	struct bofi_errent *softc;
    834 
    835 	/*
    836 	 * only allow open on minor=0 - the clone device
    837 	 */
    838 	if (minor != 0)
    839 		return (ENXIO);
    840 	/*
    841 	 * fail if not attached
    842 	 */
    843 	if (!initialized)
    844 		return (ENXIO);
    845 	/*
    846 	 * find a free slot and grab it
    847 	 */
    848 	mutex_enter(&clone_tab_mutex);
    849 	for (minor = 1; minor < NCLONES; minor++) {
    850 		if (clone_tab[minor] == 0) {
    851 			clone_tab[minor] = 1;
    852 			break;
    853 		}
    854 	}
    855 	mutex_exit(&clone_tab_mutex);
    856 	if (minor == NCLONES)
    857 		return (EAGAIN);
    858 	/*
    859 	 * soft state structure for this clone is used to maintain a list
    860 	 * of allocated errdefs so they can be freed on close
    861 	 */
    862 	if (ddi_soft_state_zalloc(statep, minor) != DDI_SUCCESS) {
    863 		mutex_enter(&clone_tab_mutex);
    864 		clone_tab[minor] = 0;
    865 		mutex_exit(&clone_tab_mutex);
    866 		return (EAGAIN);
    867 	}
    868 	softc = ddi_get_soft_state(statep, minor);
    869 	softc->cnext = softc;
    870 	softc->cprev = softc;
    871 
    872 	*devp = makedevice(getmajor(*devp), minor);
    873 	return (0);
    874 }
    875 
    876 
    877 /* ARGSUSED */
    878 static int
    879 bofi_close(dev_t dev, int flag, int otyp, cred_t *credp)
    880 {
    881 	int	minor = (int)getminor(dev);
    882 	struct bofi_errent *softc;
    883 	struct bofi_errent *ep, *next_ep;
    884 
    885 	softc = ddi_get_soft_state(statep, minor);
    886 	if (softc == NULL)
    887 		return (ENXIO);
    888 	/*
    889 	 * find list of errdefs and free them off
    890 	 */
    891 	for (ep = softc->cnext; ep != softc; ) {
    892 		next_ep = ep->cnext;
    893 		(void) bofi_errdef_free(ep);
    894 		ep = next_ep;
    895 	}
    896 	/*
    897 	 * free clone tab slot
    898 	 */
    899 	mutex_enter(&clone_tab_mutex);
    900 	clone_tab[minor] = 0;
    901 	mutex_exit(&clone_tab_mutex);
    902 
    903 	ddi_soft_state_free(statep, minor);
    904 	return (0);
    905 }
    906 
    907 
    908 /* ARGSUSED */
    909 static int
    910 bofi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
    911 	int *rvalp)
    912 {
    913 	struct bofi_errent *softc;
    914 	int	minor = (int)getminor(dev);
    915 	struct bofi_errdef errdef;
    916 	struct bofi_errctl errctl;
    917 	struct bofi_errstate errstate;
    918 	void *ed_handle;
    919 	struct bofi_get_handles get_handles;
    920 	struct bofi_get_hdl_info hdl_info;
    921 	struct handle_info *hdlip;
    922 	struct handle_info *hib;
    923 
    924 	char *buffer;
    925 	char *bufptr;
    926 	char *endbuf;
    927 	int req_count, count, err;
    928 	char *namep;
    929 	struct bofi_shadow *hp;
    930 	int retval;
    931 	struct bofi_shadow *hhashp;
    932 	int i;
    933 
    934 	switch (cmd) {
    935 	case BOFI_ADD_DEF:
    936 		/*
    937 		 * add a new error definition
    938 		 */
    939 #ifdef _MULTI_DATAMODEL
    940 		switch (ddi_model_convert_from(mode & FMODELS)) {
    941 		case DDI_MODEL_ILP32:
    942 		{
    943 			/*
    944 			 * For use when a 32 bit app makes a call into a
    945 			 * 64 bit ioctl
    946 			 */
    947 			struct bofi_errdef32	errdef_32;
    948 
    949 			if (ddi_copyin((void *)arg, &errdef_32,
    950 			    sizeof (struct bofi_errdef32), mode)) {
    951 				return (EFAULT);
    952 			}
    953 			errdef.namesize = errdef_32.namesize;
    954 			(void) strncpy(errdef.name, errdef_32.name, NAMESIZE);
    955 			errdef.instance = errdef_32.instance;
    956 			errdef.rnumber = errdef_32.rnumber;
    957 			errdef.offset = errdef_32.offset;
    958 			errdef.len = errdef_32.len;
    959 			errdef.access_type = errdef_32.access_type;
    960 			errdef.access_count = errdef_32.access_count;
    961 			errdef.fail_count = errdef_32.fail_count;
    962 			errdef.acc_chk = errdef_32.acc_chk;
    963 			errdef.optype = errdef_32.optype;
    964 			errdef.operand = errdef_32.operand;
    965 			errdef.log.logsize = errdef_32.log.logsize;
    966 			errdef.log.entries = errdef_32.log.entries;
    967 			errdef.log.flags = errdef_32.log.flags;
    968 			errdef.log.wrapcnt = errdef_32.log.wrapcnt;
    969 			errdef.log.start_time = errdef_32.log.start_time;
    970 			errdef.log.stop_time = errdef_32.log.stop_time;
    971 			errdef.log.logbase =
    972 			    (caddr_t)(uintptr_t)errdef_32.log.logbase;
    973 			errdef.errdef_handle = errdef_32.errdef_handle;
    974 			break;
    975 		}
    976 		case DDI_MODEL_NONE:
    977 			if (ddi_copyin((void *)arg, &errdef,
    978 			    sizeof (struct bofi_errdef), mode))
    979 				return (EFAULT);
    980 			break;
    981 		}
    982 #else /* ! _MULTI_DATAMODEL */
    983 		if (ddi_copyin((void *)arg, &errdef,
    984 		    sizeof (struct bofi_errdef), mode) != 0)
    985 			return (EFAULT);
    986 #endif /* _MULTI_DATAMODEL */
    987 		/*
    988 		 * do some validation
    989 		 */
    990 		if (errdef.fail_count == 0)
    991 			errdef.optype = 0;
    992 		if (errdef.optype != 0) {
    993 			if (errdef.access_type & BOFI_INTR &&
    994 			    errdef.optype != BOFI_DELAY_INTR &&
    995 			    errdef.optype != BOFI_LOSE_INTR &&
    996 			    errdef.optype != BOFI_EXTRA_INTR)
    997 				return (EINVAL);
    998 			if ((errdef.access_type & (BOFI_DMA_RW|BOFI_PIO_R)) &&
    999 			    errdef.optype == BOFI_NO_TRANSFER)
   1000 				return (EINVAL);
   1001 			if ((errdef.access_type & (BOFI_PIO_RW)) &&
   1002 			    errdef.optype != BOFI_EQUAL &&
   1003 			    errdef.optype != BOFI_OR &&
   1004 			    errdef.optype != BOFI_XOR &&
   1005 			    errdef.optype != BOFI_AND &&
   1006 			    errdef.optype != BOFI_NO_TRANSFER)
   1007 				return (EINVAL);
   1008 		}
   1009 		/*
   1010 		 * find softstate for this clone, so we can tag