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