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