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