17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 317c478bd9Sstevel@tonic-gate #include <sys/buf.h> 327c478bd9Sstevel@tonic-gate #include <sys/errno.h> 337c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 347c478bd9Sstevel@tonic-gate #include <sys/conf.h> 357c478bd9Sstevel@tonic-gate #include <sys/stat.h> 367c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 377c478bd9Sstevel@tonic-gate #include <sys/proc.h> 387c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 397c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 407c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 417c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 427c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 437c478bd9Sstevel@tonic-gate #include <sys/debug.h> 447c478bd9Sstevel@tonic-gate #include <sys/bofi.h> 457c478bd9Sstevel@tonic-gate #include <sys/dvma.h> 467c478bd9Sstevel@tonic-gate #include <sys/bofi_impl.h> 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 497c478bd9Sstevel@tonic-gate * Testing the resilience of a hardened device driver requires a suitably wide 507c478bd9Sstevel@tonic-gate * range of different types of "typical" hardware faults to be injected, 517c478bd9Sstevel@tonic-gate * preferably in a controlled and repeatable fashion. This is not in general 527c478bd9Sstevel@tonic-gate * possible via hardware, so the "fault injection test harness" is provided. 537c478bd9Sstevel@tonic-gate * This works by intercepting calls from the driver to various DDI routines, 547c478bd9Sstevel@tonic-gate * and then corrupting the result of those DDI routine calls as if the 557c478bd9Sstevel@tonic-gate * hardware had caused the corruption. 567c478bd9Sstevel@tonic-gate * 577c478bd9Sstevel@tonic-gate * Conceptually, the bofi driver consists of two parts: 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * A driver interface that supports a number of ioctls which allow error 607c478bd9Sstevel@tonic-gate * definitions ("errdefs") to be defined and subsequently managed. The 617c478bd9Sstevel@tonic-gate * driver is a clone driver, so each open will create a separate 627c478bd9Sstevel@tonic-gate * invocation. Any errdefs created by using ioctls to that invocation 637c478bd9Sstevel@tonic-gate * will automatically be deleted when that invocation is closed. 647c478bd9Sstevel@tonic-gate * 657c478bd9Sstevel@tonic-gate * Intercept routines: When the bofi driver is attached, it edits the 667c478bd9Sstevel@tonic-gate * bus_ops structure of the bus nexus specified by the "bofi-nexus" 677c478bd9Sstevel@tonic-gate * field in the "bofi.conf" file, thus allowing the 687c478bd9Sstevel@tonic-gate * bofi driver to intercept various ddi functions. These intercept 697c478bd9Sstevel@tonic-gate * routines primarily carry out fault injections based on the errdefs 707c478bd9Sstevel@tonic-gate * created for that device. 717c478bd9Sstevel@tonic-gate * 727c478bd9Sstevel@tonic-gate * Faults can be injected into: 737c478bd9Sstevel@tonic-gate * 747c478bd9Sstevel@tonic-gate * DMA (corrupting data for DMA to/from memory areas defined by 757c478bd9Sstevel@tonic-gate * ddi_dma_setup(), ddi_dma_bind_handle(), etc) 767c478bd9Sstevel@tonic-gate * 777c478bd9Sstevel@tonic-gate * Physical IO (corrupting data sent/received via ddi_get8(), ddi_put8(), 787c478bd9Sstevel@tonic-gate * etc), 797c478bd9Sstevel@tonic-gate * 807c478bd9Sstevel@tonic-gate * Interrupts (generating spurious interrupts, losing interrupts, 817c478bd9Sstevel@tonic-gate * delaying interrupts). 827c478bd9Sstevel@tonic-gate * 837c478bd9Sstevel@tonic-gate * By default, ddi routines called from all drivers will be intercepted 847c478bd9Sstevel@tonic-gate * and faults potentially injected. However, the "bofi-to-test" field in 857c478bd9Sstevel@tonic-gate * the "bofi.conf" file can be set to a space-separated list of drivers to 867c478bd9Sstevel@tonic-gate * test (or by preceding each driver name in the list with an "!", a list 877c478bd9Sstevel@tonic-gate * of drivers not to test). 887c478bd9Sstevel@tonic-gate * 897c478bd9Sstevel@tonic-gate * In addition to fault injection, the bofi driver does a number of static 907c478bd9Sstevel@tonic-gate * checks which are controlled by properties in the "bofi.conf" file. 917c478bd9Sstevel@tonic-gate * 927c478bd9Sstevel@tonic-gate * "bofi-ddi-check" - if set will validate that there are no PIO access 937c478bd9Sstevel@tonic-gate * other than those using the DDI routines (ddi_get8(), ddi_put8(), etc). 947c478bd9Sstevel@tonic-gate * 957c478bd9Sstevel@tonic-gate * "bofi-range-check" - if set to values 1 (warning) or 2 (panic), will 967c478bd9Sstevel@tonic-gate * validate that calls to ddi_get8(), ddi_put8(), etc are not made 977c478bd9Sstevel@tonic-gate * specifying addresses outside the range of the access_handle. 987c478bd9Sstevel@tonic-gate * 997c478bd9Sstevel@tonic-gate * "bofi-sync-check" - if set will validate that calls to ddi_dma_sync() 1007c478bd9Sstevel@tonic-gate * are being made correctly. 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate extern void *bp_mapin_common(struct buf *, int); 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate static int bofi_ddi_check; 1067c478bd9Sstevel@tonic-gate static int bofi_sync_check; 1077c478bd9Sstevel@tonic-gate static int bofi_range_check; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate static struct bofi_link bofi_link_array[BOFI_NLINKS], *bofi_link_freelist; 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate #define LLSZMASK (sizeof (uint64_t)-1) 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate #define HDL_HASH_TBL_SIZE 64 1147c478bd9Sstevel@tonic-gate static struct bofi_shadow hhash_table[HDL_HASH_TBL_SIZE]; 1157c478bd9Sstevel@tonic-gate static struct bofi_shadow dhash_table[HDL_HASH_TBL_SIZE]; 1167c478bd9Sstevel@tonic-gate #define HDL_DHASH(x) \ 1177c478bd9Sstevel@tonic-gate (&dhash_table[((uintptr_t)(x) >> 3) & (HDL_HASH_TBL_SIZE-1)]) 1187c478bd9Sstevel@tonic-gate #define HDL_HHASH(x) \ 1197c478bd9Sstevel@tonic-gate (&hhash_table[((uintptr_t)(x) >> 5) & (HDL_HASH_TBL_SIZE-1)]) 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate static struct bofi_shadow shadow_list; 1227c478bd9Sstevel@tonic-gate static struct bofi_errent *errent_listp; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate static char driver_list[NAMESIZE]; 1257c478bd9Sstevel@tonic-gate static int driver_list_size; 1267c478bd9Sstevel@tonic-gate static int driver_list_neg; 1277c478bd9Sstevel@tonic-gate static char nexus_name[NAMESIZE]; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate static int initialized = 0; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate #define NCLONES 256 1327c478bd9Sstevel@tonic-gate static int clone_tab[NCLONES]; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate static dev_info_t *our_dip; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate static kmutex_t bofi_mutex; 1377c478bd9Sstevel@tonic-gate static kmutex_t clone_tab_mutex; 1387c478bd9Sstevel@tonic-gate static kmutex_t bofi_low_mutex; 1397c478bd9Sstevel@tonic-gate static ddi_iblock_cookie_t bofi_low_cookie; 1407c478bd9Sstevel@tonic-gate static uint_t bofi_signal(caddr_t arg); 1417c478bd9Sstevel@tonic-gate static int bofi_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 1427c478bd9Sstevel@tonic-gate static int bofi_attach(dev_info_t *, ddi_attach_cmd_t); 1437c478bd9Sstevel@tonic-gate static int bofi_detach(dev_info_t *, ddi_detach_cmd_t); 1447c478bd9Sstevel@tonic-gate static int bofi_open(dev_t *, int, int, cred_t *); 1457c478bd9Sstevel@tonic-gate static int bofi_close(dev_t, int, int, cred_t *); 1467c478bd9Sstevel@tonic-gate static int bofi_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1477c478bd9Sstevel@tonic-gate static int bofi_errdef_alloc(struct bofi_errdef *, char *, 1487c478bd9Sstevel@tonic-gate struct bofi_errent *); 1497c478bd9Sstevel@tonic-gate static int bofi_errdef_free(struct bofi_errent *); 1507c478bd9Sstevel@tonic-gate static void bofi_start(struct bofi_errctl *, char *); 1517c478bd9Sstevel@tonic-gate static void bofi_stop(struct bofi_errctl *, char *); 1527c478bd9Sstevel@tonic-gate static void bofi_broadcast(struct bofi_errctl *, char *); 1537c478bd9Sstevel@tonic-gate static void bofi_clear_acc_chk(struct bofi_errctl *, char *); 1547c478bd9Sstevel@tonic-gate static void bofi_clear_errors(struct bofi_errctl *, char *); 1557c478bd9Sstevel@tonic-gate static void bofi_clear_errdefs(struct bofi_errctl *, char *); 1567c478bd9Sstevel@tonic-gate static int bofi_errdef_check(struct bofi_errstate *, 1577c478bd9Sstevel@tonic-gate struct acc_log_elem **); 1587c478bd9Sstevel@tonic-gate static int bofi_errdef_check_w(struct bofi_errstate *, 1597c478bd9Sstevel@tonic-gate struct acc_log_elem **); 1607c478bd9Sstevel@tonic-gate static int bofi_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 1617c478bd9Sstevel@tonic-gate off_t, off_t, caddr_t *); 1627c478bd9Sstevel@tonic-gate static int bofi_dma_map(dev_info_t *, dev_info_t *, 1637c478bd9Sstevel@tonic-gate struct ddi_dma_req *, ddi_dma_handle_t *); 1647c478bd9Sstevel@tonic-gate static int bofi_dma_allochdl(dev_info_t *, dev_info_t *, 1657c478bd9Sstevel@tonic-gate ddi_dma_attr_t *, int (*)(caddr_t), caddr_t, 1667c478bd9Sstevel@tonic-gate ddi_dma_handle_t *); 1677c478bd9Sstevel@tonic-gate static int bofi_dma_freehdl(dev_info_t *, dev_info_t *, 1687c478bd9Sstevel@tonic-gate ddi_dma_handle_t); 1697c478bd9Sstevel@tonic-gate static int bofi_dma_bindhdl(dev_info_t *, dev_info_t *, 1707c478bd9Sstevel@tonic-gate ddi_dma_handle_t, struct ddi_dma_req *, ddi_dma_cookie_t *, 1717c478bd9Sstevel@tonic-gate uint_t *); 1727c478bd9Sstevel@tonic-gate static int bofi_dma_unbindhdl(dev_info_t *, dev_info_t *, 1737c478bd9Sstevel@tonic-gate ddi_dma_handle_t); 1747c478bd9Sstevel@tonic-gate static int bofi_dma_flush(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 1757c478bd9Sstevel@tonic-gate off_t, size_t, uint_t); 1767c478bd9Sstevel@tonic-gate static int bofi_dma_ctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 1777c478bd9Sstevel@tonic-gate enum ddi_dma_ctlops, off_t *, size_t *, caddr_t *, uint_t); 1787c478bd9Sstevel@tonic-gate static int bofi_dma_win(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 1797c478bd9Sstevel@tonic-gate uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *); 1807c478bd9Sstevel@tonic-gate static int bofi_intr_ops(dev_info_t *dip, dev_info_t *rdip, 1817c478bd9Sstevel@tonic-gate ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, 1827c478bd9Sstevel@tonic-gate void *result); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate #if defined(__sparc) 1857c478bd9Sstevel@tonic-gate static void bofi_dvma_kaddr_load(ddi_dma_handle_t, caddr_t, uint_t, 1867c478bd9Sstevel@tonic-gate uint_t, ddi_dma_cookie_t *); 1877c478bd9Sstevel@tonic-gate static void bofi_dvma_unload(ddi_dma_handle_t, uint_t, uint_t); 1887c478bd9Sstevel@tonic-gate static void bofi_dvma_sync(ddi_dma_handle_t, uint_t, uint_t); 1897c478bd9Sstevel@tonic-gate static void bofi_dvma_reserve(dev_info_t *, ddi_dma_handle_t); 1907c478bd9Sstevel@tonic-gate #endif 1917c478bd9Sstevel@tonic-gate static int driver_under_test(dev_info_t *); 1927c478bd9Sstevel@tonic-gate static int bofi_check_acc_hdl(ddi_acc_impl_t *); 1937c478bd9Sstevel@tonic-gate static int bofi_check_dma_hdl(ddi_dma_impl_t *); 1947c478bd9Sstevel@tonic-gate static int bofi_post_event(dev_info_t *dip, dev_info_t *rdip, 1957c478bd9Sstevel@tonic-gate ddi_eventcookie_t eventhdl, void *impl_data); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate static struct bus_ops bofi_bus_ops = { 1987c478bd9Sstevel@tonic-gate BUSO_REV, 1997c478bd9Sstevel@tonic-gate bofi_map, 2007c478bd9Sstevel@tonic-gate NULL, 2017c478bd9Sstevel@tonic-gate NULL, 2027c478bd9Sstevel@tonic-gate NULL, 2037c478bd9Sstevel@tonic-gate i_ddi_map_fault, 2047c478bd9Sstevel@tonic-gate bofi_dma_map, 2057c478bd9Sstevel@tonic-gate bofi_dma_allochdl, 2067c478bd9Sstevel@tonic-gate bofi_dma_freehdl, 2077c478bd9Sstevel@tonic-gate bofi_dma_bindhdl, 2087c478bd9Sstevel@tonic-gate bofi_dma_unbindhdl, 2097c478bd9Sstevel@tonic-gate bofi_dma_flush, 2107c478bd9Sstevel@tonic-gate bofi_dma_win, 2117c478bd9Sstevel@tonic-gate bofi_dma_ctl, 2127c478bd9Sstevel@tonic-gate NULL, 2137c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 2147c478bd9Sstevel@tonic-gate ndi_busop_get_eventcookie, 2157c478bd9Sstevel@tonic-gate ndi_busop_add_eventcall, 2167c478bd9Sstevel@tonic-gate ndi_busop_remove_eventcall, 2177c478bd9Sstevel@tonic-gate bofi_post_event, 2187c478bd9Sstevel@tonic-gate NULL, 2197c478bd9Sstevel@tonic-gate 0, 2207c478bd9Sstevel@tonic-gate 0, 2217c478bd9Sstevel@tonic-gate 0, 2227c478bd9Sstevel@tonic-gate 0, 2237c478bd9Sstevel@tonic-gate 0, 2247c478bd9Sstevel@tonic-gate 0, 2257c478bd9Sstevel@tonic-gate 0, 2267c478bd9Sstevel@tonic-gate bofi_intr_ops 2277c478bd9Sstevel@tonic-gate }; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate static struct cb_ops bofi_cb_ops = { 230*a913d554Scth bofi_open, /* open */ 231*a913d554Scth bofi_close, /* close */ 232*a913d554Scth nodev, /* strategy */ 233*a913d554Scth nodev, /* print */ 2347c478bd9Sstevel@tonic-gate nodev, /* dump */ 235*a913d554Scth nodev, /* read */ 236*a913d554Scth nodev, /* write */ 237*a913d554Scth bofi_ioctl, /* ioctl */ 2387c478bd9Sstevel@tonic-gate nodev, /* devmap */ 239*a913d554Scth nodev, /* mmap */ 2407c478bd9Sstevel@tonic-gate nodev, /* segmap */ 241*a913d554Scth nochpoll, /* chpoll */ 242*a913d554Scth ddi_prop_op, /* prop_op */ 2437c478bd9Sstevel@tonic-gate NULL, /* for STREAMS drivers */ 244*a913d554Scth D_MP, /* driver compatibility flag */ 245*a913d554Scth CB_REV, /* cb_ops revision */ 246*a913d554Scth nodev, /* aread */ 247*a913d554Scth nodev /* awrite */ 2487c478bd9Sstevel@tonic-gate }; 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate static struct dev_ops bofi_ops = { 2517c478bd9Sstevel@tonic-gate DEVO_REV, /* driver build version */ 2527c478bd9Sstevel@tonic-gate 0, /* device reference count */ 2537c478bd9Sstevel@tonic-gate bofi_getinfo, 2547c478bd9Sstevel@tonic-gate nulldev, 2557c478bd9Sstevel@tonic-gate nulldev, /* probe */ 2567c478bd9Sstevel@tonic-gate bofi_attach, 2577c478bd9Sstevel@tonic-gate bofi_detach, 2587c478bd9Sstevel@tonic-gate nulldev, /* reset */ 2597c478bd9Sstevel@tonic-gate &bofi_cb_ops, 2607c478bd9Sstevel@tonic-gate (struct bus_ops *)NULL, 2617c478bd9Sstevel@tonic-gate nulldev /* power */ 2627c478bd9Sstevel@tonic-gate }; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* module configuration stuff */ 2657c478bd9Sstevel@tonic-gate static void *statep; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 2687c478bd9Sstevel@tonic-gate &mod_driverops, 2697c478bd9Sstevel@tonic-gate "bofi driver %I%", 2707c478bd9Sstevel@tonic-gate &bofi_ops 2717c478bd9Sstevel@tonic-gate }; 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 2747c478bd9Sstevel@tonic-gate MODREV_1, 2757c478bd9Sstevel@tonic-gate &modldrv, 2767c478bd9Sstevel@tonic-gate 0 2777c478bd9Sstevel@tonic-gate }; 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate static struct bus_ops save_bus_ops; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate #if defined(__sparc) 2827c478bd9Sstevel@tonic-gate static struct dvma_ops bofi_dvma_ops = { 2837c478bd9Sstevel@tonic-gate DVMAO_REV, 2847c478bd9Sstevel@tonic-gate bofi_dvma_kaddr_load, 2857c478bd9Sstevel@tonic-gate bofi_dvma_unload, 2867c478bd9Sstevel@tonic-gate bofi_dvma_sync 2877c478bd9Sstevel@tonic-gate }; 2887c478bd9Sstevel@tonic-gate #endif 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate /* 2917c478bd9Sstevel@tonic-gate * support routine - map user page into kernel virtual 2927c478bd9Sstevel@tonic-gate */ 2937c478bd9Sstevel@tonic-gate static caddr_t 2947c478bd9Sstevel@tonic-gate dmareq_mapin(offset_t len, caddr_t addr, struct as *as, int flag) 2957c478bd9Sstevel@tonic-gate { 2967c478bd9Sstevel@tonic-gate struct buf buf; 2977c478bd9Sstevel@tonic-gate struct proc proc; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate /* 3007c478bd9Sstevel@tonic-gate * mock up a buf structure so we can call bp_mapin_common() 3017c478bd9Sstevel@tonic-gate */ 3027c478bd9Sstevel@tonic-gate buf.b_flags = B_PHYS; 3037c478bd9Sstevel@tonic-gate buf.b_un.b_addr = (caddr_t)addr; 3047c478bd9Sstevel@tonic-gate buf.b_bcount = (size_t)len; 3057c478bd9Sstevel@tonic-gate proc.p_as = as; 3067c478bd9Sstevel@tonic-gate buf.b_proc = &proc; 3077c478bd9Sstevel@tonic-gate return (bp_mapin_common(&buf, flag)); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate /* 3127c478bd9Sstevel@tonic-gate * support routine - map page chain into kernel virtual 3137c478bd9Sstevel@tonic-gate */ 3147c478bd9Sstevel@tonic-gate static caddr_t 3157c478bd9Sstevel@tonic-gate dmareq_pp_mapin(offset_t len, uint_t offset, page_t *pp, int flag) 3167c478bd9Sstevel@tonic-gate { 3177c478bd9Sstevel@tonic-gate struct buf buf; 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * mock up a buf structure so we can call bp_mapin_common() 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate buf.b_flags = B_PAGEIO; 3237c478bd9Sstevel@tonic-gate buf.b_un.b_addr = (caddr_t)(uintptr_t)offset; 3247c478bd9Sstevel@tonic-gate buf.b_bcount = (size_t)len; 3257c478bd9Sstevel@tonic-gate buf.b_pages = pp; 3267c478bd9Sstevel@tonic-gate return (bp_mapin_common(&buf, flag)); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /* 3317c478bd9Sstevel@tonic-gate * support routine - map page array into kernel virtual 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate static caddr_t 3347c478bd9Sstevel@tonic-gate dmareq_pplist_mapin(uint_t len, caddr_t addr, page_t **pplist, struct as *as, 3357c478bd9Sstevel@tonic-gate int flag) 3367c478bd9Sstevel@tonic-gate { 3377c478bd9Sstevel@tonic-gate struct buf buf; 3387c478bd9Sstevel@tonic-gate struct proc proc; 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* 3417c478bd9Sstevel@tonic-gate * mock up a buf structure so we can call bp_mapin_common() 3427c478bd9Sstevel@tonic-gate */ 3437c478bd9Sstevel@tonic-gate buf.b_flags = B_PHYS|B_SHADOW; 3447c478bd9Sstevel@tonic-gate buf.b_un.b_addr = addr; 3457c478bd9Sstevel@tonic-gate buf.b_bcount = len; 3467c478bd9Sstevel@tonic-gate buf.b_shadow = pplist; 3477c478bd9Sstevel@tonic-gate proc.p_as = as; 3487c478bd9Sstevel@tonic-gate buf.b_proc = &proc; 3497c478bd9Sstevel@tonic-gate return (bp_mapin_common(&buf, flag)); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* 3547c478bd9Sstevel@tonic-gate * support routine - map dmareq into kernel virtual if not already 3557c478bd9Sstevel@tonic-gate * fills in *lenp with length 3567c478bd9Sstevel@tonic-gate * *mapaddr will be new kernel virtual address - or null if no mapping needed 3577c478bd9Sstevel@tonic-gate */ 3587c478bd9Sstevel@tonic-gate static caddr_t 3597c478bd9Sstevel@tonic-gate ddi_dmareq_mapin(struct ddi_dma_req *dmareqp, caddr_t *mapaddrp, 3607c478bd9Sstevel@tonic-gate offset_t *lenp) 3617c478bd9Sstevel@tonic-gate { 3627c478bd9Sstevel@tonic-gate int sleep = (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? VM_SLEEP: VM_NOSLEEP; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate *lenp = dmareqp->dmar_object.dmao_size; 3657c478bd9Sstevel@tonic-gate if (dmareqp->dmar_object.dmao_type == DMA_OTYP_PAGES) { 3667c478bd9Sstevel@tonic-gate *mapaddrp = dmareq_pp_mapin(dmareqp->dmar_object.dmao_size, 3677c478bd9Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.pp_obj.pp_offset, 3687c478bd9Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.pp_obj.pp_pp, sleep); 3697c478bd9Sstevel@tonic-gate return (*mapaddrp); 3707c478bd9Sstevel@tonic-gate } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_priv != NULL) { 3717c478bd9Sstevel@tonic-gate *mapaddrp = dmareq_pplist_mapin(dmareqp->dmar_object.dmao_size, 3727c478bd9Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_addr, 3737c478bd9Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_priv, 3747c478bd9Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_as, sleep); 3757c478bd9Sstevel@tonic-gate return (*mapaddrp); 3767c478bd9Sstevel@tonic-gate } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_as == &kas) { 3777c478bd9Sstevel@tonic-gate *mapaddrp = NULL; 3787c478bd9Sstevel@tonic-gate return (dmareqp->dmar_object.dmao_obj.virt_obj.v_addr); 3797c478bd9Sstevel@tonic-gate } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_as == NULL) { 3807c478bd9Sstevel@tonic-gate *mapaddrp = NULL; 3817c478bd9Sstevel@tonic-gate return (dmareqp->dmar_object.dmao_obj.virt_obj.v_addr); 3827c478bd9Sstevel@tonic-gate } else { 3837c478bd9Sstevel@tonic-gate *mapaddrp = dmareq_mapin(dmareqp->dmar_object.dmao_size, 3847c478bd9Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_addr, 3857c478bd9Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_as, sleep); 3867c478bd9Sstevel@tonic-gate return (*mapaddrp); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * support routine - free off kernel virtual mapping as allocated by 3937c478bd9Sstevel@tonic-gate * ddi_dmareq_mapin() 3947c478bd9Sstevel@tonic-gate */ 3957c478bd9Sstevel@tonic-gate static void 3967c478bd9Sstevel@tonic-gate ddi_dmareq_mapout(caddr_t addr, offset_t len) 3977c478bd9Sstevel@tonic-gate { 3987c478bd9Sstevel@tonic-gate struct buf buf; 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate if (addr == NULL) 4017c478bd9Sstevel@tonic-gate return; 4027c478bd9Sstevel@tonic-gate /* 4037c478bd9Sstevel@tonic-gate * mock up a buf structure 4047c478bd9Sstevel@tonic-gate */ 4057c478bd9Sstevel@tonic-gate buf.b_flags = B_REMAPPED; 4067c478bd9Sstevel@tonic-gate buf.b_un.b_addr = addr; 4077c478bd9Sstevel@tonic-gate buf.b_bcount = (size_t)len; 4087c478bd9Sstevel@tonic-gate bp_mapout(&buf); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate static time_t 4127c478bd9Sstevel@tonic-gate bofi_gettime() 4137c478bd9Sstevel@tonic-gate { 4147c478bd9Sstevel@tonic-gate timestruc_t ts; 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate gethrestime(&ts); 4177c478bd9Sstevel@tonic-gate return (ts.tv_sec); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate /* 4217c478bd9Sstevel@tonic-gate * reset the bus_ops structure of the specified nexus to point to 4227c478bd9Sstevel@tonic-gate * the original values in the save_bus_ops structure. 4237c478bd9Sstevel@tonic-gate * 4247c478bd9Sstevel@tonic-gate * Note that both this routine and modify_bus_ops() rely on the current 4257c478bd9Sstevel@tonic-gate * behavior of the framework in that nexus drivers are not unloadable 4267c478bd9Sstevel@tonic-gate * 4277c478bd9Sstevel@tonic-gate */ 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate static int 4307c478bd9Sstevel@tonic-gate reset_bus_ops(char *name, struct bus_ops *bop) 4317c478bd9Sstevel@tonic-gate { 4327c478bd9Sstevel@tonic-gate struct modctl *modp; 4337c478bd9Sstevel@tonic-gate struct modldrv *mp; 4347c478bd9Sstevel@tonic-gate struct bus_ops *bp; 4357c478bd9Sstevel@tonic-gate struct dev_ops *ops; 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * find specified module 4407c478bd9Sstevel@tonic-gate */ 4417c478bd9Sstevel@tonic-gate modp = &modules; 4427c478bd9Sstevel@tonic-gate do { 4437c478bd9Sstevel@tonic-gate if (strcmp(name, modp->mod_modname) == 0) { 4447c478bd9Sstevel@tonic-gate if (!modp->mod_linkage) { 4457c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 4467c478bd9Sstevel@tonic-gate return (0); 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate mp = modp->mod_linkage->ml_linkage[0]; 4497c478bd9Sstevel@tonic-gate if (!mp || !mp->drv_dev_ops) { 4507c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 4517c478bd9Sstevel@tonic-gate return (0); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate ops = mp->drv_dev_ops; 4547c478bd9Sstevel@tonic-gate bp = ops->devo_bus_ops; 4557c478bd9Sstevel@tonic-gate if (!bp) { 4567c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 4577c478bd9Sstevel@tonic-gate return (0); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate if (ops->devo_refcnt > 0) { 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * As long as devices are active with modified 4627c478bd9Sstevel@tonic-gate * bus ops bofi must not go away. There may be 4637c478bd9Sstevel@tonic-gate * drivers with modified access or dma handles. 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 4667c478bd9Sstevel@tonic-gate return (0); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "bofi reset bus_ops for %s", 4697c478bd9Sstevel@tonic-gate mp->drv_linkinfo); 4707c478bd9Sstevel@tonic-gate bp->bus_intr_op = bop->bus_intr_op; 4717c478bd9Sstevel@tonic-gate bp->bus_post_event = bop->bus_post_event; 4727c478bd9Sstevel@tonic-gate bp->bus_map = bop->bus_map; 4737c478bd9Sstevel@tonic-gate bp->bus_dma_map = bop->bus_dma_map; 4747c478bd9Sstevel@tonic-gate bp->bus_dma_allochdl = bop->bus_dma_allochdl; 4757c478bd9Sstevel@tonic-gate bp->bus_dma_freehdl = bop->bus_dma_freehdl; 4767c478bd9Sstevel@tonic-gate bp->bus_dma_bindhdl = bop->bus_dma_bindhdl; 4777c478bd9Sstevel@tonic-gate bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl; 4787c478bd9Sstevel@tonic-gate bp->bus_dma_flush = bop->bus_dma_flush; 4797c478bd9Sstevel@tonic-gate bp->bus_dma_win = bop->bus_dma_win; 4807c478bd9Sstevel@tonic-gate bp->bus_dma_ctl = bop->bus_dma_ctl; 4817c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 4827c478bd9Sstevel@tonic-gate return (1); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules); 4857c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 4867c478bd9Sstevel@tonic-gate return (0); 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate /* 4907c478bd9Sstevel@tonic-gate * modify the bus_ops structure of the specified nexus to point to bofi 4917c478bd9Sstevel@tonic-gate * routines, saving the original values in the save_bus_ops structure 4927c478bd9Sstevel@tonic-gate */ 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate static int 4957c478bd9Sstevel@tonic-gate modify_bus_ops(char *name, struct bus_ops *bop) 4967c478bd9Sstevel@tonic-gate { 4977c478bd9Sstevel@tonic-gate struct modctl *modp; 4987c478bd9Sstevel@tonic-gate struct modldrv *mp; 4997c478bd9Sstevel@tonic-gate struct bus_ops *bp; 5007c478bd9Sstevel@tonic-gate struct dev_ops *ops; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate if (ddi_name_to_major(name) == -1) 5037c478bd9Sstevel@tonic-gate return (0); 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 5067c478bd9Sstevel@tonic-gate /* 5077c478bd9Sstevel@tonic-gate * find specified module 5087c478bd9Sstevel@tonic-gate */ 5097c478bd9Sstevel@tonic-gate modp = &modules; 5107c478bd9Sstevel@tonic-gate do { 5117c478bd9Sstevel@tonic-gate if (strcmp(name, modp->mod_modname) == 0) { 5127c478bd9Sstevel@tonic-gate if (!modp->mod_linkage) { 5137c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 5147c478bd9Sstevel@tonic-gate return (0); 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate mp = modp->mod_linkage->ml_linkage[0]; 5177c478bd9Sstevel@tonic-gate if (!mp || !mp->drv_dev_ops) { 5187c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 5197c478bd9Sstevel@tonic-gate return (0); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate ops = mp->drv_dev_ops; 5227c478bd9Sstevel@tonic-gate bp = ops->devo_bus_ops; 5237c478bd9Sstevel@tonic-gate if (!bp) { 5247c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 5257c478bd9Sstevel@tonic-gate return (0); 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate if (ops->devo_refcnt == 0) { 5287c478bd9Sstevel@tonic-gate /* 5297c478bd9Sstevel@tonic-gate * If there is no device active for this 5307c478bd9Sstevel@tonic-gate * module then there is nothing to do for bofi. 5317c478bd9Sstevel@tonic-gate */ 5327c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 5337c478bd9Sstevel@tonic-gate return (0); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "bofi modify bus_ops for %s", 5367c478bd9Sstevel@tonic-gate mp->drv_linkinfo); 5377c478bd9Sstevel@tonic-gate save_bus_ops = *bp; 5387c478bd9Sstevel@tonic-gate bp->bus_intr_op = bop->bus_intr_op; 5397c478bd9Sstevel@tonic-gate bp->bus_post_event = bop->bus_post_event; 5407c478bd9Sstevel@tonic-gate bp->bus_map = bop->bus_map; 5417c478bd9Sstevel@tonic-gate bp->bus_dma_map = bop->bus_dma_map; 5427c478bd9Sstevel@tonic-gate bp->bus_dma_allochdl = bop->bus_dma_allochdl; 5437c478bd9Sstevel@tonic-gate bp->bus_dma_freehdl = bop->bus_dma_freehdl; 5447c478bd9Sstevel@tonic-gate bp->bus_dma_bindhdl = bop->bus_dma_bindhdl; 5457c478bd9Sstevel@tonic-gate bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl; 5467c478bd9Sstevel@tonic-gate bp->bus_dma_flush = bop->bus_dma_flush; 5477c478bd9Sstevel@tonic-gate bp->bus_dma_win = bop->bus_dma_win; 5487c478bd9Sstevel@tonic-gate bp->bus_dma_ctl = bop->bus_dma_ctl; 5497c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 5507c478bd9Sstevel@tonic-gate return (1); 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules); 5537c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 5547c478bd9Sstevel@tonic-gate return (0); 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate int 5597c478bd9Sstevel@tonic-gate _init(void) 5607c478bd9Sstevel@tonic-gate { 5617c478bd9Sstevel@tonic-gate int e; 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate e = ddi_soft_state_init(&statep, sizeof (struct bofi_errent), 1); 5647c478bd9Sstevel@tonic-gate if (e != 0) 5657c478bd9Sstevel@tonic-gate return (e); 5667c478bd9Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) 5677c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&statep); 5687c478bd9Sstevel@tonic-gate return (e); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate int 5737c478bd9Sstevel@tonic-gate _fini(void) 5747c478bd9Sstevel@tonic-gate { 5757c478bd9Sstevel@tonic-gate int e; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) != 0) 5787c478bd9Sstevel@tonic-gate return (e); 5797c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&statep); 5807c478bd9Sstevel@tonic-gate return (e); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate int 5857c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 5867c478bd9Sstevel@tonic-gate { 5877c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate static int 5927c478bd9Sstevel@tonic-gate bofi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 5937c478bd9Sstevel@tonic-gate { 5947c478bd9Sstevel@tonic-gate char *name; 5957c478bd9Sstevel@tonic-gate char buf[80]; 5967c478bd9Sstevel@tonic-gate int i; 5977c478bd9Sstevel@tonic-gate int s, ss; 5987c478bd9Sstevel@tonic-gate int size = NAMESIZE; 5997c478bd9Sstevel@tonic-gate int new_string; 6007c478bd9Sstevel@tonic-gate char *ptr; 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 6037c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6047c478bd9Sstevel@tonic-gate /* 6057c478bd9Sstevel@tonic-gate * only one instance - but we clone using the open routine 6067c478bd9Sstevel@tonic-gate */ 6077c478bd9Sstevel@tonic-gate if (ddi_get_instance(dip) > 0) 6087c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate if (!initialized) { 6117c478bd9Sstevel@tonic-gate if ((name = ddi_get_name(dip)) == NULL) 6127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6137c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s,ctl", name); 6147c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, buf, S_IFCHR, 0, 6157c478bd9Sstevel@tonic-gate DDI_PSEUDO, NULL) == DDI_FAILURE) 6167c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_MED, 6197c478bd9Sstevel@tonic-gate &bofi_low_cookie) != DDI_SUCCESS) { 6207c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 6217c478bd9Sstevel@tonic-gate return (DDI_FAILURE); /* fail attach */ 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate /* 6247c478bd9Sstevel@tonic-gate * get nexus name (from conf file) 6257c478bd9Sstevel@tonic-gate */ 6267c478bd9Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0, 6277c478bd9Sstevel@tonic-gate "bofi-nexus", nexus_name, &size) != DDI_PROP_SUCCESS) { 6287c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 6297c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * get whether to do dma map kmem private checking 6337c478bd9Sstevel@tonic-gate */ 6347c478bd9Sstevel@tonic-gate if ((bofi_range_check = ddi_prop_lookup_string(DDI_DEV_T_ANY, 6357c478bd9Sstevel@tonic-gate dip, 0, "bofi-range-check", &ptr)) != DDI_PROP_SUCCESS) 6367c478bd9Sstevel@tonic-gate bofi_range_check = 0; 6377c478bd9Sstevel@tonic-gate else if (strcmp(ptr, "panic") == 0) 6387c478bd9Sstevel@tonic-gate bofi_range_check = 2; 6397c478bd9Sstevel@tonic-gate else if (strcmp(ptr, "warn") == 0) 6407c478bd9Sstevel@tonic-gate bofi_range_check = 1; 6417c478bd9Sstevel@tonic-gate else 6427c478bd9Sstevel@tonic-gate bofi_range_check = 0; 6437c478bd9Sstevel@tonic-gate ddi_prop_free(ptr); 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate /* 6467c478bd9Sstevel@tonic-gate * get whether to prevent direct access to register 6477c478bd9Sstevel@tonic-gate */ 6487c478bd9Sstevel@tonic-gate if ((bofi_ddi_check = ddi_prop_lookup_string(DDI_DEV_T_ANY, 6497c478bd9Sstevel@tonic-gate dip, 0, "bofi-ddi-check", &ptr)) != DDI_PROP_SUCCESS) 6507c478bd9Sstevel@tonic-gate bofi_ddi_check = 0; 6517c478bd9Sstevel@tonic-gate else if (strcmp(ptr, "on") == 0) 6527c478bd9Sstevel@tonic-gate bofi_ddi_check = 1; 6537c478bd9Sstevel@tonic-gate else 6547c478bd9Sstevel@tonic-gate bofi_ddi_check = 0; 6557c478bd9Sstevel@tonic-gate ddi_prop_free(ptr); 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate /* 6587c478bd9Sstevel@tonic-gate * get whether to do copy on ddi_dma_sync 6597c478bd9Sstevel@tonic-gate */ 6607c478bd9Sstevel@tonic-gate if ((bofi_sync_check = ddi_prop_lookup_string(DDI_DEV_T_ANY, 6617c478bd9Sstevel@tonic-gate dip, 0, "bofi-sync-check", &ptr)) != DDI_PROP_SUCCESS) 6627c478bd9Sstevel@tonic-gate bofi_sync_check = 0; 6637c478bd9Sstevel@tonic-gate else if (strcmp(ptr, "on") == 0) 6647c478bd9Sstevel@tonic-gate bofi_sync_check = 1; 6657c478bd9Sstevel@tonic-gate else 6667c478bd9Sstevel@tonic-gate bofi_sync_check = 0; 6677c478bd9Sstevel@tonic-gate ddi_prop_free(ptr); 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /* 6707c478bd9Sstevel@tonic-gate * get driver-under-test names (from conf file) 6717c478bd9Sstevel@tonic-gate */ 6727c478bd9Sstevel@tonic-gate size = NAMESIZE; 6737c478bd9Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0, 6747c478bd9Sstevel@tonic-gate "bofi-to-test", driver_list, &size) != DDI_PROP_SUCCESS) 6757c478bd9Sstevel@tonic-gate driver_list[0] = 0; 6767c478bd9Sstevel@tonic-gate /* 6777c478bd9Sstevel@tonic-gate * and convert into a sequence of strings 6787c478bd9Sstevel@tonic-gate */ 6797c478bd9Sstevel@tonic-gate driver_list_neg = 1; 6807c478bd9Sstevel@tonic-gate new_string = 1; 6817c478bd9Sstevel@tonic-gate driver_list_size = strlen(driver_list); 6827c478bd9Sstevel@tonic-gate for (i = 0; i < driver_list_size; i++) { 6837c478bd9Sstevel@tonic-gate if (driver_list[i] == ' ') { 6847c478bd9Sstevel@tonic-gate driver_list[i] = '\0'; 6857c478bd9Sstevel@tonic-gate new_string = 1; 6867c478bd9Sstevel@tonic-gate } else if (new_string) { 6877c478bd9Sstevel@tonic-gate if (driver_list[i] != '!') 6887c478bd9Sstevel@tonic-gate driver_list_neg = 0; 6897c478bd9Sstevel@tonic-gate new_string = 0; 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate /* 6937c478bd9Sstevel@tonic-gate * initialize mutex, lists 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate mutex_init(&clone_tab_mutex, NULL, MUTEX_DRIVER, 6967c478bd9Sstevel@tonic-gate NULL); 6977c478bd9Sstevel@tonic-gate /* 6987c478bd9Sstevel@tonic-gate * fake up iblock cookie - need to protect outselves 6997c478bd9Sstevel@tonic-gate * against drivers that use hilevel interrupts 7007c478bd9Sstevel@tonic-gate */ 7017c478bd9Sstevel@tonic-gate ss = spl8(); 7027c478bd9Sstevel@tonic-gate s = spl8(); 7037c478bd9Sstevel@tonic-gate splx(ss); 7047c478bd9Sstevel@tonic-gate mutex_init(&bofi_mutex, NULL, MUTEX_SPIN, (void *)(uintptr_t)s); 7057c478bd9Sstevel@tonic-gate mutex_init(&bofi_low_mutex, NULL, MUTEX_DRIVER, 7067c478bd9Sstevel@tonic-gate (void *)bofi_low_cookie); 7077c478bd9Sstevel@tonic-gate shadow_list.next = &shadow_list; 7087c478bd9Sstevel@tonic-gate shadow_list.prev = &shadow_list; 7097c478bd9Sstevel@tonic-gate for (i = 0; i < HDL_HASH_TBL_SIZE; i++) { 7107c478bd9Sstevel@tonic-gate hhash_table[i].hnext = &hhash_table[i]; 7117c478bd9Sstevel@tonic-gate hhash_table[i].hprev = &hhash_table[i]; 7127c478bd9Sstevel@tonic-gate dhash_table[i].dnext = &dhash_table[i]; 7137c478bd9Sstevel@tonic-gate dhash_table[i].dprev = &dhash_table[i]; 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate for (i = 1; i < BOFI_NLINKS; i++) 7167c478bd9Sstevel@tonic-gate bofi_link_array[i].link = &bofi_link_array[i-1]; 7177c478bd9Sstevel@tonic-gate bofi_link_freelist = &bofi_link_array[BOFI_NLINKS - 1]; 7187c478bd9Sstevel@tonic-gate /* 7197c478bd9Sstevel@tonic-gate * overlay bus_ops structure 7207c478bd9Sstevel@tonic-gate */ 7217c478bd9Sstevel@tonic-gate if (modify_bus_ops(nexus_name, &bofi_bus_ops) == 0) { 7227c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 7237c478bd9Sstevel@tonic-gate mutex_destroy(&clone_tab_mutex); 7247c478bd9Sstevel@tonic-gate mutex_destroy(&bofi_mutex); 7257c478bd9Sstevel@tonic-gate mutex_destroy(&bofi_low_mutex); 7267c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate /* 7297c478bd9Sstevel@tonic-gate * save dip for getinfo 7307c478bd9Sstevel@tonic-gate */ 7317c478bd9Sstevel@tonic-gate our_dip = dip; 7327c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 7337c478bd9Sstevel@tonic-gate initialized = 1; 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate static int 7407c478bd9Sstevel@tonic-gate bofi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 7417c478bd9Sstevel@tonic-gate { 7427c478bd9Sstevel@tonic-gate char *name; 7437c478bd9Sstevel@tonic-gate char buf[80]; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) 7467c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7477c478bd9Sstevel@tonic-gate if (ddi_get_instance(dip) > 0) 7487c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7497c478bd9Sstevel@tonic-gate if ((name = ddi_get_name(dip)) == NULL) 7507c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7517c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s,ctl", name); 7527c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 7537c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 7547c478bd9Sstevel@tonic-gate /* 7557c478bd9Sstevel@tonic-gate * make sure test bofi is no longer in use 7567c478bd9Sstevel@tonic-gate */ 7577c478bd9Sstevel@tonic-gate if (shadow_list.next != &shadow_list || errent_listp != NULL) { 7587c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 7597c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 7607c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 7637c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate /* 7667c478bd9Sstevel@tonic-gate * restore bus_ops structure 7677c478bd9Sstevel@tonic-gate */ 7687c478bd9Sstevel@tonic-gate if (reset_bus_ops(nexus_name, &save_bus_ops) == 0) 7697c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate mutex_destroy(&clone_tab_mutex); 7727c478bd9Sstevel@tonic-gate mutex_destroy(&bofi_mutex); 7737c478bd9Sstevel@tonic-gate mutex_destroy(&bofi_low_mutex); 7747c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 7757c478bd9Sstevel@tonic-gate our_dip = NULL; 7767c478bd9Sstevel@tonic-gate initialized = 0; 7777c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7827c478bd9Sstevel@tonic-gate static int 7837c478bd9Sstevel@tonic-gate bofi_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 7847c478bd9Sstevel@tonic-gate { 7857c478bd9Sstevel@tonic-gate dev_t dev = (dev_t)arg; 7867c478bd9Sstevel@tonic-gate int minor = (int)getminor(dev); 7877c478bd9Sstevel@tonic-gate int retval; 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate switch (cmd) { 7907c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 7917c478bd9Sstevel@tonic-gate if (minor != 0 || our_dip == NULL) { 7927c478bd9Sstevel@tonic-gate *result = (void *)NULL; 7937c478bd9Sstevel@tonic-gate retval = DDI_FAILURE; 7947c478bd9Sstevel@tonic-gate } else { 7957c478bd9Sstevel@tonic-gate *result = (void *)our_dip; 7967c478bd9Sstevel@tonic-gate retval = DDI_SUCCESS; 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate break; 7997c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 8007c478bd9Sstevel@tonic-gate *result = (void *)0; 8017c478bd9Sstevel@tonic-gate retval = DDI_SUCCESS; 8027c478bd9Sstevel@tonic-gate break; 8037c478bd9Sstevel@tonic-gate default: 8047c478bd9Sstevel@tonic-gate retval = DDI_FAILURE; 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate return (retval); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8117c478bd9Sstevel@tonic-gate static int 8127c478bd9Sstevel@tonic-gate bofi_open(dev_t *devp, int flag, int otyp, cred_t *credp) 8137c478bd9Sstevel@tonic-gate { 8147c478bd9Sstevel@tonic-gate int minor = (int)getminor(*devp); 8157c478bd9Sstevel@tonic-gate struct bofi_errent *softc; 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* 8187c478bd9Sstevel@tonic-gate * only allow open on minor=0 - the clone device 8197c478bd9Sstevel@tonic-gate */ 8207c478bd9Sstevel@tonic-gate if (minor != 0) 8217c478bd9Sstevel@tonic-gate return (ENXIO); 8227c478bd9Sstevel@tonic-gate /* 8237c478bd9Sstevel@tonic-gate * fail if not attached 8247c478bd9Sstevel@tonic-gate */ 8257c478bd9Sstevel@tonic-gate if (!initialized) 8267c478bd9Sstevel@tonic-gate return (ENXIO); 8277c478bd9Sstevel@tonic-gate /* 8287c478bd9Sstevel@tonic-gate * find a free slot and grab it 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate mutex_enter(&clone_tab_mutex); 8317c478bd9Sstevel@tonic-gate for (minor = 1; minor < NCLONES; minor++) { 8327c478bd9Sstevel@tonic-gate if (clone_tab[minor] == 0) { 8337c478bd9Sstevel@tonic-gate clone_tab[minor] = 1; 8347c478bd9Sstevel@tonic-gate break; 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate mutex_exit(&clone_tab_mutex); 8387c478bd9Sstevel@tonic-gate if (minor == NCLONES) 8397c478bd9Sstevel@tonic-gate return (EAGAIN); 8407c478bd9Sstevel@tonic-gate /* 8417c478bd9Sstevel@tonic-gate * soft state structure for this clone is used to maintain a list 8427c478bd9Sstevel@tonic-gate * of allocated errdefs so they can be freed on close 8437c478bd9Sstevel@tonic-gate */ 8447c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(statep, minor) != DDI_SUCCESS) { 8457c478bd9Sstevel@tonic-gate mutex_enter(&clone_tab_mutex); 8467c478bd9Sstevel@tonic-gate clone_tab[minor] = 0; 8477c478bd9Sstevel@tonic-gate mutex_exit(&clone_tab_mutex); 8487c478bd9Sstevel@tonic-gate return (EAGAIN); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate softc = ddi_get_soft_state(statep, minor); 8517c478bd9Sstevel@tonic-gate softc->cnext = softc; 8527c478bd9Sstevel@tonic-gate softc->cprev = softc; 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), minor); 8557c478bd9Sstevel@tonic-gate return (0); 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8607c478bd9Sstevel@tonic-gate static int 8617c478bd9Sstevel@tonic-gate bofi_close(dev_t dev, int flag, int otyp, cred_t *credp) 8627c478bd9Sstevel@tonic-gate { 8637c478bd9Sstevel@tonic-gate int minor = (int)getminor(dev); 8647c478bd9Sstevel@tonic-gate struct bofi_errent *softc; 8657c478bd9Sstevel@tonic-gate struct bofi_errent *ep, *next_ep; 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate softc = ddi_get_soft_state(statep, minor); 8687c478bd9Sstevel@tonic-gate if (softc == NULL) 8697c478bd9Sstevel@tonic-gate return (ENXIO); 8707c478bd9Sstevel@tonic-gate /* 8717c478bd9Sstevel@tonic-gate * find list of errdefs and free them off 8727c478bd9Sstevel@tonic-gate */ 8737c478bd9Sstevel@tonic-gate for (ep = softc->cnext; ep != softc; ) { 8747c478bd9Sstevel@tonic-gate next_ep = ep->cnext; 8757c478bd9Sstevel@tonic-gate (void) bofi_errdef_free(ep); 8767c478bd9Sstevel@tonic-gate ep = next_ep; 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate /* 8797c478bd9Sstevel@tonic-gate * free clone tab slot 8807c478bd9Sstevel@tonic-gate */ 8817c478bd9Sstevel@tonic-gate mutex_enter(&clone_tab_mutex); 8827c478bd9Sstevel@tonic-gate clone_tab[minor] = 0; 8837c478bd9Sstevel@tonic-gate mutex_exit(&clone_tab_mutex); 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate ddi_soft_state_free(statep, minor); 8867c478bd9Sstevel@tonic-gate return (0); 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8917c478bd9Sstevel@tonic-gate static int 8927c478bd9Sstevel@tonic-gate bofi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 8937c478bd9Sstevel@tonic-gate int *rvalp) 8947c478bd9Sstevel@tonic-gate { 8957c478bd9Sstevel@tonic-gate struct bofi_errent *softc; 8967c478bd9Sstevel@tonic-gate int minor = (int)getminor(dev); 8977c478bd9Sstevel@tonic-gate struct bofi_errdef errdef; 8987c478bd9Sstevel@tonic-gate struct bofi_errctl errctl; 8997c478bd9Sstevel@tonic-gate struct bofi_errstate errstate; 9007c478bd9Sstevel@tonic-gate void *ed_handle; 9017c478bd9Sstevel@tonic-gate struct bofi_get_handles get_handles; 9027c478bd9Sstevel@tonic-gate struct bofi_get_hdl_info hdl_info; 9037c478bd9Sstevel@tonic-gate struct handle_info *hdlip; 9047c478bd9Sstevel@tonic-gate struct handle_info *hib; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate char *buffer; 9077c478bd9Sstevel@tonic-gate char *bufptr; 9087c478bd9Sstevel@tonic-gate char *endbuf; 9097c478bd9Sstevel@tonic-gate int req_count, count, err; 9107c478bd9Sstevel@tonic-gate char *namep; 9117c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 9127c478bd9Sstevel@tonic-gate int retval; 9137c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 9147c478bd9Sstevel@tonic-gate int i; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate switch (cmd) { 9177c478bd9Sstevel@tonic-gate case BOFI_ADD_DEF: 9187c478bd9Sstevel@tonic-gate /* 9197c478bd9Sstevel@tonic-gate * add a new error definition 9207c478bd9Sstevel@tonic-gate */ 9217c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 9227c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 9237c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: 9247c478bd9Sstevel@tonic-gate { 9257c478bd9Sstevel@tonic-gate /* 9267c478bd9Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 9277c478bd9Sstevel@tonic-gate * 64 bit ioctl 9287c478bd9Sstevel@tonic-gate */ 9297c478bd9Sstevel@tonic-gate struct bofi_errdef32 errdef_32; 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errdef_32, 9327c478bd9Sstevel@tonic-gate sizeof (struct bofi_errdef32), mode)) { 9337c478bd9Sstevel@tonic-gate return (EFAULT); 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate errdef.namesize = errdef_32.namesize; 9367c478bd9Sstevel@tonic-gate (void) strncpy(errdef.name, errdef_32.name, NAMESIZE); 9377c478bd9Sstevel@tonic-gate errdef.instance = errdef_32.instance; 9387c478bd9Sstevel@tonic-gate errdef.rnumber = errdef_32.rnumber; 9397c478bd9Sstevel@tonic-gate errdef.offset = errdef_32.offset; 9407c478bd9Sstevel@tonic-gate errdef.len = errdef_32.len; 9417c478bd9Sstevel@tonic-gate errdef.access_type = errdef_32.access_type; 9427c478bd9Sstevel@tonic-gate errdef.access_count = errdef_32.access_count; 9437c478bd9Sstevel@tonic-gate errdef.fail_count = errdef_32.fail_count; 9447c478bd9Sstevel@tonic-gate errdef.acc_chk = errdef_32.acc_chk; 9457c478bd9Sstevel@tonic-gate errdef.optype = errdef_32.optype; 9467c478bd9Sstevel@tonic-gate errdef.operand = errdef_32.operand; 9477c478bd9Sstevel@tonic-gate errdef.log.logsize = errdef_32.log.logsize; 9487c478bd9Sstevel@tonic-gate errdef.log.entries = errdef_32.log.entries; 9497c478bd9Sstevel@tonic-gate errdef.log.flags = errdef_32.log.flags; 9507c478bd9Sstevel@tonic-gate errdef.log.wrapcnt = errdef_32.log.wrapcnt; 9517c478bd9Sstevel@tonic-gate errdef.log.start_time = errdef_32.log.start_time; 9527c478bd9Sstevel@tonic-gate errdef.log.stop_time = errdef_32.log.stop_time; 9537c478bd9Sstevel@tonic-gate errdef.log.logbase = 9547c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)errdef_32.log.logbase; 9557c478bd9Sstevel@tonic-gate errdef.errdef_handle = errdef_32.errdef_handle; 9567c478bd9Sstevel@tonic-gate break; 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 9597c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errdef, 9607c478bd9Sstevel@tonic-gate sizeof (struct bofi_errdef), mode)) 9617c478bd9Sstevel@tonic-gate return (EFAULT); 9627c478bd9Sstevel@tonic-gate break; 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 9657c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errdef, 9667c478bd9Sstevel@tonic-gate sizeof (struct bofi_errdef), mode) != 0) 9677c478bd9Sstevel@tonic-gate return (EFAULT); 9687c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 9697c478bd9Sstevel@tonic-gate /* 9707c478bd9Sstevel@tonic-gate * do some validation 9717c478bd9Sstevel@tonic-gate */ 9727c478bd9Sstevel@tonic-gate if (errdef.fail_count == 0) 9737c478bd9Sstevel@tonic-gate errdef.optype = 0; 9747c478bd9Sstevel@tonic-gate if (errdef.optype != 0) { 9757c478bd9Sstevel@tonic-gate if (errdef.access_type & BOFI_INTR && 9767c478bd9Sstevel@tonic-gate errdef.optype != BOFI_DELAY_INTR && 9777c478bd9Sstevel@tonic-gate errdef.optype != BOFI_LOSE_INTR && 9787c478bd9Sstevel@tonic-gate errdef.optype != BOFI_EXTRA_INTR) 9797c478bd9Sstevel@tonic-gate return (EINVAL); 9807c478bd9Sstevel@tonic-gate if ((errdef.access_type & (BOFI_DMA_RW|BOFI_PIO_R)) && 9817c478bd9Sstevel@tonic-gate errdef.optype == BOFI_NO_TRANSFER) 9827c478bd9Sstevel@tonic-gate return (EINVAL); 9837c478bd9Sstevel@tonic-gate if ((errdef.access_type & (BOFI_PIO_RW)) && 9847c478bd9Sstevel@tonic-gate errdef.optype != BOFI_EQUAL && 9857c478bd9Sstevel@tonic-gate errdef.optype != BOFI_OR && 9867c478bd9Sstevel@tonic-gate errdef.optype != BOFI_XOR && 9877c478bd9Sstevel@tonic-gate errdef.optype != BOFI_AND && 9887c478bd9Sstevel@tonic-gate errdef.optype != BOFI_NO_TRANSFER) 9897c478bd9Sstevel@tonic-gate return (EINVAL); 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate /* 9927c478bd9Sstevel@tonic-gate * find softstate for this clone, so we can tag 9937c478bd9Sstevel@tonic-gate * new errdef on to it 9947c478bd9Sstevel@tonic-gate */ 9957c478bd9Sstevel@tonic-gate softc = ddi_get_soft_state(statep, minor); 9967c478bd9Sstevel@tonic-gate if (softc == NULL) 9977c478bd9Sstevel@tonic-gate return (ENXIO); 9987c478bd9Sstevel@tonic-gate /* 9997c478bd9Sstevel@tonic-gate * read in name 10007c478bd9Sstevel@tonic-gate */ 10017c478bd9Sstevel@tonic-gate if (errdef.namesize > NAMESIZE) 10027c478bd9Sstevel@tonic-gate return (EINVAL); 10037c478bd9Sstevel@tonic-gate namep = kmem_zalloc(errdef.namesize+1, KM_SLEEP); 10047c478bd9Sstevel@tonic-gate (void) strncpy(namep, errdef.name, errdef.namesize); 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate if (bofi_errdef_alloc(&errdef, namep, softc) != DDI_SUCCESS) { 10077c478bd9Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 10087c478bd9Sstevel@tonic-gate (uintptr_t)errdef.errdef_handle); 10097c478bd9Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 10107c478bd9Sstevel@tonic-gate return (EINVAL); 10117c478bd9Sstevel@tonic-gate } 10127c478bd9Sstevel@tonic-gate /* 10137c478bd9Sstevel@tonic-gate * copy out errdef again, including filled in errdef_handle 10147c478bd9Sstevel@tonic-gate */ 10157c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 10167c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 10177c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: 10187c478bd9Sstevel@tonic-gate { 10197c478bd9Sstevel@tonic-gate /* 10207c478bd9Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 10217c478bd9Sstevel@tonic-gate * 64 bit ioctl 10227c478bd9Sstevel@tonic-gate */ 10237c478bd9Sstevel@tonic-gate struct bofi_errdef32 errdef_32; 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate errdef_32.namesize = errdef.namesize; 10267c478bd9Sstevel@tonic-gate (void) strncpy(errdef_32.name, errdef.name, NAMESIZE); 10277c478bd9Sstevel@tonic-gate errdef_32.instance = errdef.instance; 10287c478bd9Sstevel@tonic-gate errdef_32.rnumber = errdef.rnumber; 10297c478bd9Sstevel@tonic-gate errdef_32.offset = errdef.offset; 10307c478bd9Sstevel@tonic-gate errdef_32.len = errdef.len; 10317c478bd9Sstevel@tonic-gate errdef_32.access_type = errdef.access_type; 10327c478bd9Sstevel@tonic-gate errdef_32.access_count = errdef.access_count; 10337c478bd9Sstevel@tonic-gate errdef_32.fail_count = errdef.fail_count; 10347c478bd9Sstevel@tonic-gate errdef_32.acc_chk = errdef.acc_chk; 10357c478bd9Sstevel@tonic-gate errdef_32.optype = errdef.optype; 10367c478bd9Sstevel@tonic-gate errdef_32.operand = errdef.operand; 10377c478bd9Sstevel@tonic-gate errdef_32.log.logsize = errdef.log.logsize; 10387c478bd9Sstevel@tonic-gate errdef_32.log.entries = errdef.log.entries; 10397c478bd9Sstevel@tonic-gate errdef_32.log.flags = errdef.log.flags; 10407c478bd9Sstevel@tonic-gate errdef_32.log.wrapcnt = errdef.log.wrapcnt; 10417c478bd9Sstevel@tonic-gate errdef_32.log.start_time = errdef.log.start_time; 10427c478bd9Sstevel@tonic-gate errdef_32.log.stop_time = errdef.log.stop_time; 10437c478bd9Sstevel@tonic-gate errdef_32.log.logbase = 10447c478bd9Sstevel@tonic-gate (caddr32_t)(uintptr_t)errdef.log.logbase; 10457c478bd9Sstevel@tonic-gate errdef_32.errdef_handle = errdef.errdef_handle; 10467c478bd9Sstevel@tonic-gate if (ddi_copyout(&errdef_32, (void *)arg, 10477c478bd9Sstevel@tonic-gate sizeof (struct bofi_errdef32), mode) != 0) { 10487c478bd9Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 10497c478bd9Sstevel@tonic-gate errdef.errdef_handle); 10507c478bd9Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 10517c478bd9Sstevel@tonic-gate return (EFAULT); 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate break; 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 10567c478bd9Sstevel@tonic-gate if (ddi_copyout(&errdef, (void *)arg, 10577c478bd9Sstevel@tonic-gate sizeof (struct bofi_errdef), mode) != 0) { 10587c478bd9Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 10597c478bd9Sstevel@tonic-gate errdef.errdef_handle); 10607c478bd9Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 10617c478bd9Sstevel@tonic-gate return (EFAULT); 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate break; 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 10667c478bd9Sstevel@tonic-gate if (ddi_copyout(&errdef, (void *)arg, 10677c478bd9Sstevel@tonic-gate sizeof (struct bofi_errdef), mode) != 0) { 10687c478bd9Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 10697c478bd9Sstevel@tonic-gate (uintptr_t)errdef.errdef_handle); 10707c478bd9Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 10717c478bd9Sstevel@tonic-gate return (EFAULT); 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 10747c478bd9Sstevel@tonic-gate return (0); 10757c478bd9Sstevel@tonic-gate case BOFI_DEL_DEF: 10767c478bd9Sstevel@tonic-gate /* 10777c478bd9Sstevel@tonic-gate * delete existing errdef 10787c478bd9Sstevel@tonic-gate */ 10797c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &ed_handle, 10807c478bd9Sstevel@tonic-gate sizeof (void *), mode) != 0) 10817c478bd9Sstevel@tonic-gate return (EFAULT); 10827c478bd9Sstevel@tonic-gate return (bofi_errdef_free((struct bofi_errent *)ed_handle)); 10837c478bd9Sstevel@tonic-gate case BOFI_START: 10847c478bd9Sstevel@tonic-gate /* 10857c478bd9Sstevel@tonic-gate * start all errdefs corresponding to 10867c478bd9Sstevel@tonic-gate * this name and instance 10877c478bd9Sstevel@tonic-gate */ 10887c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 10897c478bd9Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 10907c478bd9Sstevel@tonic-gate return (EFAULT); 10917c478bd9Sstevel@tonic-gate /* 10927c478bd9Sstevel@tonic-gate * copy in name 10937c478bd9Sstevel@tonic-gate */ 10947c478bd9Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 10957c478bd9Sstevel@tonic-gate return (EINVAL); 10967c478bd9Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 10977c478bd9Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 10987c478bd9Sstevel@tonic-gate bofi_start(&errctl, namep); 10997c478bd9Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 11007c478bd9Sstevel@tonic-gate return (0); 11017c478bd9Sstevel@tonic-gate case BOFI_STOP: 11027c478bd9Sstevel@tonic-gate /* 11037c478bd9Sstevel@tonic-gate * stop all errdefs corresponding to 11047c478bd9Sstevel@tonic-gate * this name and instance 11057c478bd9Sstevel@tonic-gate */ 11067c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 11077c478bd9Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 11087c478bd9Sstevel@tonic-gate return (EFAULT); 11097c478bd9Sstevel@tonic-gate /* 11107c478bd9Sstevel@tonic-gate * copy in name 11117c478bd9Sstevel@tonic-gate */ 11127c478bd9Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 11137c478bd9Sstevel@tonic-gate return (EINVAL); 11147c478bd9Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 11157c478bd9Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 11167c478bd9Sstevel@tonic-gate bofi_stop(&errctl, namep); 11177c478bd9Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 11187c478bd9Sstevel@tonic-gate return (0); 11197c478bd9Sstevel@tonic-gate case BOFI_BROADCAST: 11207c478bd9Sstevel@tonic-gate /* 11217c478bd9Sstevel@tonic-gate * wakeup all errdefs corresponding to 11227c478bd9Sstevel@tonic-gate * this name and instance 11237c478bd9Sstevel@tonic-gate */ 11247c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 11257c478bd9Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 11267c478bd9Sstevel@tonic-gate return (EFAULT); 11277c478bd9Sstevel@tonic-gate /* 11287c478bd9Sstevel@tonic-gate * copy in name 11297c478bd9Sstevel@tonic-gate */ 11307c478bd9Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 11317c478bd9Sstevel@tonic-gate return (EINVAL); 11327c478bd9Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 11337c478bd9Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 11347c478bd9Sstevel@tonic-gate bofi_broadcast(&errctl, namep); 11357c478bd9Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 11367c478bd9Sstevel@tonic-gate return (0); 11377c478bd9Sstevel@tonic-gate case BOFI_CLEAR_ACC_CHK: 11387c478bd9Sstevel@tonic-gate /* 11397c478bd9Sstevel@tonic-gate * clear "acc_chk" for all errdefs corresponding to 11407c478bd9Sstevel@tonic-gate * this name and instance 11417c478bd9Sstevel@tonic-gate */ 11427c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 11437c478bd9Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 11447c478bd9Sstevel@tonic-gate return (EFAULT); 11457c478bd9Sstevel@tonic-gate /* 11467c478bd9Sstevel@tonic-gate * copy in name 11477c478bd9Sstevel@tonic-gate */ 11487c478bd9Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 11497c478bd9Sstevel@tonic-gate return (EINVAL); 11507c478bd9Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 11517c478bd9Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 11527c478bd9Sstevel@tonic-gate bofi_clear_acc_chk(&errctl, namep); 11537c478bd9Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 11547c478bd9Sstevel@tonic-gate return (0); 11557c478bd9Sstevel@tonic-gate case BOFI_CLEAR_ERRORS: 11567c478bd9Sstevel@tonic-gate /* 11577c478bd9Sstevel@tonic-gate * set "fail_count" to 0 for all errdefs corresponding to 11587c478bd9Sstevel@tonic-gate * this name and instance whose "access_count" 11597c478bd9Sstevel@tonic-gate * has expired. 11607c478bd9Sstevel@tonic-gate */ 11617c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 11627c478bd9Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 11637c478bd9Sstevel@tonic-gate return (EFAULT); 11647c478bd9Sstevel@tonic-gate /* 11657c478bd9Sstevel@tonic-gate * copy in name 11667c478bd9Sstevel@tonic-gate */ 11677c478bd9Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 11687c478bd9Sstevel@tonic-gate return (EINVAL); 11697c478bd9Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 11707c478bd9Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 11717c478bd9Sstevel@tonic-gate bofi_clear_errors(&errctl, namep); 11727c478bd9Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 11737c478bd9Sstevel@tonic-gate return (0); 11747c478bd9Sstevel@tonic-gate case BOFI_CLEAR_ERRDEFS: 11757c478bd9Sstevel@tonic-gate /* 11767c478bd9Sstevel@tonic-gate * set "access_count" and "fail_count" to 0 for all errdefs 11777c478bd9Sstevel@tonic-gate * corresponding to this name and instance 11787c478bd9Sstevel@tonic-gate */ 11797c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 11807c478bd9Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 11817c478bd9Sstevel@tonic-gate return (EFAULT); 11827c478bd9Sstevel@tonic-gate /* 11837c478bd9Sstevel@tonic-gate * copy in name 11847c478bd9Sstevel@tonic-gate */ 11857c478bd9Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 11867c478bd9Sstevel@tonic-gate return (EINVAL); 11877c478bd9Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 11887c478bd9Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 11897c478bd9Sstevel@tonic-gate bofi_clear_errdefs(&errctl, namep); 11907c478bd9Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 11917c478bd9Sstevel@tonic-gate return (0); 11927c478bd9Sstevel@tonic-gate case BOFI_CHK_STATE: 11937c478bd9Sstevel@tonic-gate { 11947c478bd9Sstevel@tonic-gate struct acc_log_elem *klg; 11957c478bd9Sstevel@tonic-gate size_t uls; 11967c478bd9Sstevel@tonic-gate /* 11977c478bd9Sstevel@tonic-gate * get state for this errdef - read in dummy errstate 11987c478bd9Sstevel@tonic-gate * with just the errdef_handle filled in 11997c478bd9Sstevel@tonic-gate */ 12007c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 12017c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 12027c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: 12037c478bd9Sstevel@tonic-gate { 12047c478bd9Sstevel@tonic-gate /* 12057c478bd9Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 12067c478bd9Sstevel@tonic-gate * 64 bit ioctl 12077c478bd9Sstevel@tonic-gate */ 12087c478bd9Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate_32, 12117c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) { 12127c478bd9Sstevel@tonic-gate return (EFAULT); 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate errstate.fail_time = errstate_32.fail_time; 12157c478bd9Sstevel@tonic-gate errstate.msg_time = errstate_32.msg_time; 12167c478bd9Sstevel@tonic-gate errstate.access_count = errstate_32.access_count; 12177c478bd9Sstevel@tonic-gate errstate.fail_count = errstate_32.fail_count; 12187c478bd9Sstevel@tonic-gate errstate.acc_chk = errstate_32.acc_chk; 12197c478bd9Sstevel@tonic-gate errstate.errmsg_count = errstate_32.errmsg_count; 12207c478bd9Sstevel@tonic-gate (void) strncpy(errstate.buffer, errstate_32.buffer, 12217c478bd9Sstevel@tonic-gate ERRMSGSIZE); 12227c478bd9Sstevel@tonic-gate errstate.severity = errstate_32.severity; 12237c478bd9Sstevel@tonic-gate errstate.log.logsize = errstate_32.log.logsize; 12247c478bd9Sstevel@tonic-gate errstate.log.entries = errstate_32.log.entries; 12257c478bd9Sstevel@tonic-gate errstate.log.flags = errstate_32.log.flags; 12267c478bd9Sstevel@tonic-gate errstate.log.wrapcnt = errstate_32.log.wrapcnt; 12277c478bd9Sstevel@tonic-gate errstate.log.start_time = errstate_32.log.start_time; 12287c478bd9Sstevel@tonic-gate errstate.log.stop_time = errstate_32.log.stop_time; 12297c478bd9Sstevel@tonic-gate errstate.log.logbase = 12307c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)errstate_32.log.logbase; 12317c478bd9Sstevel@tonic-gate errstate.errdef_handle = errstate_32.errdef_handle; 12327c478bd9Sstevel@tonic-gate break; 12337c478bd9Sstevel@tonic-gate } 12347c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 12357c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 12367c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 12377c478bd9Sstevel@tonic-gate return (EFAULT); 12387c478bd9Sstevel@tonic-gate break; 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 12417c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 12427c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 12437c478bd9Sstevel@tonic-gate return (EFAULT); 12447c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 12457c478bd9Sstevel@tonic-gate if ((retval = bofi_errdef_check(&errstate, &klg)) == EINVAL) 12467c478bd9Sstevel@tonic-gate return (EINVAL); 12477c478bd9Sstevel@tonic-gate /* 12487c478bd9Sstevel@tonic-gate * copy out real errstate structure 12497c478bd9Sstevel@tonic-gate */ 12507c478bd9Sstevel@tonic-gate uls = errstate.log.logsize; 12517c478bd9Sstevel@tonic-gate if (errstate.log.entries > uls && uls) 12527c478bd9Sstevel@tonic-gate /* insufficient user memory */ 12537c478bd9Sstevel@tonic-gate errstate.log.entries = uls; 12547c478bd9Sstevel@tonic-gate /* always pass back a time */ 12557c478bd9Sstevel@tonic-gate if (errstate.log.stop_time == 0ul) 12567c478bd9Sstevel@tonic-gate (void) drv_getparm(TIME, &(errstate.log.stop_time)); 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 12597c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 12607c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: 12617c478bd9Sstevel@tonic-gate { 12627c478bd9Sstevel@tonic-gate /* 12637c478bd9Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 12647c478bd9Sstevel@tonic-gate * 64 bit ioctl 12657c478bd9Sstevel@tonic-gate */ 12667c478bd9Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate errstate_32.fail_time = errstate.fail_time; 12697c478bd9Sstevel@tonic-gate errstate_32.msg_time = errstate.msg_time; 12707c478bd9Sstevel@tonic-gate errstate_32.access_count = errstate.access_count; 12717c478bd9Sstevel@tonic-gate errstate_32.fail_count = errstate.fail_count; 12727c478bd9Sstevel@tonic-gate errstate_32.acc_chk = errstate.acc_chk; 12737c478bd9Sstevel@tonic-gate errstate_32.errmsg_count = errstate.errmsg_count; 12747c478bd9Sstevel@tonic-gate (void) strncpy(errstate_32.buffer, errstate.buffer, 12757c478bd9Sstevel@tonic-gate ERRMSGSIZE); 12767c478bd9Sstevel@tonic-gate errstate_32.severity = errstate.severity; 12777c478bd9Sstevel@tonic-gate errstate_32.log.logsize = errstate.log.logsize; 12787c478bd9Sstevel@tonic-gate errstate_32.log.entries = errstate.log.entries; 12797c478bd9Sstevel@tonic-gate errstate_32.log.flags = errstate.log.flags; 12807c478bd9Sstevel@tonic-gate errstate_32.log.wrapcnt = errstate.log.wrapcnt; 12817c478bd9Sstevel@tonic-gate errstate_32.log.start_time = errstate.log.start_time; 12827c478bd9Sstevel@tonic-gate errstate_32.log.stop_time = errstate.log.stop_time; 12837c478bd9Sstevel@tonic-gate errstate_32.log.logbase = 12847c478bd9Sstevel@tonic-gate (caddr32_t)(uintptr_t)errstate.log.logbase; 12857c478bd9Sstevel@tonic-gate errstate_32.errdef_handle = errstate.errdef_handle; 12867c478bd9Sstevel@tonic-gate if (ddi_copyout(&errstate_32, (void *)arg, 12877c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) 12887c478bd9Sstevel@tonic-gate return (EFAULT); 12897c478bd9Sstevel@tonic-gate break; 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 12927c478bd9Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 12937c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 12947c478bd9Sstevel@tonic-gate return (EFAULT); 12957c478bd9Sstevel@tonic-gate break; 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 12987c478bd9Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 12997c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 13007c478bd9Sstevel@tonic-gate return (EFAULT); 13017c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 13027c478bd9Sstevel@tonic-gate if (uls && errstate.log.entries && 13037c478bd9Sstevel@tonic-gate ddi_copyout(klg, errstate.log.logbase, 13047c478bd9Sstevel@tonic-gate errstate.log.entries * sizeof (struct acc_log_elem), 13057c478bd9Sstevel@tonic-gate mode) != 0) { 13067c478bd9Sstevel@tonic-gate return (EFAULT); 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate return (retval); 13097c478bd9Sstevel@tonic-gate } 13107c478bd9Sstevel@tonic-gate case BOFI_CHK_STATE_W: 13117c478bd9Sstevel@tonic-gate { 13127c478bd9Sstevel@tonic-gate struct acc_log_elem *klg; 13137c478bd9Sstevel@tonic-gate size_t uls; 13147c478bd9Sstevel@tonic-gate /* 13157c478bd9Sstevel@tonic-gate * get state for this errdef - read in dummy errstate 13167c478bd9Sstevel@tonic-gate * with just the errdef_handle filled in. Then wait for 13177c478bd9Sstevel@tonic-gate * a ddi_report_fault message to come back 13187c478bd9Sstevel@tonic-gate */ 13197c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 13207c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 13217c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: 13227c478bd9Sstevel@tonic-gate { 13237c478bd9Sstevel@tonic-gate /* 13247c478bd9Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 13257c478bd9Sstevel@tonic-gate * 64 bit ioctl 13267c478bd9Sstevel@tonic-gate */ 13277c478bd9Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate_32, 13307c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) { 13317c478bd9Sstevel@tonic-gate return (EFAULT); 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate errstate.fail_time = errstate_32.fail_time; 13347c478bd9Sstevel@tonic-gate errstate.msg_time = errstate_32.msg_time; 13357c478bd9Sstevel@tonic-gate errstate.access_count = errstate_32.access_count; 13367c478bd9Sstevel@tonic-gate errstate.fail_count = errstate_32.fail_count; 13377c478bd9Sstevel@tonic-gate errstate.acc_chk = errstate_32.acc_chk; 13387c478bd9Sstevel@tonic-gate errstate.errmsg_count = errstate_32.errmsg_count; 13397c478bd9Sstevel@tonic-gate (void) strncpy(errstate.buffer, errstate_32.buffer, 13407c478bd9Sstevel@tonic-gate ERRMSGSIZE); 13417c478bd9Sstevel@tonic-gate errstate.severity = errstate_32.severity; 13427c478bd9Sstevel@tonic-gate errstate.log.logsize = errstate_32.log.logsize; 13437c478bd9Sstevel@tonic-gate errstate.log.entries = errstate_32.log.entries; 13447c478bd9Sstevel@tonic-gate errstate.log.flags = errstate_32.log.flags; 13457c478bd9Sstevel@tonic-gate errstate.log.wrapcnt = errstate_32.log.wrapcnt; 13467c478bd9Sstevel@tonic-gate errstate.log.start_time = errstate_32.log.start_time; 13477c478bd9Sstevel@tonic-gate errstate.log.stop_time = errstate_32.log.stop_time; 13487c478bd9Sstevel@tonic-gate errstate.log.logbase = 13497c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)errstate_32.log.logbase; 13507c478bd9Sstevel@tonic-gate errstate.errdef_handle = errstate_32.errdef_handle; 13517c478bd9Sstevel@tonic-gate break; 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 13547c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 13557c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 13567c478bd9Sstevel@tonic-gate return (EFAULT); 13577c478bd9Sstevel@tonic-gate break; 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 13607c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 13617c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 13627c478bd9Sstevel@tonic-gate return (EFAULT); 13637c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 13647c478bd9Sstevel@tonic-gate if ((retval = bofi_errdef_check_w(&errstate, &klg)) == EINVAL) 13657c478bd9Sstevel@tonic-gate return (EINVAL); 13667c478bd9Sstevel@tonic-gate /* 13677c478bd9Sstevel@tonic-gate * copy out real errstate structure 13687c478bd9Sstevel@tonic-gate */ 13697c478bd9Sstevel@tonic-gate uls = errstate.log.logsize; 13707c478bd9Sstevel@tonic-gate uls = errstate.log.logsize; 13717c478bd9Sstevel@tonic-gate if (errstate.log.entries > uls && uls) 13727c478bd9Sstevel@tonic-gate /* insufficient user memory */ 13737c478bd9Sstevel@tonic-gate errstate.log.entries = uls; 13747c478bd9Sstevel@tonic-gate /* always pass back a time */ 13757c478bd9Sstevel@tonic-gate if (errstate.log.stop_time == 0ul) 13767c478bd9Sstevel@tonic-gate (void) drv_getparm(TIME, &(errstate.log.stop_time)); 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 13797c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 13807c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: 13817c478bd9Sstevel@tonic-gate { 13827c478bd9Sstevel@tonic-gate /* 13837c478bd9Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 13847c478bd9Sstevel@tonic-gate * 64 bit ioctl 13857c478bd9Sstevel@tonic-gate */ 13867c478bd9Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 13877c478bd9Sstevel@tonic-gate 13887c478bd9Sstevel@tonic-gate errstate_32.fail_time = errstate.fail_time; 13897c478bd9Sstevel@tonic-gate errstate_32.msg_time = errstate.msg_time; 13907c478bd9Sstevel@tonic-gate errstate_32.access_count = errstate.access_count; 13917c478bd9Sstevel@tonic-gate errstate_32.fail_count = errstate.fail_count; 13927c478bd9Sstevel@tonic-gate errstate_32.acc_chk = errstate.acc_chk; 13937c478bd9Sstevel@tonic-gate errstate_32.errmsg_count = errstate.errmsg_count; 13947c478bd9Sstevel@tonic-gate (void) strncpy(errstate_32.buffer, errstate.buffer, 13957c478bd9Sstevel@tonic-gate ERRMSGSIZE); 13967c478bd9Sstevel@tonic-gate errstate_32.severity = errstate.severity; 13977c478bd9Sstevel@tonic-gate errstate_32.log.logsize = errstate.log.logsize; 13987c478bd9Sstevel@tonic-gate errstate_32.log.entries = errstate.log.entries; 13997c478bd9Sstevel@tonic-gate errstate_32.log.flags = errstate.log.flags; 14007c478bd9Sstevel@tonic-gate errstate_32.log.wrapcnt = errstate.log.wrapcnt; 14017c478bd9Sstevel@tonic-gate errstate_32.log.start_time = errstate.log.start_time; 14027c478bd9Sstevel@tonic-gate errstate_32.log.stop_time = errstate.log.stop_time; 14037c478bd9Sstevel@tonic-gate errstate_32.log.logbase = 14047c478bd9Sstevel@tonic-gate (caddr32_t)(uintptr_t)errstate.log.logbase; 14057c478bd9Sstevel@tonic-gate errstate_32.errdef_handle = errstate.errdef_handle; 14067c478bd9Sstevel@tonic-gate if (ddi_copyout(&errstate_32, (void *)arg, 14077c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) 14087c478bd9Sstevel@tonic-gate return (EFAULT); 14097c478bd9Sstevel@tonic-gate break; 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 14127c478bd9Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 14137c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 14147c478bd9Sstevel@tonic-gate return (EFAULT); 14157c478bd9Sstevel@tonic-gate break; 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 14187c478bd9Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 14197c478bd9Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 14207c478bd9Sstevel@tonic-gate return (EFAULT); 14217c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate if (uls && errstate.log.entries && 14247c478bd9Sstevel@tonic-gate ddi_copyout(klg, errstate.log.logbase, 14257c478bd9Sstevel@tonic-gate errstate.log.entries * sizeof (struct acc_log_elem), 14267c478bd9Sstevel@tonic-gate mode) != 0) { 14277c478bd9Sstevel@tonic-gate return (EFAULT); 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate return (retval); 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate case BOFI_GET_HANDLES: 14327c478bd9Sstevel@tonic-gate /* 14337c478bd9Sstevel@tonic-gate * display existing handles 14347c478bd9Sstevel@tonic-gate */ 14357c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 14367c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 14377c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: 14387c478bd9Sstevel@tonic-gate { 14397c478bd9Sstevel@tonic-gate /* 14407c478bd9Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 14417c478bd9Sstevel@tonic-gate * 64 bit ioctl 14427c478bd9Sstevel@tonic-gate */ 14437c478bd9Sstevel@tonic-gate struct bofi_get_handles32 get_handles_32; 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &get_handles_32, 14467c478bd9Sstevel@tonic-gate sizeof (get_handles_32), mode) != 0) { 14477c478bd9Sstevel@tonic-gate return (EFAULT); 14487c478bd9Sstevel@tonic-gate } 14497c478bd9Sstevel@tonic-gate get_handles.namesize = get_handles_32.namesize; 14507c478bd9Sstevel@tonic-gate (void) strncpy(get_handles.name, get_handles_32.name, 14517c478bd9Sstevel@tonic-gate NAMESIZE); 14527c478bd9Sstevel@tonic-gate get_handles.instance = get_handles_32.instance; 14537c478bd9Sstevel@tonic-gate get_handles.count = get_handles_32.count; 14547c478bd9Sstevel@tonic-gate get_handles.buffer = 14557c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)get_handles_32.buffer; 14567c478bd9Sstevel@tonic-gate break; 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 14597c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &get_handles, 14607c478bd9Sstevel@tonic-gate sizeof (get_handles), mode) != 0) 14617c478bd9Sstevel@tonic-gate return (EFAULT); 14627c478bd9Sstevel@tonic-gate break; 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 14657c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &get_handles, 14667c478bd9Sstevel@tonic-gate sizeof (get_handles), mode) != 0) 14677c478bd9Sstevel@tonic-gate return (EFAULT); 14687c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 14697c478bd9Sstevel@tonic-gate /* 14707c478bd9Sstevel@tonic-gate * read in name 14717c478bd9Sstevel@tonic-gate */ 14727c478bd9Sstevel@tonic-gate if (get_handles.namesize > NAMESIZE) 14737c478bd9Sstevel@tonic-gate return (EINVAL); 14747c478bd9Sstevel@tonic-gate namep = kmem_zalloc(get_handles.namesize+1, KM_SLEEP); 14757c478bd9Sstevel@tonic-gate (void) strncpy(namep, get_handles.name, get_handles.namesize); 14767c478bd9Sstevel@tonic-gate req_count = get_handles.count; 14777c478bd9Sstevel@tonic-gate bufptr = buffer = kmem_zalloc(req_count, KM_SLEEP); 14787c478bd9Sstevel@tonic-gate endbuf = bufptr + req_count; 14797c478bd9Sstevel@tonic-gate /* 14807c478bd9Sstevel@tonic-gate * display existing handles 14817c478bd9Sstevel@tonic-gate */ 14827c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 14837c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 14847c478bd9Sstevel@tonic-gate for (i = 0; i < HDL_HASH_TBL_SIZE; i++) { 14857c478bd9Sstevel@tonic-gate hhashp = &hhash_table[i]; 14867c478bd9Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) { 14877c478bd9Sstevel@tonic-gate if (!driver_under_test(hp->dip)) 14887c478bd9Sstevel@tonic-gate continue; 14897c478bd9Sstevel@tonic-gate if (ddi_name_to_major(ddi_get_name(hp->dip)) != 14907c478bd9Sstevel@tonic-gate ddi_name_to_major(namep)) 14917c478bd9Sstevel@tonic-gate continue; 14927c478bd9Sstevel@tonic-gate if (hp->instance != get_handles.instance) 14937c478bd9Sstevel@tonic-gate continue; 14947c478bd9Sstevel@tonic-gate /* 14957c478bd9Sstevel@tonic-gate * print information per handle - note that 14967c478bd9Sstevel@tonic-gate * DMA* means an unbound DMA handle 14977c478bd9Sstevel@tonic-gate */ 14987c478bd9Sstevel@tonic-gate (void) snprintf(bufptr, (size_t)(endbuf-bufptr), 14997c478bd9Sstevel@tonic-gate " %s %d %s ", hp->name, hp->instance, 15007c478bd9Sstevel@tonic-gate (hp->type == BOFI_INT_HDL) ? "INTR" : 15017c478bd9Sstevel@tonic-gate (hp->type == BOFI_ACC_HDL) ? "PIO" : 15027c478bd9Sstevel@tonic-gate (hp->type == BOFI_DMA_HDL) ? "DMA" : 15037c478bd9Sstevel@tonic-gate (hp->hparrayp != NULL) ? "DVMA" : "DMA*"); 15047c478bd9Sstevel@tonic-gate bufptr += strlen(bufptr); 15057c478bd9Sstevel@tonic-gate if (hp->type == BOFI_ACC_HDL) { 15067c478bd9Sstevel@tonic-gate if (hp->len == INT_MAX - hp->offset) 15077c478bd9Sstevel@tonic-gate (void) snprintf(bufptr, 15087c478bd9Sstevel@tonic-gate (size_t)(endbuf-bufptr), 15097c478bd9Sstevel@tonic-gate "reg set %d off 0x%llx\n", 15107c478bd9Sstevel@tonic-gate hp->rnumber, hp->offset); 15117c478bd9Sstevel@tonic-gate else 15127c478bd9Sstevel@tonic-gate (void) snprintf(bufptr, 15137c478bd9Sstevel@tonic-gate (size_t)(endbuf-bufptr), 15147c478bd9Sstevel@tonic-gate "reg set %d off 0x%llx" 15157c478bd9Sstevel@tonic-gate " len 0x%llx\n", 15167c478bd9Sstevel@tonic-gate hp->rnumber, hp->offset, 15177c478bd9Sstevel@tonic-gate hp->len); 15187c478bd9Sstevel@tonic-gate } else if (hp->type == BOFI_DMA_HDL) 15197c478bd9Sstevel@tonic-gate (void) snprintf(bufptr, 15207c478bd9Sstevel@tonic-gate (size_t)(endbuf-bufptr), 15217c478bd9Sstevel@tonic-gate "handle no %d len 0x%llx" 15227c478bd9Sstevel@tonic-gate " addr 0x%p\n", hp->rnumber, 15237c478bd9Sstevel@tonic-gate hp->len, (void *)hp->addr); 15247c478bd9Sstevel@tonic-gate else if (hp->type == BOFI_NULL && 15257c478bd9Sstevel@tonic-gate hp->hparrayp == NULL) 15267c478bd9Sstevel@tonic-gate (void) snprintf(bufptr, 15277c478bd9Sstevel@tonic-gate (size_t)(endbuf-bufptr), 15287c478bd9Sstevel@tonic-gate "handle no %d\n", hp->rnumber); 15297c478bd9Sstevel@tonic-gate else 15307c478bd9Sstevel@tonic-gate (void) snprintf(bufptr, 15317c478bd9Sstevel@tonic-gate (size_t)(endbuf-bufptr), "\n"); 15327c478bd9Sstevel@tonic-gate bufptr += strlen(bufptr); 15337c478bd9Sstevel@tonic-gate } 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 15367c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 15377c478bd9Sstevel@tonic-gate err = ddi_copyout(buffer, get_handles.buffer, req_count, mode); 15387c478bd9Sstevel@tonic-gate kmem_free(namep, get_handles.namesize+1); 15397c478bd9Sstevel@tonic-gate kmem_free(buffer, req_count); 15407c478bd9Sstevel@tonic-gate if (err != 0) 15417c478bd9Sstevel@tonic-gate return (EFAULT); 15427c478bd9Sstevel@tonic-gate else 15437c478bd9Sstevel@tonic-gate return (0); 15447c478bd9Sstevel@tonic-gate case BOFI_GET_HANDLE_INFO: 15457c478bd9Sstevel@tonic-gate /* 15467c478bd9Sstevel@tonic-gate * display existing handles 15477c478bd9Sstevel@tonic-gate */ 15487c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 15497c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 15507c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: 15517c478bd9Sstevel@tonic-gate { 15527c478bd9Sstevel@tonic-gate /* 15537c478bd9Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 15547c478bd9Sstevel@tonic-gate * 64 bit ioctl 15557c478bd9Sstevel@tonic-gate */ 15567c478bd9Sstevel@tonic-gate struct bofi_get_hdl_info32 hdl_info_32; 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &hdl_info_32, 15597c478bd9Sstevel@tonic-gate sizeof (hdl_info_32), mode)) { 15607c478bd9Sstevel@tonic-gate return (EFAULT); 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate hdl_info.namesize = hdl_info_32.namesize; 15637c478bd9Sstevel@tonic-gate (void) strncpy(hdl_info.name, hdl_info_32.name, 15647c478bd9Sstevel@tonic-gate NAMESIZE); 15657c478bd9Sstevel@tonic-gate hdl_info.count = hdl_info_32.count; 15667c478bd9Sstevel@tonic-gate hdl_info.hdli = (caddr_t)(uintptr_t)hdl_info_32.hdli; 15677c478bd9Sstevel@tonic-gate break; 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 15707c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &hdl_info, 15717c478bd9Sstevel@tonic-gate sizeof (hdl_info), mode)) 15727c478bd9Sstevel@tonic-gate return (EFAULT); 15737c478bd9Sstevel@tonic-gate break; 15747c478bd9Sstevel@tonic-gate } 15757c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 15767c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)arg, &hdl_info, 15777c478bd9Sstevel@tonic-gate sizeof (hdl_info), mode)) 15787c478bd9Sstevel@tonic-gate return (EFAULT); 15797c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 15807c478bd9Sstevel@tonic-gate if (hdl_info.namesize > NAMESIZE) 15817c478bd9Sstevel@tonic-gate return (EINVAL); 15827c478bd9Sstevel@tonic-gate namep = kmem_zalloc(hdl_info.namesize + 1, KM_SLEEP); 15837c478bd9Sstevel@tonic-gate (void) strncpy(namep, hdl_info.name, hdl_info.namesize); 15847c478bd9Sstevel@tonic-gate req_count = hdl_info.count; 15857c478bd9Sstevel@tonic-gate count = hdl_info.count = 0; /* the actual no of handles */ 15867c478bd9Sstevel@tonic-gate if (req_count > 0) { 15877c478bd9Sstevel@tonic-gate hib = hdlip = 15887c478bd9Sstevel@tonic-gate kmem_zalloc(req_count * sizeof (struct handle_info), 15897c478bd9Sstevel@tonic-gate KM_SLEEP); 15907c478bd9Sstevel@tonic-gate } else { 15917c478bd9Sstevel@tonic-gate hib = hdlip = 0; 15927c478bd9Sstevel@tonic-gate req_count = hdl_info.count = 0; 15937c478bd9Sstevel@tonic-gate } 15947c478bd9Sstevel@tonic-gate 15957c478bd9Sstevel@tonic-gate /* 15967c478bd9Sstevel@tonic-gate * display existing handles 15977c478bd9Sstevel@tonic-gate */ 15987c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 15997c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 16007c478bd9Sstevel@tonic-gate for (i = 0; i < HDL_HASH_TBL_SIZE; i++) { 16017c478bd9Sstevel@tonic-gate hhashp = &hhash_table[i]; 16027c478bd9Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) { 16037c478bd9Sstevel@tonic-gate if (!driver_under_test(hp->dip) || 16047c478bd9Sstevel@tonic-gate ddi_name_to_major(ddi_get_name(hp->dip)) != 16057c478bd9Sstevel@tonic-gate ddi_name_to_major(namep) || 16067c478bd9Sstevel@tonic-gate ++(hdl_info.count) > req_count || 16077c478bd9Sstevel@tonic-gate count == req_count) 16087c478bd9Sstevel@tonic-gate continue; 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate hdlip->instance = hp->instance; 16117c478bd9Sstevel@tonic-gate hdlip->rnumber = hp->rnumber; 16127c478bd9Sstevel@tonic-gate switch (hp->type) { 16137c478bd9Sstevel@tonic-gate case BOFI_ACC_HDL: 16147c478bd9Sstevel@tonic-gate hdlip->access_type = BOFI_PIO_RW; 16157c478bd9Sstevel@tonic-gate hdlip->offset = hp->offset; 16167c478bd9Sstevel@tonic-gate hdlip->len = hp->len; 16177c478bd9Sstevel@tonic-gate break; 16187c478bd9Sstevel@tonic-gate case BOFI_DMA_HDL: 16197c478bd9Sstevel@tonic-gate hdlip->access_type = 0; 16207c478bd9Sstevel@tonic-gate if (hp->flags & DDI_DMA_WRITE) 16217c478bd9Sstevel@tonic-gate hdlip->access_type |= 16227c478bd9Sstevel@tonic-gate BOFI_DMA_W; 16237c478bd9Sstevel@tonic-gate if (hp->flags & DDI_DMA_READ) 16247c478bd9Sstevel@tonic-gate hdlip->access_type |= 16257c478bd9Sstevel@tonic-gate BOFI_DMA_R; 16267c478bd9Sstevel@tonic-gate hdlip->len = hp->len; 16277c478bd9Sstevel@tonic-gate hdlip->addr_cookie = 16287c478bd9Sstevel@tonic-gate (uint64_t)(uintptr_t)hp->addr; 16297c478bd9Sstevel@tonic-gate break; 16307c478bd9Sstevel@tonic-gate case BOFI_INT_HDL: 16317c478bd9Sstevel@tonic-gate hdlip->access_type = BOFI_INTR; 16327c478bd9Sstevel@tonic-gate break; 16337c478bd9Sstevel@tonic-gate default: 16347c478bd9Sstevel@tonic-gate hdlip->access_type = 0; 16357c478bd9Sstevel@tonic-gate break; 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate hdlip++; 16387c478bd9Sstevel@tonic-gate count++; 16397c478bd9Sstevel@tonic-gate } 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 16427c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 16437c478bd9Sstevel@tonic-gate err = 0; 16447c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 16457c478bd9Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 16467c478bd9Sstevel@tonic-gate case DDI_MODEL_ILP32: 16477c478bd9Sstevel@tonic-gate { 16487c478bd9Sstevel@tonic-gate /* 16497c478bd9Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 16507c478bd9Sstevel@tonic-gate * 64 bit ioctl 16517c478bd9Sstevel@tonic-gate */ 16527c478bd9Sstevel@tonic-gate struct bofi_get_hdl_info32 hdl_info_32; 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate hdl_info_32.namesize = hdl_info.namesize; 16557c478bd9Sstevel@tonic-gate (void) strncpy(hdl_info_32.name, hdl_info.name, 16567c478bd9Sstevel@tonic-gate NAMESIZE); 16577c478bd9Sstevel@tonic-gate hdl_info_32.count = hdl_info.count; 16587c478bd9Sstevel@tonic-gate hdl_info_32.hdli = (caddr32_t)(uintptr_t)hdl_info.hdli; 16597c478bd9Sstevel@tonic-gate if (ddi_copyout(&hdl_info_32, (void *)arg, 16607c478bd9Sstevel@tonic-gate sizeof (hdl_info_32), mode) != 0) { 16617c478bd9Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 16627c478bd9Sstevel@tonic-gate if (req_count > 0) 16637c478bd9Sstevel@tonic-gate kmem_free(hib, 16647c478bd9Sstevel@tonic-gate req_count * sizeof (*hib)); 16657c478bd9Sstevel@tonic-gate return (EFAULT); 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate break; 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate case DDI_MODEL_NONE: 16707c478bd9Sstevel@tonic-gate if (ddi_copyout(&hdl_info, (void *)arg, 16717c478bd9Sstevel@tonic-gate sizeof (hdl_info), mode) != 0) { 16727c478bd9Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 16737c478bd9Sstevel@tonic-gate if (req_count > 0) 16747c478bd9Sstevel@tonic-gate kmem_free(hib, 16757c478bd9Sstevel@tonic-gate req_count * sizeof (*hib)); 16767c478bd9Sstevel@tonic-gate return (EFAULT); 16777c478bd9Sstevel@tonic-gate } 16787c478bd9Sstevel@tonic-gate break; 16797c478bd9Sstevel@tonic-gate } 16807c478bd9Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 16817c478bd9Sstevel@tonic-gate if (ddi_copyout(&hdl_info, (void *)arg, 16827c478bd9Sstevel@tonic-gate sizeof (hdl_info), mode) != 0) { 16837c478bd9Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 16847c478bd9Sstevel@tonic-gate if (req_count > 0) 16857c478bd9Sstevel@tonic-gate kmem_free(hib, req_count * sizeof (*hib)); 16867c478bd9Sstevel@tonic-gate return (EFAULT); 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate #endif /* ! _MULTI_DATAMODEL */ 16897c478bd9Sstevel@tonic-gate if (count > 0) { 16907c478bd9Sstevel@tonic-gate if (ddi_copyout(hib, hdl_info.hdli, 16917c478bd9Sstevel@tonic-gate count * sizeof (*hib), mode) != 0) { 16927c478bd9Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 16937c478bd9Sstevel@tonic-gate if (req_count > 0) 16947c478bd9Sstevel@tonic-gate kmem_free(hib, 16957c478bd9Sstevel@tonic-gate req_count * sizeof (*hib)); 16967c478bd9Sstevel@tonic-gate return (EFAULT); 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate } 16997c478bd9Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 17007c478bd9Sstevel@tonic-gate if (req_count > 0) 17017c478bd9Sstevel@tonic-gate kmem_free(hib, req_count * sizeof (*hib)); 17027c478bd9Sstevel@tonic-gate return (err); 17037c478bd9Sstevel@tonic-gate default: 17047c478bd9Sstevel@tonic-gate return (ENOTTY); 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate /* 17107c478bd9Sstevel@tonic-gate * add a new error definition 17117c478bd9Sstevel@tonic-gate */ 17127c478bd9Sstevel@tonic-gate static int 17137c478bd9Sstevel@tonic-gate bofi_errdef_alloc(struct bofi_errdef *errdefp, char *namep, 17147c478bd9Sstevel@tonic-gate struct bofi_errent *softc) 17157c478bd9Sstevel@tonic-gate { 17167c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 17177c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 17187c478bd9Sstevel@tonic-gate struct bofi_link *lp; 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate /* 17217c478bd9Sstevel@tonic-gate * allocate errdef structure and put on in-use list 17227c478bd9Sstevel@tonic-gate */ 17237c478bd9Sstevel@tonic-gate ep = kmem_zalloc(sizeof (struct bofi_errent), KM_SLEEP); 17247c478bd9Sstevel@tonic-gate ep->errdef = *errdefp; 17257c478bd9Sstevel@tonic-gate ep->name = namep; 17267c478bd9Sstevel@tonic-gate ep->errdef.errdef_handle = (uint64_t)(uintptr_t)ep; 17277c478bd9Sstevel@tonic-gate ep->errstate.errdef_handle = (uint64_t)(uintptr_t)ep; 17287c478bd9Sstevel@tonic-gate cv_init(&ep->cv, NULL, CV_DRIVER, NULL); 17297c478bd9Sstevel@tonic-gate /* 17307c478bd9Sstevel@tonic-gate * allocate space for logging 17317c478bd9Sstevel@tonic-gate */ 17327c478bd9Sstevel@tonic-gate ep->errdef.log.entries = 0; 17337c478bd9Sstevel@tonic-gate ep->errdef.log.wrapcnt = 0; 17347c478bd9Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) 17357c478bd9Sstevel@tonic-gate ep->logbase = kmem_alloc(sizeof (struct acc_log_elem) * 17367c478bd9Sstevel@tonic-gate ep->errdef.log.logsize, KM_SLEEP); 17377c478bd9Sstevel@tonic-gate else 17387c478bd9Sstevel@tonic-gate ep->logbase = NULL; 17397c478bd9Sstevel@tonic-gate /* 17407c478bd9Sstevel@tonic-gate * put on in-use list 17417c478bd9Sstevel@tonic-gate */ 17427c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 17437c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 17447c478bd9Sstevel@tonic-gate ep->next = errent_listp; 17457c478bd9Sstevel@tonic-gate errent_listp = ep; 17467c478bd9Sstevel@tonic-gate /* 17477c478bd9Sstevel@tonic-gate * and add it to the per-clone list 17487c478bd9Sstevel@tonic-gate */ 17497c478bd9Sstevel@tonic-gate ep->cnext = softc->cnext; 17507c478bd9Sstevel@tonic-gate softc->cnext->cprev = ep; 17517c478bd9Sstevel@tonic-gate ep->cprev = softc; 17527c478bd9Sstevel@tonic-gate softc->cnext = ep; 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate /* 17557c478bd9Sstevel@tonic-gate * look for corresponding shadow handle structures and if we find any 17567c478bd9Sstevel@tonic-gate * tag this errdef structure on to their link lists. 17577c478bd9Sstevel@tonic-gate */ 17587c478bd9Sstevel@tonic-gate for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) { 17597c478bd9Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == ddi_name_to_major(namep) && 17607c478bd9Sstevel@tonic-gate hp->instance == errdefp->instance && 17617c478bd9Sstevel@tonic-gate (((errdefp->access_type & BOFI_DMA_RW) && 17627c478bd9Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 17637c478bd9Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 17647c478bd9Sstevel@tonic-gate hp->type == BOFI_DMA_HDL && 17657c478bd9Sstevel@tonic-gate (((uintptr_t)(hp->addr + ep->errdef.offset + 17667c478bd9Sstevel@tonic-gate ep->errdef.len) & ~LLSZMASK) > 17677c478bd9Sstevel@tonic-gate ((uintptr_t)((hp->addr + ep->errdef.offset) + 17687c478bd9Sstevel@tonic-gate LLSZMASK) & ~LLSZMASK))) || 17697c478bd9Sstevel@tonic-gate ((errdefp->access_type & BOFI_INTR) && 17707c478bd9Sstevel@tonic-gate hp->type == BOFI_INT_HDL) || 17717c478bd9Sstevel@tonic-gate ((errdefp->access_type & BOFI_PIO_RW) && 17727c478bd9Sstevel@tonic-gate hp->type == BOFI_ACC_HDL && 17737c478bd9Sstevel@tonic-gate (errdefp->rnumber == -1 || 17747c478bd9Sstevel@tonic-gate hp->rnumber == errdefp->rnumber) && 17757c478bd9Sstevel@tonic-gate (errdefp->len == 0 || 17767c478bd9Sstevel@tonic-gate hp->offset < errdefp->offset + errdefp->len) && 17777c478bd9Sstevel@tonic-gate hp->offset + hp->len > errdefp->offset))) { 17787c478bd9Sstevel@tonic-gate lp = bofi_link_freelist; 17797c478bd9Sstevel@tonic-gate if (lp != NULL) { 17807c478bd9Sstevel@tonic-gate bofi_link_freelist = lp->link; 17817c478bd9Sstevel@tonic-gate lp->errentp = ep; 17827c478bd9Sstevel@tonic-gate lp->link = hp->link; 17837c478bd9Sstevel@tonic-gate hp->link = lp; 17847c478bd9Sstevel@tonic-gate } 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate } 17877c478bd9Sstevel@tonic-gate errdefp->errdef_handle = (uint64_t)(uintptr_t)ep; 17887c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 17897c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 17907c478bd9Sstevel@tonic-gate ep->softintr_id = NULL; 17917c478bd9Sstevel@tonic-gate return (ddi_add_softintr(our_dip, DDI_SOFTINT_MED, &ep->softintr_id, 17927c478bd9Sstevel@tonic-gate NULL, NULL, bofi_signal, (caddr_t)&ep->errdef)); 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate /* 17977c478bd9Sstevel@tonic-gate * delete existing errdef 17987c478bd9Sstevel@tonic-gate */ 17997c478bd9Sstevel@tonic-gate static int 18007c478bd9Sstevel@tonic-gate bofi_errdef_free(struct bofi_errent *ep) 18017c478bd9Sstevel@tonic-gate { 18027c478bd9Sstevel@tonic-gate struct bofi_errent *hep, *prev_hep; 18037c478bd9Sstevel@tonic-gate struct bofi_link *lp, *prev_lp, *next_lp; 18047c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 18077c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 18087c478bd9Sstevel@tonic-gate /* 18097c478bd9Sstevel@tonic-gate * don't just assume its a valid ep - check that its on the 18107c478bd9Sstevel@tonic-gate * in-use list 18117c478bd9Sstevel@tonic-gate */ 18127c478bd9Sstevel@tonic-gate prev_hep = NULL; 18137c478bd9Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; ) { 18147c478bd9Sstevel@tonic-gate if (hep == ep) 18157c478bd9Sstevel@tonic-gate break; 18167c478bd9Sstevel@tonic-gate prev_hep = hep; 18177c478bd9Sstevel@tonic-gate hep = hep->next; 18187c478bd9Sstevel@tonic-gate } 18197c478bd9Sstevel@tonic-gate if (hep == NULL) { 18207c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 18217c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 18227c478bd9Sstevel@tonic-gate return (EINVAL); 18237c478bd9Sstevel@tonic-gate } 18247c478bd9Sstevel@tonic-gate /* 18257c478bd9Sstevel@tonic-gate * found it - delete from in-use list 18267c478bd9Sstevel@tonic-gate */ 18277c478bd9Sstevel@tonic-gate 18287c478bd9Sstevel@tonic-gate if (prev_hep) 18297c478bd9Sstevel@tonic-gate prev_hep->next = hep->next; 18307c478bd9Sstevel@tonic-gate else 18317c478bd9Sstevel@tonic-gate errent_listp = hep->next; 18327c478bd9Sstevel@tonic-gate /* 18337c478bd9Sstevel@tonic-gate * and take it off the per-clone list 18347c478bd9Sstevel@tonic-gate */ 18357c478bd9Sstevel@tonic-gate hep->cnext->cprev = hep->cprev; 18367c478bd9Sstevel@tonic-gate hep->cprev->cnext = hep->cnext; 18377c478bd9Sstevel@tonic-gate /* 18387c478bd9Sstevel@tonic-gate * see if we are on any shadow handle link lists - and if we 18397c478bd9Sstevel@tonic-gate * are then take us off 18407c478bd9Sstevel@tonic-gate */ 18417c478bd9Sstevel@tonic-gate for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) { 18427c478bd9Sstevel@tonic-gate prev_lp = NULL; 18437c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 18447c478bd9Sstevel@tonic-gate if (lp->errentp == ep) { 18457c478bd9Sstevel@tonic-gate if (prev_lp) 18467c478bd9Sstevel@tonic-gate prev_lp->link = lp->link; 18477c478bd9Sstevel@tonic-gate else 18487c478bd9Sstevel@tonic-gate hp->link = lp->link; 18497c478bd9Sstevel@tonic-gate next_lp = lp->link; 18507c478bd9Sstevel@tonic-gate lp->link = bofi_link_freelist; 18517c478bd9Sstevel@tonic-gate bofi_link_freelist = lp; 18527c478bd9Sstevel@tonic-gate lp = next_lp; 18537c478bd9Sstevel@tonic-gate } else { 18547c478bd9Sstevel@tonic-gate prev_lp = lp; 18557c478bd9Sstevel@tonic-gate lp = lp->link; 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate } 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 18607c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate cv_destroy(&ep->cv); 18637c478bd9Sstevel@tonic-gate kmem_free(ep->name, ep->errdef.namesize+1); 18647c478bd9Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_LOG) && 18657c478bd9Sstevel@tonic-gate ep->errdef.log.logsize && ep->logbase) /* double check */ 18667c478bd9Sstevel@tonic-gate kmem_free(ep->logbase, 18677c478bd9Sstevel@tonic-gate sizeof (struct acc_log_elem) * ep->errdef.log.logsize); 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate if (ep->softintr_id) 18707c478bd9Sstevel@tonic-gate ddi_remove_softintr(ep->softintr_id); 18717c478bd9Sstevel@tonic-gate kmem_free(ep, sizeof (struct bofi_errent)); 18727c478bd9Sstevel@tonic-gate return (0); 18737c478bd9Sstevel@tonic-gate } 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate 18767c478bd9Sstevel@tonic-gate /* 18777c478bd9Sstevel@tonic-gate * start all errdefs corresponding to this name and instance 18787c478bd9Sstevel@tonic-gate */ 18797c478bd9Sstevel@tonic-gate static void 18807c478bd9Sstevel@tonic-gate bofi_start(struct bofi_errctl *errctlp, char *namep) 18817c478bd9Sstevel@tonic-gate { 18827c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate /* 18857c478bd9Sstevel@tonic-gate * look for any errdefs with matching name and instance 18867c478bd9Sstevel@tonic-gate */ 18877c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 18887c478bd9Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 18897c478bd9Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 18907c478bd9Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 18917c478bd9Sstevel@tonic-gate ep->state |= BOFI_DEV_ACTIVE; 18927c478bd9Sstevel@tonic-gate (void) drv_getparm(TIME, &(ep->errdef.log.start_time)); 18937c478bd9Sstevel@tonic-gate ep->errdef.log.stop_time = 0ul; 18947c478bd9Sstevel@tonic-gate } 18957c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate /* 19007c478bd9Sstevel@tonic-gate * stop all errdefs corresponding to this name and instance 19017c478bd9Sstevel@tonic-gate */ 19027c478bd9Sstevel@tonic-gate static void 19037c478bd9Sstevel@tonic-gate bofi_stop(struct bofi_errctl *errctlp, char *namep) 19047c478bd9Sstevel@tonic-gate { 19057c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 19067c478bd9Sstevel@tonic-gate 19077c478bd9Sstevel@tonic-gate /* 19087c478bd9Sstevel@tonic-gate * look for any errdefs with matching name and instance 19097c478bd9Sstevel@tonic-gate */ 19107c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 19117c478bd9Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 19127c478bd9Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 19137c478bd9Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 19147c478bd9Sstevel@tonic-gate ep->state &= ~BOFI_DEV_ACTIVE; 19157c478bd9Sstevel@tonic-gate if (ep->errdef.log.stop_time == 0ul) 19167c478bd9Sstevel@tonic-gate (void) drv_getparm(TIME, 19177c478bd9Sstevel@tonic-gate &(ep->errdef.log.stop_time)); 19187c478bd9Sstevel@tonic-gate } 19197c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate /* 19247c478bd9Sstevel@tonic-gate * wake up any thread waiting on this errdefs 19257c478bd9Sstevel@tonic-gate */ 19267c478bd9Sstevel@tonic-gate static uint_t 19277c478bd9Sstevel@tonic-gate bofi_signal(caddr_t arg) 19287c478bd9Sstevel@tonic-gate { 19297c478bd9Sstevel@tonic-gate struct bofi_errdef *edp = (struct bofi_errdef *)arg; 19307c478bd9Sstevel@tonic-gate struct bofi_errent *hep; 19317c478bd9Sstevel@tonic-gate struct bofi_errent *ep = 19327c478bd9Sstevel@tonic-gate (struct bofi_errent *)(uintptr_t)edp->errdef_handle; 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 19357c478bd9Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; ) { 19367c478bd9Sstevel@tonic-gate if (hep == ep) 19377c478bd9Sstevel@tonic-gate break; 19387c478bd9Sstevel@tonic-gate hep = hep->next; 19397c478bd9Sstevel@tonic-gate } 19407c478bd9Sstevel@tonic-gate if (hep == NULL) { 19417c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 19427c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 19437c478bd9Sstevel@tonic-gate } 19447c478bd9Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_LOG) && 19457c478bd9Sstevel@tonic-gate (edp->log.flags & BOFI_LOG_FULL)) { 19467c478bd9Sstevel@tonic-gate edp->log.stop_time = bofi_gettime(); 19477c478bd9Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 19487c478bd9Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 19497c478bd9Sstevel@tonic-gate cv_broadcast(&ep->cv); 19507c478bd9Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 19517c478bd9Sstevel@tonic-gate } 19527c478bd9Sstevel@tonic-gate if (ep->errstate.msg_time != 0) { 19537c478bd9Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 19547c478bd9Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 19557c478bd9Sstevel@tonic-gate cv_broadcast(&ep->cv); 19567c478bd9Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 19577c478bd9Sstevel@tonic-gate } 19587c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 19597c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 19607c478bd9Sstevel@tonic-gate } 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate 19637c478bd9Sstevel@tonic-gate /* 19647c478bd9Sstevel@tonic-gate * wake up all errdefs corresponding to this name and instance 19657c478bd9Sstevel@tonic-gate */ 19667c478bd9Sstevel@tonic-gate static void 19677c478bd9Sstevel@tonic-gate bofi_broadcast(struct bofi_errctl *errctlp, char *namep) 19687c478bd9Sstevel@tonic-gate { 19697c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate /* 19727c478bd9Sstevel@tonic-gate * look for any errdefs with matching name and instance 19737c478bd9Sstevel@tonic-gate */ 19747c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 19757c478bd9Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 19767c478bd9Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 19777c478bd9Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 19787c478bd9Sstevel@tonic-gate /* 19797c478bd9Sstevel@tonic-gate * wake up sleepers 19807c478bd9Sstevel@tonic-gate */ 19817c478bd9Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 19827c478bd9Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 19837c478bd9Sstevel@tonic-gate cv_broadcast(&ep->cv); 19847c478bd9Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 19857c478bd9Sstevel@tonic-gate } 19867c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 19877c478bd9Sstevel@tonic-gate } 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate /* 19917c478bd9Sstevel@tonic-gate * clear "acc_chk" for all errdefs corresponding to this name and instance 19927c478bd9Sstevel@tonic-gate * and wake them up. 19937c478bd9Sstevel@tonic-gate */ 19947c478bd9Sstevel@tonic-gate static void 19957c478bd9Sstevel@tonic-gate bofi_clear_acc_chk(struct bofi_errctl *errctlp, char *namep) 19967c478bd9Sstevel@tonic-gate { 19977c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 19987c478bd9Sstevel@tonic-gate 19997c478bd9Sstevel@tonic-gate /* 20007c478bd9Sstevel@tonic-gate * look for any errdefs with matching name and instance 20017c478bd9Sstevel@tonic-gate */ 20027c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 20037c478bd9Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 20047c478bd9Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 20057c478bd9Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 20067c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 20077c478bd9Sstevel@tonic-gate if (ep->errdef.access_count == 0 && 20087c478bd9Sstevel@tonic-gate ep->errdef.fail_count == 0) 20097c478bd9Sstevel@tonic-gate ep->errdef.acc_chk = 0; 20107c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 20117c478bd9Sstevel@tonic-gate /* 20127c478bd9Sstevel@tonic-gate * wake up sleepers 20137c478bd9Sstevel@tonic-gate */ 20147c478bd9Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 20157c478bd9Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 20167c478bd9Sstevel@tonic-gate cv_broadcast(&ep->cv); 20177c478bd9Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 20187c478bd9Sstevel@tonic-gate } 20197c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 20207c478bd9Sstevel@tonic-gate } 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate /* 20247c478bd9Sstevel@tonic-gate * set "fail_count" to 0 for all errdefs corresponding to this name and instance 20257c478bd9Sstevel@tonic-gate * whose "access_count" has expired, set "acc_chk" to 0 and wake them up. 20267c478bd9Sstevel@tonic-gate */ 20277c478bd9Sstevel@tonic-gate static void 20287c478bd9Sstevel@tonic-gate bofi_clear_errors(struct bofi_errctl *errctlp, char *namep) 20297c478bd9Sstevel@tonic-gate { 20307c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 20317c478bd9Sstevel@tonic-gate 20327c478bd9Sstevel@tonic-gate /* 20337c478bd9Sstevel@tonic-gate * look for any errdefs with matching name and instance 20347c478bd9Sstevel@tonic-gate */ 20357c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 20367c478bd9Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 20377c478bd9Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 20387c478bd9Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 20397c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 20407c478bd9Sstevel@tonic-gate if (ep->errdef.access_count == 0) { 20417c478bd9Sstevel@tonic-gate ep->errdef.acc_chk = 0; 20427c478bd9Sstevel@tonic-gate ep->errdef.fail_count = 0; 20437c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 20447c478bd9Sstevel@tonic-gate if (ep->errdef.log.stop_time == 0ul) 20457c478bd9Sstevel@tonic-gate (void) drv_getparm(TIME, 20467c478bd9Sstevel@tonic-gate &(ep->errdef.log.stop_time)); 20477c478bd9Sstevel@tonic-gate } else 20487c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 20497c478bd9Sstevel@tonic-gate /* 20507c478bd9Sstevel@tonic-gate * wake up sleepers 20517c478bd9Sstevel@tonic-gate */ 20527c478bd9Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 20537c478bd9Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 20547c478bd9Sstevel@tonic-gate cv_broadcast(&ep->cv); 20557c478bd9Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 20567c478bd9Sstevel@tonic-gate } 20577c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate /* 20627c478bd9Sstevel@tonic-gate * set "access_count" and "fail_count" to 0 for all errdefs corresponding to 20637c478bd9Sstevel@tonic-gate * this name and instance, set "acc_chk" to 0, and wake them up. 20647c478bd9Sstevel@tonic-gate */ 20657c478bd9Sstevel@tonic-gate static void 20667c478bd9Sstevel@tonic-gate bofi_clear_errdefs(struct bofi_errctl *errctlp, char *namep) 20677c478bd9Sstevel@tonic-gate { 20687c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 20697c478bd9Sstevel@tonic-gate 20707c478bd9Sstevel@tonic-gate /* 20717c478bd9Sstevel@tonic-gate * look for any errdefs with matching name and instance 20727c478bd9Sstevel@tonic-gate */ 20737c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 20747c478bd9Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 20757c478bd9Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 20767c478bd9Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 20777c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 20787c478bd9Sstevel@tonic-gate ep->errdef.acc_chk = 0; 20797c478bd9Sstevel@tonic-gate ep->errdef.access_count = 0; 20807c478bd9Sstevel@tonic-gate ep->errdef.fail_count = 0; 20817c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 20827c478bd9Sstevel@tonic-gate if (ep->errdef.log.stop_time == 0ul) 20837c478bd9Sstevel@tonic-gate (void) drv_getparm(TIME, 20847c478bd9Sstevel@tonic-gate &(ep->errdef.log.stop_time)); 20857c478bd9Sstevel@tonic-gate /* 20867c478bd9Sstevel@tonic-gate * wake up sleepers 20877c478bd9Sstevel@tonic-gate */ 20887c478bd9Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 20897c478bd9Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 20907c478bd9Sstevel@tonic-gate cv_broadcast(&ep->cv); 20917c478bd9Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 20947c478bd9Sstevel@tonic-gate } 20957c478bd9Sstevel@tonic-gate 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate /* 20987c478bd9Sstevel@tonic-gate * get state for this errdef 20997c478bd9Sstevel@tonic-gate */ 21007c478bd9Sstevel@tonic-gate static int 21017c478bd9Sstevel@tonic-gate bofi_errdef_check(struct bofi_errstate *errstatep, struct acc_log_elem **logpp) 21027c478bd9Sstevel@tonic-gate { 21037c478bd9Sstevel@tonic-gate struct bofi_errent *hep; 21047c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 21057c478bd9Sstevel@tonic-gate 21067c478bd9Sstevel@tonic-gate ep = (struct bofi_errent *)(uintptr_t)errstatep->errdef_handle; 21077c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 21087c478bd9Sstevel@tonic-gate /* 21097c478bd9Sstevel@tonic-gate * don't just assume its a valid ep - check that its on the 21107c478bd9Sstevel@tonic-gate * in-use list 21117c478bd9Sstevel@tonic-gate */ 21127c478bd9Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; hep = hep->next) 21137c478bd9Sstevel@tonic-gate if (hep == ep) 21147c478bd9Sstevel@tonic-gate break; 21157c478bd9Sstevel@tonic-gate if (hep == NULL) { 21167c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 21177c478bd9Sstevel@tonic-gate return (EINVAL); 21187c478bd9Sstevel@tonic-gate } 21197c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 21207c478bd9Sstevel@tonic-gate ep->errstate.access_count = ep->errdef.access_count; 21217c478bd9Sstevel@tonic-gate ep->errstate.fail_count = ep->errdef.fail_count; 21227c478bd9Sstevel@tonic-gate ep->errstate.acc_chk = ep->errdef.acc_chk; 21237c478bd9Sstevel@tonic-gate ep->errstate.log = ep->errdef.log; 21247c478bd9Sstevel@tonic-gate *logpp = ep->logbase; 21257c478bd9Sstevel@tonic-gate *errstatep = ep->errstate; 21267c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 21277c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 21287c478bd9Sstevel@tonic-gate return (0); 21297c478bd9Sstevel@tonic-gate } 21307c478bd9Sstevel@tonic-gate 21317c478bd9Sstevel@tonic-gate 21327c478bd9Sstevel@tonic-gate /* 21337c478bd9Sstevel@tonic-gate * Wait for a ddi_report_fault message to come back for this errdef 21347c478bd9Sstevel@tonic-gate * Then return state for this errdef. 21357c478bd9Sstevel@tonic-gate * fault report is intercepted by bofi_post_event, which triggers 21367c478bd9Sstevel@tonic-gate * bofi_signal via a softint, which will wake up this routine if 21377c478bd9Sstevel@tonic-gate * we are waiting 21387c478bd9Sstevel@tonic-gate */ 21397c478bd9Sstevel@tonic-gate static int 21407c478bd9Sstevel@tonic-gate bofi_errdef_check_w(struct bofi_errstate *errstatep, 21417c478bd9Sstevel@tonic-gate struct acc_log_elem **logpp) 21427c478bd9Sstevel@tonic-gate { 21437c478bd9Sstevel@tonic-gate struct bofi_errent *hep; 21447c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 21457c478bd9Sstevel@tonic-gate int rval = 0; 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate ep = (struct bofi_errent *)(uintptr_t)errstatep->errdef_handle; 21487c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 21497c478bd9Sstevel@tonic-gate retry: 21507c478bd9Sstevel@tonic-gate /* 21517c478bd9Sstevel@tonic-gate * don't just assume its a valid ep - check that its on the 21527c478bd9Sstevel@tonic-gate * in-use list 21537c478bd9Sstevel@tonic-gate */ 21547c478bd9Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; hep = hep->next) 21557c478bd9Sstevel@tonic-gate if (hep == ep) 21567c478bd9Sstevel@tonic-gate break; 21577c478bd9Sstevel@tonic-gate if (hep == NULL) { 21587c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 21597c478bd9Sstevel@tonic-gate return (EINVAL); 21607c478bd9Sstevel@tonic-gate } 21617c478bd9Sstevel@tonic-gate /* 21627c478bd9Sstevel@tonic-gate * wait for ddi_report_fault for the devinfo corresponding 21637c478bd9Sstevel@tonic-gate * to this errdef 21647c478bd9Sstevel@tonic-gate */ 21657c478bd9Sstevel@tonic-gate if (rval == 0 && !(ep->state & BOFI_NEW_MESSAGE)) { 21667c478bd9Sstevel@tonic-gate ep->state |= BOFI_MESSAGE_WAIT; 21677c478bd9Sstevel@tonic-gate if (cv_wait_sig(&ep->cv, &bofi_low_mutex) == 0) 21687c478bd9Sstevel@tonic-gate rval = EINTR; 21697c478bd9Sstevel@tonic-gate goto retry; 21707c478bd9Sstevel@tonic-gate } 21717c478bd9Sstevel@tonic-gate ep->state &= ~BOFI_NEW_MESSAGE; 21727c478bd9Sstevel@tonic-gate /* 21737c478bd9Sstevel@tonic-gate * we either didn't need to sleep, we've been woken up or we've been 21747c478bd9Sstevel@tonic-gate * signaled - either way return state now 21757c478bd9Sstevel@tonic-gate */ 21767c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 21777c478bd9Sstevel@tonic-gate ep->errstate.access_count = ep->errdef.access_count; 21787c478bd9Sstevel@tonic-gate ep->errstate.fail_count = ep->errdef.fail_count; 21797c478bd9Sstevel@tonic-gate ep->errstate.acc_chk = ep->errdef.acc_chk; 21807c478bd9Sstevel@tonic-gate ep->errstate.log = ep->errdef.log; 21817c478bd9Sstevel@tonic-gate *logpp = ep->logbase; 21827c478bd9Sstevel@tonic-gate *errstatep = ep->errstate; 21837c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 21847c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 21857c478bd9Sstevel@tonic-gate return (rval); 21867c478bd9Sstevel@tonic-gate } 21877c478bd9Sstevel@tonic-gate 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate /* 21907c478bd9Sstevel@tonic-gate * support routine - check if requested driver is defined as under test in the 21917c478bd9Sstevel@tonic-gate * conf file. 21927c478bd9Sstevel@tonic-gate */ 21937c478bd9Sstevel@tonic-gate static int 21947c478bd9Sstevel@tonic-gate driver_under_test(dev_info_t *rdip) 21957c478bd9Sstevel@tonic-gate { 21967c478bd9Sstevel@tonic-gate int i; 21977c478bd9Sstevel@tonic-gate char *rname; 21987c478bd9Sstevel@tonic-gate major_t rmaj; 21997c478bd9Sstevel@tonic-gate 22007c478bd9Sstevel@tonic-gate rname = ddi_get_name(rdip); 22017c478bd9Sstevel@tonic-gate rmaj = ddi_name_to_major(rname); 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate /* 22047c478bd9Sstevel@tonic-gate * Enforce the user to specifically request the following drivers. 22057c478bd9Sstevel@tonic-gate */ 22067c478bd9Sstevel@tonic-gate for (i = 0; i < driver_list_size; i += (1 + strlen(&driver_list[i]))) { 22077c478bd9Sstevel@tonic-gate if (driver_list_neg == 0) { 22087c478bd9Sstevel@tonic-gate if (rmaj == ddi_name_to_major(&driver_list[i])) 22097c478bd9Sstevel@tonic-gate return (1); 22107c478bd9Sstevel@tonic-gate } else { 22117c478bd9Sstevel@tonic-gate if (rmaj == ddi_name_to_major(&driver_list[i+1])) 22127c478bd9Sstevel@tonic-gate return (0); 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate } 22157c478bd9Sstevel@tonic-gate if (driver_list_neg == 0) 22167c478bd9Sstevel@tonic-gate return (0); 22177c478bd9Sstevel@tonic-gate else 22187c478bd9Sstevel@tonic-gate return (1); 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate } 22217c478bd9Sstevel@tonic-gate 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate static void 22247c478bd9Sstevel@tonic-gate log_acc_event(struct bofi_errent *ep, uint_t at, offset_t offset, off_t len, 22257c478bd9Sstevel@tonic-gate size_t repcount, uint64_t *valuep) 22267c478bd9Sstevel@tonic-gate { 22277c478bd9Sstevel@tonic-gate struct bofi_errdef *edp = &(ep->errdef); 22287c478bd9Sstevel@tonic-gate struct acc_log *log = &edp->log; 22297c478bd9Sstevel@tonic-gate 22307c478bd9Sstevel@tonic-gate ASSERT(log != NULL); 22317c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 22327c478bd9Sstevel@tonic-gate 22337c478bd9Sstevel@tonic-gate if (log->flags & BOFI_LOG_REPIO) 22347c478bd9Sstevel@tonic-gate repcount = 1; 22357c478bd9Sstevel@tonic-gate else if (repcount == 0 && edp->access_count > 0 && 22367c478bd9Sstevel@tonic-gate (log->flags & BOFI_LOG_FULL) == 0) 22377c478bd9Sstevel@tonic-gate edp->access_count += 1; 22387c478bd9Sstevel@tonic-gate 22397c478bd9Sstevel@tonic-gate if (repcount && log->entries < log->logsize) { 22407c478bd9Sstevel@tonic-gate struct acc_log_elem *elem = ep->logbase + log->entries; 22417c478bd9Sstevel@tonic-gate 22427c478bd9Sstevel@tonic-gate if (log->flags & BOFI_LOG_TIMESTAMP) 22437c478bd9Sstevel@tonic-gate elem->access_time = bofi_gettime(); 22447c478bd9Sstevel@tonic-gate elem->access_type = at; 22457c478bd9Sstevel@tonic-gate elem->offset = offset; 22467c478bd9Sstevel@tonic-gate elem->value = valuep ? *valuep : 0ll; 22477c478bd9Sstevel@tonic-gate elem->size = len; 22487c478bd9Sstevel@tonic-gate elem->repcount = repcount; 22497c478bd9Sstevel@tonic-gate ++log->entries; 22507c478bd9Sstevel@tonic-gate if (log->entries == log->logsize) { 22517c478bd9Sstevel@tonic-gate log->flags |= BOFI_LOG_FULL; 22527c478bd9Sstevel@tonic-gate ddi_trigger_softintr(((struct bofi_errent *) 22537c478bd9Sstevel@tonic-gate (uintptr_t)edp->errdef_handle)->softintr_id); 22547c478bd9Sstevel@tonic-gate } 22557c478bd9Sstevel@tonic-gate } 22567c478bd9Sstevel@tonic-gate if ((log->flags & BOFI_LOG_WRAP) && edp->access_count <= 1) { 22577c478bd9Sstevel@tonic-gate log->wrapcnt++; 22587c478bd9Sstevel@tonic-gate edp->access_count = log->logsize; 22597c478bd9Sstevel@tonic-gate log->entries = 0; /* wrap back to the start */ 22607c478bd9Sstevel@tonic-gate } 22617c478bd9Sstevel@tonic-gate } 22627c478bd9Sstevel@tonic-gate 22637c478bd9Sstevel@tonic-gate 22647c478bd9Sstevel@tonic-gate /* 22657c478bd9Sstevel@tonic-gate * got a condition match on dma read/write - check counts and corrupt 22667c478bd9Sstevel@tonic-gate * data if necessary 22677c478bd9Sstevel@tonic-gate * 22687c478bd9Sstevel@tonic-gate * bofi_mutex always held when this is called. 22697c478bd9Sstevel@tonic-gate */ 22707c478bd9Sstevel@tonic-gate static void 22717c478bd9Sstevel@tonic-gate do_dma_corrupt(struct bofi_shadow *hp, struct bofi_errent *ep, 22727c478bd9Sstevel@tonic-gate uint_t synctype, off_t off, off_t length) 22737c478bd9Sstevel@tonic-gate { 22747c478bd9Sstevel@tonic-gate uint64_t operand; 22757c478bd9Sstevel@tonic-gate int i; 22767c478bd9Sstevel@tonic-gate off_t len; 22777c478bd9Sstevel@tonic-gate caddr_t logaddr; 22787c478bd9Sstevel@tonic-gate uint64_t *addr; 22797c478bd9Sstevel@tonic-gate uint64_t *endaddr; 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 22827c478bd9Sstevel@tonic-gate if ((ep->errdef.access_count || 22837c478bd9Sstevel@tonic-gate ep->errdef.fail_count) && 22847c478bd9Sstevel@tonic-gate (ep->errdef.access_type & BOFI_LOG)) { 22857c478bd9Sstevel@tonic-gate uint_t atype; 22867c478bd9Sstevel@tonic-gate 22877c478bd9Sstevel@tonic-gate if (synctype == DDI_DMA_SYNC_FORDEV) 22887c478bd9Sstevel@tonic-gate atype = BOFI_DMA_W; 22897c478bd9Sstevel@tonic-gate else if (synctype == DDI_DMA_SYNC_FORCPU || 22907c478bd9Sstevel@tonic-gate synctype == DDI_DMA_SYNC_FORKERNEL) 22917c478bd9Sstevel@tonic-gate atype = BOFI_DMA_R; 22927c478bd9Sstevel@tonic-gate else 22937c478bd9Sstevel@tonic-gate atype = 0; 22947c478bd9Sstevel@tonic-gate if ((off <= ep->errdef.offset && 22957c478bd9Sstevel@tonic-gate off + length > ep->errdef.offset) || 22967c478bd9Sstevel@tonic-gate (off > ep->errdef.offset && 22977c478bd9Sstevel@tonic-gate off < ep->errdef.offset + ep->errdef.len)) { 22987c478bd9Sstevel@tonic-gate logaddr = (caddr_t)((uintptr_t)(hp->addr + 22997c478bd9Sstevel@tonic-gate off + LLSZMASK) & ~LLSZMASK); 23007c478bd9Sstevel@tonic-gate 23017c478bd9Sstevel@tonic-gate log_acc_event(ep, atype, logaddr - hp->addr, 23027c478bd9Sstevel@tonic-gate length, 1, 0); 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate } 23057c478bd9Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 23067c478bd9Sstevel@tonic-gate ep->errdef.access_count--; 23077c478bd9Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 23087c478bd9Sstevel@tonic-gate ep->errdef.fail_count--; 23097c478bd9Sstevel@tonic-gate ep->errdef.access_count = 0; 23107c478bd9Sstevel@tonic-gate /* 23117c478bd9Sstevel@tonic-gate * OK do the corruption 23127c478bd9Sstevel@tonic-gate */ 23137c478bd9Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 23147c478bd9Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 23157c478bd9Sstevel@tonic-gate /* 23167c478bd9Sstevel@tonic-gate * work out how much to corrupt 23177c478bd9Sstevel@tonic-gate * 23187c478bd9Sstevel@tonic-gate * Make sure endaddr isn't greater than hp->addr + hp->len. 23197c478bd9Sstevel@tonic-gate * If endaddr becomes less than addr len becomes negative 23207c478bd9Sstevel@tonic-gate * and the following loop isn't entered. 23217c478bd9Sstevel@tonic-gate */ 23227c478bd9Sstevel@tonic-gate addr = (uint64_t *)((uintptr_t)((hp->addr + 23237c478bd9Sstevel@tonic-gate ep->errdef.offset) + LLSZMASK) & ~LLSZMASK); 23247c478bd9Sstevel@tonic-gate endaddr = (uint64_t *)((uintptr_t)(hp->addr + min(hp->len, 23257c478bd9Sstevel@tonic-gate ep->errdef.offset + ep->errdef.len)) & ~LLSZMASK); 23267c478bd9Sstevel@tonic-gate len = endaddr - addr; 23277c478bd9Sstevel@tonic-gate operand = ep->errdef.operand; 23287c478bd9Sstevel@tonic-gate switch (ep->errdef.optype) { 23297c478bd9Sstevel@tonic-gate case BOFI_EQUAL : 23307c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) 23317c478bd9Sstevel@tonic-gate *(addr + i) = operand; 23327c478bd9Sstevel@tonic-gate break; 23337c478bd9Sstevel@tonic-gate case BOFI_AND : 23347c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) 23357c478bd9Sstevel@tonic-gate *(addr + i) &= operand; 23367c478bd9Sstevel@tonic-gate break; 23377c478bd9Sstevel@tonic-gate case BOFI_OR : 23387c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) 23397c478bd9Sstevel@tonic-gate *(addr + i) |= operand; 23407c478bd9Sstevel@tonic-gate break; 23417c478bd9Sstevel@tonic-gate case BOFI_XOR : 23427c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) 23437c478bd9Sstevel@tonic-gate *(addr + i) ^= operand; 23447c478bd9Sstevel@tonic-gate break; 23457c478bd9Sstevel@tonic-gate default: 23467c478bd9Sstevel@tonic-gate /* do nothing */ 23477c478bd9Sstevel@tonic-gate break; 23487c478bd9Sstevel@tonic-gate } 23497c478bd9Sstevel@tonic-gate } 23507c478bd9Sstevel@tonic-gate } 23517c478bd9Sstevel@tonic-gate 23527c478bd9Sstevel@tonic-gate 23537c478bd9Sstevel@tonic-gate static uint64_t do_bofi_rd8(struct bofi_shadow *, caddr_t); 23547c478bd9Sstevel@tonic-gate static uint64_t do_bofi_rd16(struct bofi_shadow *, caddr_t); 23557c478bd9Sstevel@tonic-gate static uint64_t do_bofi_rd32(struct bofi_shadow *, caddr_t); 23567c478bd9Sstevel@tonic-gate static uint64_t do_bofi_rd64(struct bofi_shadow *, caddr_t); 23577c478bd9Sstevel@tonic-gate 23587c478bd9Sstevel@tonic-gate 23597c478bd9Sstevel@tonic-gate /* 23607c478bd9Sstevel@tonic-gate * check all errdefs linked to this shadow handle. If we've got a condition 23617c478bd9Sstevel@tonic-gate * match check counts and corrupt data if necessary 23627c478bd9Sstevel@tonic-gate * 23637c478bd9Sstevel@tonic-gate * bofi_mutex always held when this is called. 23647c478bd9Sstevel@tonic-gate * 23657c478bd9Sstevel@tonic-gate * because of possibility of BOFI_NO_TRANSFER, we couldn't get data 23667c478bd9Sstevel@tonic-gate * from io-space before calling this, so we pass in the func to do the 23677c478bd9Sstevel@tonic-gate * transfer as a parameter. 23687c478bd9Sstevel@tonic-gate */ 23697c478bd9Sstevel@tonic-gate static uint64_t 23707c478bd9Sstevel@tonic-gate do_pior_corrupt(struct bofi_shadow *hp, caddr_t addr, 23717c478bd9Sstevel@tonic-gate uint64_t (*func)(), size_t repcount, size_t accsize) 23727c478bd9Sstevel@tonic-gate { 23737c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 23747c478bd9Sstevel@tonic-gate struct bofi_link *lp; 23757c478bd9Sstevel@tonic-gate uint64_t operand; 23767c478bd9Sstevel@tonic-gate uintptr_t minlen; 23777c478bd9Sstevel@tonic-gate intptr_t base; 23787c478bd9Sstevel@tonic-gate int done_get = 0; 23797c478bd9Sstevel@tonic-gate uint64_t get_val, gv; 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 23827c478bd9Sstevel@tonic-gate /* 23837c478bd9Sstevel@tonic-gate * check through all errdefs associated with this shadow handle 23847c478bd9Sstevel@tonic-gate */ 23857c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 23867c478bd9Sstevel@tonic-gate ep = lp->errentp; 23877c478bd9Sstevel@tonic-gate if (ep->errdef.len == 0) 23887c478bd9Sstevel@tonic-gate minlen = hp->len; 23897c478bd9Sstevel@tonic-gate else 23907c478bd9Sstevel@tonic-gate minlen = min(hp->len, ep->errdef.len); 23917c478bd9Sstevel@tonic-gate base = addr - hp->addr - ep->errdef.offset + hp->offset; 23927c478bd9Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_PIO_R) && 23937c478bd9Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE) && 23947c478bd9Sstevel@tonic-gate base >= 0 && base < minlen) { 23957c478bd9Sstevel@tonic-gate /* 23967c478bd9Sstevel@tonic-gate * condition match for pio read 23977c478bd9Sstevel@tonic-gate */ 23987c478bd9Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 23997c478bd9Sstevel@tonic-gate ep->errdef.access_count--; 24007c478bd9Sstevel@tonic-gate if (done_get == 0) { 24017c478bd9Sstevel@tonic-gate done_get = 1; 24027c478bd9Sstevel@tonic-gate gv = get_val = func(hp, addr); 24037c478bd9Sstevel@tonic-gate } 24047c478bd9Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) { 24057c478bd9Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_R, 24067c478bd9Sstevel@tonic-gate addr - hp->addr, 24077c478bd9Sstevel@tonic-gate accsize, repcount, &gv); 24087c478bd9Sstevel@tonic-gate } 24097c478bd9Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 24107c478bd9Sstevel@tonic-gate ep->errdef.fail_count--; 24117c478bd9Sstevel@tonic-gate ep->errdef.access_count = 0; 24127c478bd9Sstevel@tonic-gate /* 24137c478bd9Sstevel@tonic-gate * OK do corruption 24147c478bd9Sstevel@tonic-gate */ 24157c478bd9Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 24167c478bd9Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 24177c478bd9Sstevel@tonic-gate operand = ep->errdef.operand; 24187c478bd9Sstevel@tonic-gate if (done_get == 0) { 24197c478bd9Sstevel@tonic-gate if (ep->errdef.optype == 24207c478bd9Sstevel@tonic-gate BOFI_NO_TRANSFER) 24217c478bd9Sstevel@tonic-gate /* 24227c478bd9Sstevel@tonic-gate * no transfer - bomb out 24237c478bd9Sstevel@tonic-gate */ 24247c478bd9Sstevel@tonic-gate return (operand); 24257c478bd9Sstevel@tonic-gate done_get = 1; 24267c478bd9Sstevel@tonic-gate gv = get_val = func(hp, addr); 24277c478bd9Sstevel@tonic-gate 24287c478bd9Sstevel@tonic-gate } 24297c478bd9Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) { 24307c478bd9Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_R, 24317c478bd9Sstevel@tonic-gate addr - hp->addr, 24327c478bd9Sstevel@tonic-gate accsize, repcount, &gv); 24337c478bd9Sstevel@tonic-gate } 24347c478bd9Sstevel@tonic-gate switch (ep->errdef.optype) { 24357c478bd9Sstevel@tonic-gate case BOFI_EQUAL : 24367c478bd9Sstevel@tonic-gate get_val = operand; 24377c478bd9Sstevel@tonic-gate break; 24387c478bd9Sstevel@tonic-gate case BOFI_AND : 24397c478bd9Sstevel@tonic-gate get_val &= operand; 24407c478bd9Sstevel@tonic-gate break; 24417c478bd9Sstevel@tonic-gate case BOFI_OR : 24427c478bd9Sstevel@tonic-gate get_val |= operand; 24437c478bd9Sstevel@tonic-gate break; 24447c478bd9Sstevel@tonic-gate case BOFI_XOR : 24457c478bd9Sstevel@tonic-gate get_val ^= operand; 24467c478bd9Sstevel@tonic-gate break; 24477c478bd9Sstevel@tonic-gate default: 24487c478bd9Sstevel@tonic-gate /* do nothing */ 24497c478bd9Sstevel@tonic-gate break; 24507c478bd9Sstevel@tonic-gate } 24517c478bd9Sstevel@tonic-gate } 24527c478bd9Sstevel@tonic-gate } 24537c478bd9Sstevel@tonic-gate } 24547c478bd9Sstevel@tonic-gate if (done_get == 0) 24557c478bd9Sstevel@tonic-gate return (func(hp, addr)); 24567c478bd9Sstevel@tonic-gate else 24577c478bd9Sstevel@tonic-gate return (get_val); 24587c478bd9Sstevel@tonic-gate } 24597c478bd9Sstevel@tonic-gate 24607c478bd9Sstevel@tonic-gate 24617c478bd9Sstevel@tonic-gate /* 24627c478bd9Sstevel@tonic-gate * check all errdefs linked to this shadow handle. If we've got a condition 24637c478bd9Sstevel@tonic-gate * match check counts and corrupt data if necessary 24647c478bd9Sstevel@tonic-gate * 24657c478bd9Sstevel@tonic-gate * bofi_mutex always held when this is called. 24667c478bd9Sstevel@tonic-gate * 24677c478bd9Sstevel@tonic-gate * because of possibility of BOFI_NO_TRANSFER, we return 0 if no data 24687c478bd9Sstevel@tonic-gate * is to be written out to io-space, 1 otherwise 24697c478bd9Sstevel@tonic-gate */ 24707c478bd9Sstevel@tonic-gate static int 24717c478bd9Sstevel@tonic-gate do_piow_corrupt(struct bofi_shadow *hp, caddr_t addr, uint64_t *valuep, 24727c478bd9Sstevel@tonic-gate size_t size, size_t repcount) 24737c478bd9Sstevel@tonic-gate { 24747c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 24757c478bd9Sstevel@tonic-gate struct bofi_link *lp; 24767c478bd9Sstevel@tonic-gate uintptr_t minlen; 24777c478bd9Sstevel@tonic-gate intptr_t base; 24787c478bd9Sstevel@tonic-gate uint64_t v = *valuep; 24797c478bd9Sstevel@tonic-gate 24807c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 24817c478bd9Sstevel@tonic-gate /* 24827c478bd9Sstevel@tonic-gate * check through all errdefs associated with this shadow handle 24837c478bd9Sstevel@tonic-gate */ 24847c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 24857c478bd9Sstevel@tonic-gate ep = lp->errentp; 24867c478bd9Sstevel@tonic-gate if (ep->errdef.len == 0) 24877c478bd9Sstevel@tonic-gate minlen = hp->len; 24887c478bd9Sstevel@tonic-gate else 24897c478bd9Sstevel@tonic-gate minlen = min(hp->len, ep->errdef.len); 24907c478bd9Sstevel@tonic-gate base = (caddr_t)addr - hp->addr - ep->errdef.offset +hp->offset; 24917c478bd9Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_PIO_W) && 24927c478bd9Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE) && 24937c478bd9Sstevel@tonic-gate base >= 0 && base < minlen) { 24947c478bd9Sstevel@tonic-gate /* 24957c478bd9Sstevel@tonic-gate * condition match for pio write 24967c478bd9Sstevel@tonic-gate */ 24977c478bd9Sstevel@tonic-gate 24987c478bd9Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 24997c478bd9Sstevel@tonic-gate ep->errdef.access_count--; 25007c478bd9Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) 25017c478bd9Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_W, 25027c478bd9Sstevel@tonic-gate addr - hp->addr, size, 25037c478bd9Sstevel@tonic-gate repcount, &v); 25047c478bd9Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 25057c478bd9Sstevel@tonic-gate ep->errdef.fail_count--; 25067c478bd9Sstevel@tonic-gate ep->errdef.access_count = 0; 25077c478bd9Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) 25087c478bd9Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_W, 25097c478bd9Sstevel@tonic-gate addr - hp->addr, size, 25107c478bd9Sstevel@tonic-gate repcount, &v); 25117c478bd9Sstevel@tonic-gate /* 25127c478bd9Sstevel@tonic-gate * OK do corruption 25137c478bd9Sstevel@tonic-gate */ 25147c478bd9Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 25157c478bd9Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 25167c478bd9Sstevel@tonic-gate switch (ep->errdef.optype) { 25177c478bd9Sstevel@tonic-gate case BOFI_EQUAL : 25187c478bd9Sstevel@tonic-gate *valuep = ep->errdef.operand; 25197c478bd9Sstevel@tonic-gate break; 25207c478bd9Sstevel@tonic-gate case BOFI_AND : 25217c478bd9Sstevel@tonic-gate *valuep &= ep->errdef.operand; 25227c478bd9Sstevel@tonic-gate break; 25237c478bd9Sstevel@tonic-gate case BOFI_OR : 25247c478bd9Sstevel@tonic-gate *valuep |= ep->errdef.operand; 25257c478bd9Sstevel@tonic-gate break; 25267c478bd9Sstevel@tonic-gate case BOFI_XOR : 25277c478bd9Sstevel@tonic-gate *valuep ^= ep->errdef.operand; 25287c478bd9Sstevel@tonic-gate break; 25297c478bd9Sstevel@tonic-gate case BOFI_NO_TRANSFER : 25307c478bd9Sstevel@tonic-gate /* 25317c478bd9Sstevel@tonic-gate * no transfer - bomb out 25327c478bd9Sstevel@tonic-gate */ 25337c478bd9Sstevel@tonic-gate return (0); 25347c478bd9Sstevel@tonic-gate default: 25357c478bd9Sstevel@tonic-gate /* do nothing */ 25367c478bd9Sstevel@tonic-gate break; 25377c478bd9Sstevel@tonic-gate } 25387c478bd9Sstevel@tonic-gate } 25397c478bd9Sstevel@tonic-gate } 25407c478bd9Sstevel@tonic-gate } 25417c478bd9Sstevel@tonic-gate return (1); 25427c478bd9Sstevel@tonic-gate } 25437c478bd9Sstevel@tonic-gate 25447c478bd9Sstevel@tonic-gate 25457c478bd9Sstevel@tonic-gate static uint64_t 25467c478bd9Sstevel@tonic-gate do_bofi_rd8(struct bofi_shadow *hp, caddr_t addr) 25477c478bd9Sstevel@tonic-gate { 25487c478bd9Sstevel@tonic-gate return (hp->save.acc.ahi_get8(&hp->save.acc, (uint8_t *)addr)); 25497c478bd9Sstevel@tonic-gate } 25507c478bd9Sstevel@tonic-gate 25517c478bd9Sstevel@tonic-gate #define BOFI_READ_CHECKS(type) \ 25527c478bd9Sstevel@tonic-gate if (bofi_ddi_check) \ 25537c478bd9Sstevel@tonic-gate addr = (type *)((uintptr_t)addr - 64 + hp->addr); \ 25547c478bd9Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)addr < hp->addr || \ 25557c478bd9Sstevel@tonic-gate (caddr_t)addr - hp->addr >= hp->len)) { \ 25567c478bd9Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 25577c478bd9Sstevel@tonic-gate "ddi_get() out of range addr %p not in %p/%llx", \ 25587c478bd9Sstevel@tonic-gate (void *)addr, (void *)hp->addr, hp->len); \ 25597c478bd9Sstevel@tonic-gate return (0); \ 25607c478bd9Sstevel@tonic-gate } 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate /* 25637c478bd9Sstevel@tonic-gate * our getb() routine - use tryenter 25647c478bd9Sstevel@tonic-gate */ 25657c478bd9Sstevel@tonic-gate static uint8_t 25667c478bd9Sstevel@tonic-gate bofi_rd8(ddi_acc_impl_t *handle, uint8_t *addr) 25677c478bd9Sstevel@tonic-gate { 25687c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 25697c478bd9Sstevel@tonic-gate uint8_t retval; 25707c478bd9Sstevel@tonic-gate 25717c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 25727c478bd9Sstevel@tonic-gate BOFI_READ_CHECKS(uint8_t) 25737c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 25747c478bd9Sstevel@tonic-gate return (hp->save.acc.ahi_get8(&hp->save.acc, addr)); 25757c478bd9Sstevel@tonic-gate retval = (uint8_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd8, 1, 25767c478bd9Sstevel@tonic-gate 1); 25777c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 25787c478bd9Sstevel@tonic-gate return (retval); 25797c478bd9Sstevel@tonic-gate } 25807c478bd9Sstevel@tonic-gate 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate static uint64_t 25837c478bd9Sstevel@tonic-gate do_bofi_rd16(struct bofi_shadow *hp, caddr_t addr) 25847c478bd9Sstevel@tonic-gate { 25857c478bd9Sstevel@tonic-gate return (hp->save.acc.ahi_get16(&hp->save.acc, (uint16_t *)addr)); 25867c478bd9Sstevel@tonic-gate } 25877c478bd9Sstevel@tonic-gate 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate /* 25907c478bd9Sstevel@tonic-gate * our getw() routine - use tryenter 25917c478bd9Sstevel@tonic-gate */ 25927c478bd9Sstevel@tonic-gate static uint16_t 25937c478bd9Sstevel@tonic-gate bofi_rd16(ddi_acc_impl_t *handle, uint16_t *addr) 25947c478bd9Sstevel@tonic-gate { 25957c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 25967c478bd9Sstevel@tonic-gate uint16_t retval; 25977c478bd9Sstevel@tonic-gate 25987c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 25997c478bd9Sstevel@tonic-gate BOFI_READ_CHECKS(uint16_t) 26007c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 26017c478bd9Sstevel@tonic-gate return (hp->save.acc.ahi_get16(&hp->save.acc, addr)); 26027c478bd9Sstevel@tonic-gate retval = (uint16_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd16, 1, 26037c478bd9Sstevel@tonic-gate 2); 26047c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 26057c478bd9Sstevel@tonic-gate return (retval); 26067c478bd9Sstevel@tonic-gate } 26077c478bd9Sstevel@tonic-gate 26087c478bd9Sstevel@tonic-gate 26097c478bd9Sstevel@tonic-gate static uint64_t 26107c478bd9Sstevel@tonic-gate do_bofi_rd32(struct bofi_shadow *hp, caddr_t addr) 26117c478bd9Sstevel@tonic-gate { 26127c478bd9Sstevel@tonic-gate return (hp->save.acc.ahi_get32(&hp->save.acc, (uint32_t *)addr)); 26137c478bd9Sstevel@tonic-gate } 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate 26167c478bd9Sstevel@tonic-gate /* 26177c478bd9Sstevel@tonic-gate * our getl() routine - use tryenter 26187c478bd9Sstevel@tonic-gate */ 26197c478bd9Sstevel@tonic-gate static uint32_t 26207c478bd9Sstevel@tonic-gate bofi_rd32(ddi_acc_impl_t *handle, uint32_t *addr) 26217c478bd9Sstevel@tonic-gate { 26227c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 26237c478bd9Sstevel@tonic-gate uint32_t retval; 26247c478bd9Sstevel@tonic-gate 26257c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 26267c478bd9Sstevel@tonic-gate BOFI_READ_CHECKS(uint32_t) 26277c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 26287c478bd9Sstevel@tonic-gate return (hp->save.acc.ahi_get32(&hp->save.acc, addr)); 26297c478bd9Sstevel@tonic-gate retval = (uint32_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd32, 1, 26307c478bd9Sstevel@tonic-gate 4); 26317c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 26327c478bd9Sstevel@tonic-gate return (retval); 26337c478bd9Sstevel@tonic-gate } 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate 26367c478bd9Sstevel@tonic-gate static uint64_t 26377c478bd9Sstevel@tonic-gate do_bofi_rd64(struct bofi_shadow *hp, caddr_t addr) 26387c478bd9Sstevel@tonic-gate { 26397c478bd9Sstevel@tonic-gate return (hp->save.acc.ahi_get64(&hp->save.acc, (uint64_t *)addr)); 26407c478bd9Sstevel@tonic-gate } 26417c478bd9Sstevel@tonic-gate 26427c478bd9Sstevel@tonic-gate 26437c478bd9Sstevel@tonic-gate /* 26447c478bd9Sstevel@tonic-gate * our getll() routine - use tryenter 26457c478bd9Sstevel@tonic-gate */ 26467c478bd9Sstevel@tonic-gate static uint64_t 26477c478bd9Sstevel@tonic-gate bofi_rd64(ddi_acc_impl_t *handle, uint64_t *addr) 26487c478bd9Sstevel@tonic-gate { 26497c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 26507c478bd9Sstevel@tonic-gate uint64_t retval; 26517c478bd9Sstevel@tonic-gate 26527c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 26537c478bd9Sstevel@tonic-gate BOFI_READ_CHECKS(uint64_t) 26547c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 26557c478bd9Sstevel@tonic-gate return (hp->save.acc.ahi_get64(&hp->save.acc, addr)); 26567c478bd9Sstevel@tonic-gate retval = (uint64_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd64, 1, 26577c478bd9Sstevel@tonic-gate 8); 26587c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 26597c478bd9Sstevel@tonic-gate return (retval); 26607c478bd9Sstevel@tonic-gate } 26617c478bd9Sstevel@tonic-gate 26627c478bd9Sstevel@tonic-gate #define BOFI_WRITE_TESTS(type) \ 26637c478bd9Sstevel@tonic-gate if (bofi_ddi_check) \ 26647c478bd9Sstevel@tonic-gate addr = (type *)((uintptr_t)addr - 64 + hp->addr); \ 26657c478bd9Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)addr < hp->addr || \ 26667c478bd9Sstevel@tonic-gate (caddr_t)addr - hp->addr >= hp->len)) { \ 26677c478bd9Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 26687c478bd9Sstevel@tonic-gate "ddi_put() out of range addr %p not in %p/%llx\n", \ 26697c478bd9Sstevel@tonic-gate (void *)addr, (void *)hp->addr, hp->len); \ 26707c478bd9Sstevel@tonic-gate return; \ 26717c478bd9Sstevel@tonic-gate } 26727c478bd9Sstevel@tonic-gate 26737c478bd9Sstevel@tonic-gate /* 26747c478bd9Sstevel@tonic-gate * our putb() routine - use tryenter 26757c478bd9Sstevel@tonic-gate */ 26767c478bd9Sstevel@tonic-gate static void 26777c478bd9Sstevel@tonic-gate bofi_wr8(ddi_acc_impl_t *handle, uint8_t *addr, uint8_t value) 26787c478bd9Sstevel@tonic-gate { 26797c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 26807c478bd9Sstevel@tonic-gate uint64_t llvalue = value; 26817c478bd9Sstevel@tonic-gate 26827c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 26837c478bd9Sstevel@tonic-gate BOFI_WRITE_TESTS(uint8_t) 26847c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 26857c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put8(&hp->save.acc, addr, (uint8_t)llvalue); 26867c478bd9Sstevel@tonic-gate return; 26877c478bd9Sstevel@tonic-gate } 26887c478bd9Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 1, 1)) 26897c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put8(&hp->save.acc, addr, (uint8_t)llvalue); 26907c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 26917c478bd9Sstevel@tonic-gate } 26927c478bd9Sstevel@tonic-gate 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate /* 26957c478bd9Sstevel@tonic-gate * our putw() routine - use tryenter 26967c478bd9Sstevel@tonic-gate */ 26977c478bd9Sstevel@tonic-gate static void 26987c478bd9Sstevel@tonic-gate bofi_wr16(ddi_acc_impl_t *handle, uint16_t *addr, uint16_t value) 26997c478bd9Sstevel@tonic-gate { 27007c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 27017c478bd9Sstevel@tonic-gate uint64_t llvalue = value; 27027c478bd9Sstevel@tonic-gate 27037c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 27047c478bd9Sstevel@tonic-gate BOFI_WRITE_TESTS(uint16_t) 27057c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 27067c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put16(&hp->save.acc, addr, (uint16_t)llvalue); 27077c478bd9Sstevel@tonic-gate return; 27087c478bd9Sstevel@tonic-gate } 27097c478bd9Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 2, 1)) 27107c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put16(&hp->save.acc, addr, (uint16_t)llvalue); 27117c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 27127c478bd9Sstevel@tonic-gate } 27137c478bd9Sstevel@tonic-gate 27147c478bd9Sstevel@tonic-gate 27157c478bd9Sstevel@tonic-gate /* 27167c478bd9Sstevel@tonic-gate * our putl() routine - use tryenter 27177c478bd9Sstevel@tonic-gate */ 27187c478bd9Sstevel@tonic-gate static void 27197c478bd9Sstevel@tonic-gate bofi_wr32(ddi_acc_impl_t *handle, uint32_t *addr, uint32_t value) 27207c478bd9Sstevel@tonic-gate { 27217c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 27227c478bd9Sstevel@tonic-gate uint64_t llvalue = value; 27237c478bd9Sstevel@tonic-gate 27247c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 27257c478bd9Sstevel@tonic-gate BOFI_WRITE_TESTS(uint32_t) 27267c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 27277c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put32(&hp->save.acc, addr, (uint32_t)llvalue); 27287c478bd9Sstevel@tonic-gate return; 27297c478bd9Sstevel@tonic-gate } 27307c478bd9Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 4, 1)) 27317c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put32(&hp->save.acc, addr, (uint32_t)llvalue); 27327c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 27337c478bd9Sstevel@tonic-gate } 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate 27367c478bd9Sstevel@tonic-gate /* 27377c478bd9Sstevel@tonic-gate * our putll() routine - use tryenter 27387c478bd9Sstevel@tonic-gate */ 27397c478bd9Sstevel@tonic-gate static void 27407c478bd9Sstevel@tonic-gate bofi_wr64(ddi_acc_impl_t *handle, uint64_t *addr, uint64_t value) 27417c478bd9Sstevel@tonic-gate { 27427c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 27437c478bd9Sstevel@tonic-gate uint64_t llvalue = value; 27447c478bd9Sstevel@tonic-gate 27457c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 27467c478bd9Sstevel@tonic-gate BOFI_WRITE_TESTS(uint64_t) 27477c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 27487c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put64(&hp->save.acc, addr, (uint64_t)llvalue); 27497c478bd9Sstevel@tonic-gate return; 27507c478bd9Sstevel@tonic-gate } 27517c478bd9Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 8, 1)) 27527c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put64(&hp->save.acc, addr, (uint64_t)llvalue); 27537c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 27547c478bd9Sstevel@tonic-gate } 27557c478bd9Sstevel@tonic-gate 27567c478bd9Sstevel@tonic-gate #define BOFI_REP_READ_TESTS(type) \ 27577c478bd9Sstevel@tonic-gate if (bofi_ddi_check) \ 27587c478bd9Sstevel@tonic-gate dev_addr = (type *)((uintptr_t)dev_addr - 64 + hp->addr); \ 27597c478bd9Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)dev_addr < hp->addr || \ 27607c478bd9Sstevel@tonic-gate (caddr_t)(dev_addr + repcount) - hp->addr > hp->len)) { \ 27617c478bd9Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 27627c478bd9Sstevel@tonic-gate "ddi_rep_get() out of range addr %p not in %p/%llx\n", \ 27637c478bd9Sstevel@tonic-gate (void *)dev_addr, (void *)hp->addr, hp->len); \ 27647c478bd9Sstevel@tonic-gate if ((caddr_t)dev_addr < hp->addr || \ 27657c478bd9Sstevel@tonic-gate (caddr_t)dev_addr - hp->addr >= hp->len) \ 27667c478bd9Sstevel@tonic-gate return; \ 27677c478bd9Sstevel@tonic-gate repcount = (type *)(hp->addr + hp->len) - dev_addr; \ 27687c478bd9Sstevel@tonic-gate } 27697c478bd9Sstevel@tonic-gate 27707c478bd9Sstevel@tonic-gate /* 27717c478bd9Sstevel@tonic-gate * our rep_getb() routine - use tryenter 27727c478bd9Sstevel@tonic-gate */ 27737c478bd9Sstevel@tonic-gate static void 27747c478bd9Sstevel@tonic-gate bofi_rep_rd8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr, 27757c478bd9Sstevel@tonic-gate size_t repcount, uint_t flags) 27767c478bd9Sstevel@tonic-gate { 27777c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 27787c478bd9Sstevel@tonic-gate int i; 27797c478bd9Sstevel@tonic-gate uint8_t *addr; 27807c478bd9Sstevel@tonic-gate 27817c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 27827c478bd9Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint8_t) 27837c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 27847c478bd9Sstevel@tonic-gate hp->save.acc.ahi_rep_get8(&hp->save.acc, host_addr, dev_addr, 27857c478bd9Sstevel@tonic-gate repcount, flags); 27867c478bd9Sstevel@tonic-gate return; 27877c478bd9Sstevel@tonic-gate } 27887c478bd9Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 27897c478bd9Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 27907c478bd9Sstevel@tonic-gate *(host_addr + i) = (uint8_t)do_pior_corrupt(hp, (caddr_t)addr, 27917c478bd9Sstevel@tonic-gate do_bofi_rd8, i ? 0 : repcount, 1); 27927c478bd9Sstevel@tonic-gate } 27937c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 27947c478bd9Sstevel@tonic-gate } 27957c478bd9Sstevel@tonic-gate 27967c478bd9Sstevel@tonic-gate 27977c478bd9Sstevel@tonic-gate /* 27987c478bd9Sstevel@tonic-gate * our rep_getw() routine - use tryenter 27997c478bd9Sstevel@tonic-gate */ 28007c478bd9Sstevel@tonic-gate static void 28017c478bd9Sstevel@tonic-gate bofi_rep_rd16(ddi_acc_impl_t *handle, uint16_t *host_addr, 28027c478bd9Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 28037c478bd9Sstevel@tonic-gate { 28047c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 28057c478bd9Sstevel@tonic-gate int i; 28067c478bd9Sstevel@tonic-gate uint16_t *addr; 28077c478bd9Sstevel@tonic-gate 28087c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 28097c478bd9Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint16_t) 28107c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 28117c478bd9Sstevel@tonic-gate hp->save.acc.ahi_rep_get16(&hp->save.acc, host_addr, dev_addr, 28127c478bd9Sstevel@tonic-gate repcount, flags); 28137c478bd9Sstevel@tonic-gate return; 28147c478bd9Sstevel@tonic-gate } 28157c478bd9Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 28167c478bd9Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 28177c478bd9Sstevel@tonic-gate *(host_addr + i) = (uint16_t)do_pior_corrupt(hp, (caddr_t)addr, 28187c478bd9Sstevel@tonic-gate do_bofi_rd16, i ? 0 : repcount, 2); 28197c478bd9Sstevel@tonic-gate } 28207c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 28217c478bd9Sstevel@tonic-gate } 28227c478bd9Sstevel@tonic-gate 28237c478bd9Sstevel@tonic-gate 28247c478bd9Sstevel@tonic-gate /* 28257c478bd9Sstevel@tonic-gate * our rep_getl() routine - use tryenter 28267c478bd9Sstevel@tonic-gate */ 28277c478bd9Sstevel@tonic-gate static void 28287c478bd9Sstevel@tonic-gate bofi_rep_rd32(ddi_acc_impl_t *handle, uint32_t *host_addr, 28297c478bd9Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 28307c478bd9Sstevel@tonic-gate { 28317c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 28327c478bd9Sstevel@tonic-gate int i; 28337c478bd9Sstevel@tonic-gate uint32_t *addr; 28347c478bd9Sstevel@tonic-gate 28357c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 28367c478bd9Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint32_t) 28377c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 28387c478bd9Sstevel@tonic-gate hp->save.acc.ahi_rep_get32(&hp->save.acc, host_addr, dev_addr, 28397c478bd9Sstevel@tonic-gate repcount, flags); 28407c478bd9Sstevel@tonic-gate return; 28417c478bd9Sstevel@tonic-gate } 28427c478bd9Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 28437c478bd9Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 28447c478bd9Sstevel@tonic-gate *(host_addr + i) = (uint32_t)do_pior_corrupt(hp, (caddr_t)addr, 28457c478bd9Sstevel@tonic-gate do_bofi_rd32, i ? 0 : repcount, 4); 28467c478bd9Sstevel@tonic-gate } 28477c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 28487c478bd9Sstevel@tonic-gate } 28497c478bd9Sstevel@tonic-gate 28507c478bd9Sstevel@tonic-gate 28517c478bd9Sstevel@tonic-gate /* 28527c478bd9Sstevel@tonic-gate * our rep_getll() routine - use tryenter 28537c478bd9Sstevel@tonic-gate */ 28547c478bd9Sstevel@tonic-gate static void 28557c478bd9Sstevel@tonic-gate bofi_rep_rd64(ddi_acc_impl_t *handle, uint64_t *host_addr, 28567c478bd9Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 28577c478bd9Sstevel@tonic-gate { 28587c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 28597c478bd9Sstevel@tonic-gate int i; 28607c478bd9Sstevel@tonic-gate uint64_t *addr; 28617c478bd9Sstevel@tonic-gate 28627c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 28637c478bd9Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint64_t) 28647c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 28657c478bd9Sstevel@tonic-gate hp->save.acc.ahi_rep_get64(&hp->save.acc, host_addr, dev_addr, 28667c478bd9Sstevel@tonic-gate repcount, flags); 28677c478bd9Sstevel@tonic-gate return; 28687c478bd9Sstevel@tonic-gate } 28697c478bd9Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 28707c478bd9Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 28717c478bd9Sstevel@tonic-gate *(host_addr + i) = (uint64_t)do_pior_corrupt(hp, (caddr_t)addr, 28727c478bd9Sstevel@tonic-gate do_bofi_rd64, i ? 0 : repcount, 8); 28737c478bd9Sstevel@tonic-gate } 28747c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 28757c478bd9Sstevel@tonic-gate } 28767c478bd9Sstevel@tonic-gate 28777c478bd9Sstevel@tonic-gate #define BOFI_REP_WRITE_TESTS(type) \ 28787c478bd9Sstevel@tonic-gate if (bofi_ddi_check) \ 28797c478bd9Sstevel@tonic-gate dev_addr = (type *)((uintptr_t)dev_addr - 64 + hp->addr); \ 28807c478bd9Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)dev_addr < hp->addr || \ 28817c478bd9Sstevel@tonic-gate (caddr_t)(dev_addr + repcount) - hp->addr > hp->len)) { \ 28827c478bd9Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 28837c478bd9Sstevel@tonic-gate "ddi_rep_put() out of range addr %p not in %p/%llx\n", \ 28847c478bd9Sstevel@tonic-gate (void *)dev_addr, (void *)hp->addr, hp->len); \ 28857c478bd9Sstevel@tonic-gate if ((caddr_t)dev_addr < hp->addr || \ 28867c478bd9Sstevel@tonic-gate (caddr_t)dev_addr - hp->addr >= hp->len) \ 28877c478bd9Sstevel@tonic-gate return; \ 28887c478bd9Sstevel@tonic-gate repcount = (type *)(hp->addr + hp->len) - dev_addr; \ 28897c478bd9Sstevel@tonic-gate } 28907c478bd9Sstevel@tonic-gate 28917c478bd9Sstevel@tonic-gate /* 28927c478bd9Sstevel@tonic-gate * our rep_putb() routine - use tryenter 28937c478bd9Sstevel@tonic-gate */ 28947c478bd9Sstevel@tonic-gate static void 28957c478bd9Sstevel@tonic-gate bofi_rep_wr8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr, 28967c478bd9Sstevel@tonic-gate size_t repcount, uint_t flags) 28977c478bd9Sstevel@tonic-gate { 28987c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 28997c478bd9Sstevel@tonic-gate int i; 29007c478bd9Sstevel@tonic-gate uint64_t llvalue; 29017c478bd9Sstevel@tonic-gate uint8_t *addr; 29027c478bd9Sstevel@tonic-gate 29037c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 29047c478bd9Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint8_t) 29057c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 29067c478bd9Sstevel@tonic-gate hp->save.acc.ahi_rep_put8(&hp->save.acc, host_addr, dev_addr, 29077c478bd9Sstevel@tonic-gate repcount, flags); 29087c478bd9Sstevel@tonic-gate return; 29097c478bd9Sstevel@tonic-gate } 29107c478bd9Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 29117c478bd9Sstevel@tonic-gate llvalue = *(host_addr + i); 29127c478bd9Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 29137c478bd9Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 1, i ? 0 : 29147c478bd9Sstevel@tonic-gate repcount)) 29157c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put8(&hp->save.acc, addr, 29167c478bd9Sstevel@tonic-gate (uint8_t)llvalue); 29177c478bd9Sstevel@tonic-gate } 29187c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 29197c478bd9Sstevel@tonic-gate } 29207c478bd9Sstevel@tonic-gate 29217c478bd9Sstevel@tonic-gate 29227c478bd9Sstevel@tonic-gate /* 29237c478bd9Sstevel@tonic-gate * our rep_putw() routine - use tryenter 29247c478bd9Sstevel@tonic-gate */ 29257c478bd9Sstevel@tonic-gate static void 29267c478bd9Sstevel@tonic-gate bofi_rep_wr16(ddi_acc_impl_t *handle, uint16_t *host_addr, 29277c478bd9Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 29287c478bd9Sstevel@tonic-gate { 29297c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 29307c478bd9Sstevel@tonic-gate int i; 29317c478bd9Sstevel@tonic-gate uint64_t llvalue; 29327c478bd9Sstevel@tonic-gate uint16_t *addr; 29337c478bd9Sstevel@tonic-gate 29347c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 29357c478bd9Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint16_t) 29367c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 29377c478bd9Sstevel@tonic-gate hp->save.acc.ahi_rep_put16(&hp->save.acc, host_addr, dev_addr, 29387c478bd9Sstevel@tonic-gate repcount, flags); 29397c478bd9Sstevel@tonic-gate return; 29407c478bd9Sstevel@tonic-gate } 29417c478bd9Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 29427c478bd9Sstevel@tonic-gate llvalue = *(host_addr + i); 29437c478bd9Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 29447c478bd9Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 2, i ? 0 : 29457c478bd9Sstevel@tonic-gate repcount)) 29467c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put16(&hp->save.acc, addr, 29477c478bd9Sstevel@tonic-gate (uint16_t)llvalue); 29487c478bd9Sstevel@tonic-gate } 29497c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 29507c478bd9Sstevel@tonic-gate } 29517c478bd9Sstevel@tonic-gate 29527c478bd9Sstevel@tonic-gate 29537c478bd9Sstevel@tonic-gate /* 29547c478bd9Sstevel@tonic-gate * our rep_putl() routine - use tryenter 29557c478bd9Sstevel@tonic-gate */ 29567c478bd9Sstevel@tonic-gate static void 29577c478bd9Sstevel@tonic-gate bofi_rep_wr32(ddi_acc_impl_t *handle, uint32_t *host_addr, 29587c478bd9Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 29597c478bd9Sstevel@tonic-gate { 29607c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 29617c478bd9Sstevel@tonic-gate int i; 29627c478bd9Sstevel@tonic-gate uint64_t llvalue; 29637c478bd9Sstevel@tonic-gate uint32_t *addr; 29647c478bd9Sstevel@tonic-gate 29657c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 29667c478bd9Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint32_t) 29677c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 29687c478bd9Sstevel@tonic-gate hp->save.acc.ahi_rep_put32(&hp->save.acc, host_addr, dev_addr, 29697c478bd9Sstevel@tonic-gate repcount, flags); 29707c478bd9Sstevel@tonic-gate return; 29717c478bd9Sstevel@tonic-gate } 29727c478bd9Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 29737c478bd9Sstevel@tonic-gate llvalue = *(host_addr + i); 29747c478bd9Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 29757c478bd9Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 4, i ? 0 : 29767c478bd9Sstevel@tonic-gate repcount)) 29777c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put32(&hp->save.acc, addr, 29787c478bd9Sstevel@tonic-gate (uint32_t)llvalue); 29797c478bd9Sstevel@tonic-gate } 29807c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 29817c478bd9Sstevel@tonic-gate } 29827c478bd9Sstevel@tonic-gate 29837c478bd9Sstevel@tonic-gate 29847c478bd9Sstevel@tonic-gate /* 29857c478bd9Sstevel@tonic-gate * our rep_putll() routine - use tryenter 29867c478bd9Sstevel@tonic-gate */ 29877c478bd9Sstevel@tonic-gate static void 29887c478bd9Sstevel@tonic-gate bofi_rep_wr64(ddi_acc_impl_t *handle, uint64_t *host_addr, 29897c478bd9Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 29907c478bd9Sstevel@tonic-gate { 29917c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 29927c478bd9Sstevel@tonic-gate int i; 29937c478bd9Sstevel@tonic-gate uint64_t llvalue; 29947c478bd9Sstevel@tonic-gate uint64_t *addr; 29957c478bd9Sstevel@tonic-gate 29967c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 29977c478bd9Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint64_t) 29987c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 29997c478bd9Sstevel@tonic-gate hp->save.acc.ahi_rep_put64(&hp->save.acc, host_addr, dev_addr, 30007c478bd9Sstevel@tonic-gate repcount, flags); 30017c478bd9Sstevel@tonic-gate return; 30027c478bd9Sstevel@tonic-gate } 30037c478bd9Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 30047c478bd9Sstevel@tonic-gate llvalue = *(host_addr + i); 30057c478bd9Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 30067c478bd9Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 8, i ? 0 : 30077c478bd9Sstevel@tonic-gate repcount)) 30087c478bd9Sstevel@tonic-gate hp->save.acc.ahi_put64(&hp->save.acc, addr, 30097c478bd9Sstevel@tonic-gate (uint64_t)llvalue); 30107c478bd9Sstevel@tonic-gate } 30117c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 30127c478bd9Sstevel@tonic-gate } 30137c478bd9Sstevel@tonic-gate 30147c478bd9Sstevel@tonic-gate 30157c478bd9Sstevel@tonic-gate /* 30167c478bd9Sstevel@tonic-gate * our ddi_map routine 30177c478bd9Sstevel@tonic-gate */ 30187c478bd9Sstevel@tonic-gate static int 30197c478bd9Sstevel@tonic-gate bofi_map(dev_info_t *dip, dev_info_t *rdip, 30207c478bd9Sstevel@tonic-gate ddi_map_req_t *reqp, off_t offset, off_t len, caddr_t *vaddrp) 30217c478bd9Sstevel@tonic-gate { 30227c478bd9Sstevel@tonic-gate ddi_acc_impl_t *ap; 30237c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 30247c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 30257c478bd9Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 30267c478bd9Sstevel@tonic-gate int retval; 30277c478bd9Sstevel@tonic-gate struct bofi_shadow *dhashp; 30287c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 30297c478bd9Sstevel@tonic-gate 30307c478bd9Sstevel@tonic-gate switch (reqp->map_op) { 30317c478bd9Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: 30327c478bd9Sstevel@tonic-gate /* 30337c478bd9Sstevel@tonic-gate * for this case get nexus to do real work first 30347c478bd9Sstevel@tonic-gate */ 30357c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_map(dip, rdip, reqp, offset, len, 30367c478bd9Sstevel@tonic-gate vaddrp); 30377c478bd9Sstevel@tonic-gate if (retval != DDI_SUCCESS) 30387c478bd9Sstevel@tonic-gate return (retval); 30397c478bd9Sstevel@tonic-gate 30407c478bd9Sstevel@tonic-gate ap = (ddi_acc_impl_t *)reqp->map_handlep; 30417c478bd9Sstevel@tonic-gate if (ap == NULL) 30427c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 30437c478bd9Sstevel@tonic-gate /* 30447c478bd9Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 30457c478bd9Sstevel@tonic-gate */ 30467c478bd9Sstevel@tonic-gate if (!driver_under_test(ap->ahi_common.ah_dip)) 30477c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 30487c478bd9Sstevel@tonic-gate 30497c478bd9Sstevel@tonic-gate /* 30507c478bd9Sstevel@tonic-gate * support for ddi_regs_map_setup() 30517c478bd9Sstevel@tonic-gate * - allocate shadow handle structure and fill it in 30527c478bd9Sstevel@tonic-gate */ 30537c478bd9Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), KM_SLEEP); 30547c478bd9Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(ap->ahi_common.ah_dip), 30557c478bd9Sstevel@tonic-gate NAMESIZE); 30567c478bd9Sstevel@tonic-gate hp->instance = ddi_get_instance(ap->ahi_common.ah_dip); 30577c478bd9Sstevel@tonic-gate hp->dip = ap->ahi_common.ah_dip; 30587c478bd9Sstevel@tonic-gate hp->addr = *vaddrp; 30597c478bd9Sstevel@tonic-gate /* 30607c478bd9Sstevel@tonic-gate * return spurious value to catch direct access to registers 30617c478bd9Sstevel@tonic-gate */ 30627c478bd9Sstevel@tonic-gate if (bofi_ddi_check) 30637c478bd9Sstevel@tonic-gate *vaddrp = (caddr_t)64; 30647c478bd9Sstevel@tonic-gate hp->rnumber = ((ddi_acc_hdl_t *)ap)->ah_rnumber; 30657c478bd9Sstevel@tonic-gate hp->offset = offset; 30667c478bd9Sstevel@tonic-gate if (len == 0) 30677c478bd9Sstevel@tonic-gate hp->len = INT_MAX - offset; 30687c478bd9Sstevel@tonic-gate else 30697c478bd9Sstevel@tonic-gate hp->len = min(len, INT_MAX - offset); 30707c478bd9Sstevel@tonic-gate hp->hdl.acc_handle = (ddi_acc_handle_t)ap; 30717c478bd9Sstevel@tonic-gate hp->link = NULL; 30727c478bd9Sstevel@tonic-gate hp->type = BOFI_ACC_HDL; 30737c478bd9Sstevel@tonic-gate /* 30747c478bd9Sstevel@tonic-gate * save existing function pointers and plug in our own 30757c478bd9Sstevel@tonic-gate */ 30767c478bd9Sstevel@tonic-gate hp->save.acc = *ap; 30777c478bd9Sstevel@tonic-gate ap->ahi_get8 = bofi_rd8; 30787c478bd9Sstevel@tonic-gate ap->ahi_get16 = bofi_rd16; 30797c478bd9Sstevel@tonic-gate ap->ahi_get32 = bofi_rd32; 30807c478bd9Sstevel@tonic-gate ap->ahi_get64 = bofi_rd64; 30817c478bd9Sstevel@tonic-gate ap->ahi_put8 = bofi_wr8; 30827c478bd9Sstevel@tonic-gate ap->ahi_put16 = bofi_wr16; 30837c478bd9Sstevel@tonic-gate ap->ahi_put32 = bofi_wr32; 30847c478bd9Sstevel@tonic-gate ap->ahi_put64 = bofi_wr64; 30857c478bd9Sstevel@tonic-gate ap->ahi_rep_get8 = bofi_rep_rd8; 30867c478bd9Sstevel@tonic-gate ap->ahi_rep_get16 = bofi_rep_rd16; 30877c478bd9Sstevel@tonic-gate ap->ahi_rep_get32 = bofi_rep_rd32; 30887c478bd9Sstevel@tonic-gate ap->ahi_rep_get64 = bofi_rep_rd64; 30897c478bd9Sstevel@tonic-gate ap->ahi_rep_put8 = bofi_rep_wr8; 30907c478bd9Sstevel@tonic-gate ap->ahi_rep_put16 = bofi_rep_wr16; 30917c478bd9Sstevel@tonic-gate ap->ahi_rep_put32 = bofi_rep_wr32; 30927c478bd9Sstevel@tonic-gate ap->ahi_rep_put64 = bofi_rep_wr64; 30937c478bd9Sstevel@tonic-gate ap->ahi_fault_check = bofi_check_acc_hdl; 30947c478bd9Sstevel@tonic-gate #if defined(__sparc) 30957c478bd9Sstevel@tonic-gate #else 30967c478bd9Sstevel@tonic-gate ap->ahi_acc_attr &= ~DDI_ACCATTR_DIRECT; 30977c478bd9Sstevel@tonic-gate #endif 30987c478bd9Sstevel@tonic-gate /* 30997c478bd9Sstevel@tonic-gate * stick in a pointer to our shadow handle 31007c478bd9Sstevel@tonic-gate */ 31017c478bd9Sstevel@tonic-gate ap->ahi_common.ah_bus_private = hp; 31027c478bd9Sstevel@tonic-gate /* 31037c478bd9Sstevel@tonic-gate * add to dhash, hhash and inuse lists 31047c478bd9Sstevel@tonic-gate */ 31057c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 31067c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 31077c478bd9Sstevel@tonic-gate hp->next = shadow_list.next; 31087c478bd9Sstevel@tonic-gate shadow_list.next->prev = hp; 31097c478bd9Sstevel@tonic-gate hp->prev = &shadow_list; 31107c478bd9Sstevel@tonic-gate shadow_list.next = hp; 31117c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(ap); 31127c478bd9Sstevel@tonic-gate hp->hnext = hhashp->hnext; 31137c478bd9Sstevel@tonic-gate hhashp->hnext->hprev = hp; 31147c478bd9Sstevel@tonic-gate hp->hprev = hhashp; 31157c478bd9Sstevel@tonic-gate hhashp->hnext = hp; 31167c478bd9Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 31177c478bd9Sstevel@tonic-gate hp->dnext = dhashp->dnext; 31187c478bd9Sstevel@tonic-gate dhashp->dnext->dprev = hp; 31197c478bd9Sstevel@tonic-gate hp->dprev = dhashp; 31207c478bd9Sstevel@tonic-gate dhashp->dnext = hp; 31217c478bd9Sstevel@tonic-gate /* 31227c478bd9Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 31237c478bd9Sstevel@tonic-gate * acc_handle 31247c478bd9Sstevel@tonic-gate */ 31257c478bd9Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 31267c478bd9Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 31277c478bd9Sstevel@tonic-gate ddi_name_to_major(ep->name) && 31287c478bd9Sstevel@tonic-gate hp->instance == ep->errdef.instance && 31297c478bd9Sstevel@tonic-gate (ep->errdef.access_type & BOFI_PIO_RW) && 31307c478bd9Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 31317c478bd9Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 31327c478bd9Sstevel@tonic-gate (ep->errdef.len == 0 || 31337c478bd9Sstevel@tonic-gate offset < ep->errdef.offset + ep->errdef.len) && 31347c478bd9Sstevel@tonic-gate offset + hp->len > ep->errdef.offset) { 31357c478bd9Sstevel@tonic-gate lp = bofi_link_freelist; 31367c478bd9Sstevel@tonic-gate if (lp != NULL) { 31377c478bd9Sstevel@tonic-gate bofi_link_freelist = lp->link; 31387c478bd9Sstevel@tonic-gate lp->errentp = ep; 31397c478bd9Sstevel@tonic-gate lp->link = hp->link; 31407c478bd9Sstevel@tonic-gate hp->link = lp; 31417c478bd9Sstevel@tonic-gate } 31427c478bd9Sstevel@tonic-gate } 31437c478bd9Sstevel@tonic-gate } 31447c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 31457c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 31467c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 31477c478bd9Sstevel@tonic-gate case DDI_MO_UNMAP: 31487c478bd9Sstevel@tonic-gate 31497c478bd9Sstevel@tonic-gate ap = (ddi_acc_impl_t *)reqp->map_handlep; 31507c478bd9Sstevel@tonic-gate if (ap == NULL) 31517c478bd9Sstevel@tonic-gate break; 31527c478bd9Sstevel@tonic-gate /* 31537c478bd9Sstevel@tonic-gate * support for ddi_regs_map_free() 31547c478bd9Sstevel@tonic-gate * - check we really have a shadow handle for this one 31557c478bd9Sstevel@tonic-gate */ 31567c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 31577c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 31587c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(ap); 31597c478bd9Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 31607c478bd9Sstevel@tonic-gate if (hp->hdl.acc_handle == (ddi_acc_handle_t)ap) 31617c478bd9Sstevel@tonic-gate break; 31627c478bd9Sstevel@tonic-gate if (hp == hhashp) { 31637c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 31647c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 31657c478bd9Sstevel@tonic-gate break; 31667c478bd9Sstevel@tonic-gate } 31677c478bd9Sstevel@tonic-gate /* 31687c478bd9Sstevel@tonic-gate * got a shadow handle - restore original pointers 31697c478bd9Sstevel@tonic-gate */ 31707c478bd9Sstevel@tonic-gate *ap = hp->save.acc; 31717c478bd9Sstevel@tonic-gate *vaddrp = hp->addr; 31727c478bd9Sstevel@tonic-gate /* 31737c478bd9Sstevel@tonic-gate * remove from dhash, hhash and inuse lists 31747c478bd9Sstevel@tonic-gate */ 31757c478bd9Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 31767c478bd9Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 31777c478bd9Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 31787c478bd9Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 31797c478bd9Sstevel@tonic-gate hp->next->prev = hp->prev; 31807c478bd9Sstevel@tonic-gate hp->prev->next = hp->next; 31817c478bd9Sstevel@tonic-gate /* 31827c478bd9Sstevel@tonic-gate * free any errdef link structures tagged onto the shadow handle 31837c478bd9Sstevel@tonic-gate */ 31847c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 31857c478bd9Sstevel@tonic-gate next_lp = lp->link; 31867c478bd9Sstevel@tonic-gate lp->link = bofi_link_freelist; 31877c478bd9Sstevel@tonic-gate bofi_link_freelist = lp; 31887c478bd9Sstevel@tonic-gate lp = next_lp; 31897c478bd9Sstevel@tonic-gate } 31907c478bd9Sstevel@tonic-gate hp->link = NULL; 31917c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 31927c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 31937c478bd9Sstevel@tonic-gate /* 31947c478bd9Sstevel@tonic-gate * finally delete shadow handle 31957c478bd9Sstevel@tonic-gate */ 31967c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 31977c478bd9Sstevel@tonic-gate break; 31987c478bd9Sstevel@tonic-gate default: 31997c478bd9Sstevel@tonic-gate break; 32007c478bd9Sstevel@tonic-gate } 32017c478bd9Sstevel@tonic-gate return (save_bus_ops.bus_map(dip, rdip, reqp, offset, len, vaddrp)); 32027c478bd9Sstevel@tonic-gate } 32037c478bd9Sstevel@tonic-gate 32047c478bd9Sstevel@tonic-gate 32057c478bd9Sstevel@tonic-gate /* 32067c478bd9Sstevel@tonic-gate * chain any pre-existing errdefs on to newly created dma handle 32077c478bd9Sstevel@tonic-gate * if required call do_dma_corrupt() to corrupt data 32087c478bd9Sstevel@tonic-gate */ 32097c478bd9Sstevel@tonic-gate static void 32107c478bd9Sstevel@tonic-gate chain_on_errdefs(struct bofi_shadow *hp) 32117c478bd9Sstevel@tonic-gate { 32127c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 32137c478bd9Sstevel@tonic-gate struct bofi_link *lp; 32147c478bd9Sstevel@tonic-gate 32157c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 32167c478bd9Sstevel@tonic-gate /* 32177c478bd9Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this dma_handle 32187c478bd9Sstevel@tonic-gate */ 32197c478bd9Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 32207c478bd9Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 32217c478bd9Sstevel@tonic-gate ddi_name_to_major(ep->name) && 32227c478bd9Sstevel@tonic-gate hp->instance == ep->errdef.instance && 32237c478bd9Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 32247c478bd9Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 32257c478bd9Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_RW) && 32267c478bd9Sstevel@tonic-gate (((uintptr_t)(hp->addr + ep->errdef.offset + 32277c478bd9Sstevel@tonic-gate ep->errdef.len) & ~LLSZMASK) > 32287c478bd9Sstevel@tonic-gate ((uintptr_t)((hp->addr + ep->errdef.offset) + 32297c478bd9Sstevel@tonic-gate LLSZMASK) & ~LLSZMASK)))) { 32307c478bd9Sstevel@tonic-gate /* 32317c478bd9Sstevel@tonic-gate * got a match - link it on 32327c478bd9Sstevel@tonic-gate */ 32337c478bd9Sstevel@tonic-gate lp = bofi_link_freelist; 32347c478bd9Sstevel@tonic-gate if (lp != NULL) { 32357c478bd9Sstevel@tonic-gate bofi_link_freelist = lp->link; 32367c478bd9Sstevel@tonic-gate lp->errentp = ep; 32377c478bd9Sstevel@tonic-gate lp->link = hp->link; 32387c478bd9Sstevel@tonic-gate hp->link = lp; 32397c478bd9Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_W) && 32407c478bd9Sstevel@tonic-gate (hp->flags & DDI_DMA_WRITE) && 32417c478bd9Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 32427c478bd9Sstevel@tonic-gate do_dma_corrupt(hp, ep, 32437c478bd9Sstevel@tonic-gate DDI_DMA_SYNC_FORDEV, 32447c478bd9Sstevel@tonic-gate 0, hp->len); 32457c478bd9Sstevel@tonic-gate } 32467c478bd9Sstevel@tonic-gate } 32477c478bd9Sstevel@tonic-gate } 32487c478bd9Sstevel@tonic-gate } 32497c478bd9Sstevel@tonic-gate } 32507c478bd9Sstevel@tonic-gate 32517c478bd9Sstevel@tonic-gate 32527c478bd9Sstevel@tonic-gate /* 32537c478bd9Sstevel@tonic-gate * need to do copy byte-by-byte in case one of pages is little-endian 32547c478bd9Sstevel@tonic-gate */ 32557c478bd9Sstevel@tonic-gate static void 32567c478bd9Sstevel@tonic-gate xbcopy(void *from, void *to, u_longlong_t len) 32577c478bd9Sstevel@tonic-gate { 32587c478bd9Sstevel@tonic-gate uchar_t *f = from; 32597c478bd9Sstevel@tonic-gate uchar_t *t = to; 32607c478bd9Sstevel@tonic-gate 32617c478bd9Sstevel@tonic-gate while (len--) 32627c478bd9Sstevel@tonic-gate *t++ = *f++; 32637c478bd9Sstevel@tonic-gate } 32647c478bd9Sstevel@tonic-gate 32657c478bd9Sstevel@tonic-gate 32667c478bd9Sstevel@tonic-gate /* 32677c478bd9Sstevel@tonic-gate * our ddi_dma_map routine 32687c478bd9Sstevel@tonic-gate */ 32697c478bd9Sstevel@tonic-gate static int 32707c478bd9Sstevel@tonic-gate bofi_dma_map(dev_info_t *dip, dev_info_t *rdip, 32717c478bd9Sstevel@tonic-gate struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep) 32727c478bd9Sstevel@tonic-gate { 32737c478bd9Sstevel@tonic-gate struct bofi_shadow *hp, *xhp; 32747c478bd9Sstevel@tonic-gate int maxrnumber = 0; 32757c478bd9Sstevel@tonic-gate int retval = DDI_DMA_NORESOURCES; 32767c478bd9Sstevel@tonic-gate auto struct ddi_dma_req dmareq; 32777c478bd9Sstevel@tonic-gate int sleep; 32787c478bd9Sstevel@tonic-gate struct bofi_shadow *dhashp; 32797c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 32807c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp; 32817c478bd9Sstevel@tonic-gate unsigned long pagemask = ddi_ptob(rdip, 1) - 1; 32827c478bd9Sstevel@tonic-gate 32837c478bd9Sstevel@tonic-gate /* 32847c478bd9Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 32857c478bd9Sstevel@tonic-gate */ 32867c478bd9Sstevel@tonic-gate if (handlep == NULL || !driver_under_test(rdip)) 32877c478bd9Sstevel@tonic-gate return (save_bus_ops.bus_dma_map(dip, rdip, dmareqp, handlep)); 32887c478bd9Sstevel@tonic-gate 32897c478bd9Sstevel@tonic-gate sleep = (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 32907c478bd9Sstevel@tonic-gate /* 32917c478bd9Sstevel@tonic-gate * allocate shadow handle structure and fill it in 32927c478bd9Sstevel@tonic-gate */ 32937c478bd9Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), sleep); 32947c478bd9Sstevel@tonic-gate if (hp == NULL) 32957c478bd9Sstevel@tonic-gate goto error; 32967c478bd9Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 32977c478bd9Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 32987c478bd9Sstevel@tonic-gate hp->dip = rdip; 32997c478bd9Sstevel@tonic-gate hp->flags = dmareqp->dmar_flags; 33007c478bd9Sstevel@tonic-gate hp->link = NULL; 33017c478bd9Sstevel@tonic-gate hp->type = BOFI_DMA_HDL; 33027c478bd9Sstevel@tonic-gate /* 33037c478bd9Sstevel@tonic-gate * get a kernel virtual mapping 33047c478bd9Sstevel@tonic-gate */ 33057c478bd9Sstevel@tonic-gate hp->addr = ddi_dmareq_mapin(dmareqp, &hp->mapaddr, &hp->len); 33067c478bd9Sstevel@tonic-gate if (hp->addr == NULL) 33077c478bd9Sstevel@tonic-gate goto error; 33087c478bd9Sstevel@tonic-gate if (bofi_sync_check) { 33097c478bd9Sstevel@tonic-gate /* 33107c478bd9Sstevel@tonic-gate * Take a copy and pass pointers to this up to nexus instead. 33117c478bd9Sstevel@tonic-gate * Data will be copied from the original on explicit 33127c478bd9Sstevel@tonic-gate * and implicit ddi_dma_sync() 33137c478bd9Sstevel@tonic-gate * 33147c478bd9Sstevel@tonic-gate * - maintain page alignment because some devices assume it. 33157c478bd9Sstevel@tonic-gate */ 33167c478bd9Sstevel@tonic-gate hp->origaddr = hp->addr; 33177c478bd9Sstevel@tonic-gate hp->allocaddr = ddi_umem_alloc( 33187c478bd9Sstevel@tonic-gate ((uintptr_t)hp->addr & pagemask) + hp->len, sleep, 33197c478bd9Sstevel@tonic-gate &hp->umem_cookie); 33207c478bd9Sstevel@tonic-gate if (hp->allocaddr == NULL) 33217c478bd9Sstevel@tonic-gate goto error; 33227c478bd9Sstevel@tonic-gate hp->addr = hp->allocaddr + ((uintptr_t)hp->addr & pagemask); 33237c478bd9Sstevel@tonic-gate if (dmareqp->dmar_flags & DDI_DMA_WRITE) 33247c478bd9Sstevel@tonic-gate xbcopy(hp->origaddr, hp->addr, hp->len); 33257c478bd9Sstevel@tonic-gate dmareq = *dmareqp; 33267c478bd9Sstevel@tonic-gate dmareq.dmar_object.dmao_size = hp->len; 33277c478bd9Sstevel@tonic-gate dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR; 33287c478bd9Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_as = &kas; 33297c478bd9Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_addr = hp->addr; 33307c478bd9Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL; 33317c478bd9Sstevel@tonic-gate dmareqp = &dmareq; 33327c478bd9Sstevel@tonic-gate } 33337c478bd9Sstevel@tonic-gate /* 33347c478bd9Sstevel@tonic-gate * call nexus to do the real work 33357c478bd9Sstevel@tonic-gate */ 33367c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_dma_map(dip, rdip, dmareqp, handlep); 33377c478bd9Sstevel@tonic-gate if (retval != DDI_SUCCESS) 33387c478bd9Sstevel@tonic-gate goto error2; 33397c478bd9Sstevel@tonic-gate /* 33407c478bd9Sstevel@tonic-gate * now set dma_handle to point to real handle 33417c478bd9Sstevel@tonic-gate */ 33427c478bd9Sstevel@tonic-gate hp->hdl.dma_handle = *handlep; 33437c478bd9Sstevel@tonic-gate /* 33447c478bd9Sstevel@tonic-gate * unset DMP_NOSYNC 33457c478bd9Sstevel@tonic-gate */ 33467c478bd9Sstevel@tonic-gate mp = (ddi_dma_impl_t *)*handlep; 33477c478bd9Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 33487c478bd9Sstevel@tonic-gate mp->dmai_fault_check = bofi_check_dma_hdl; 33497c478bd9Sstevel@tonic-gate /* 33507c478bd9Sstevel@tonic-gate * bind and unbind are cached in devinfo - must overwrite them 33517c478bd9Sstevel@tonic-gate * - note that our bind and unbind are quite happy dealing with 33527c478bd9Sstevel@tonic-gate * any handles for this devinfo that were previously allocated 33537c478bd9Sstevel@tonic-gate */ 33547c478bd9Sstevel@tonic-gate if (save_bus_ops.bus_dma_bindhdl == DEVI(rdip)->devi_bus_dma_bindfunc) 33557c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_bindfunc = bofi_dma_bindhdl; 33567c478bd9Sstevel@tonic-gate if (save_bus_ops.bus_dma_unbindhdl == 33577c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc) 33587c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc = bofi_dma_unbindhdl; 33597c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 33607c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 33617c478bd9Sstevel@tonic-gate /* 33627c478bd9Sstevel@tonic-gate * get an "rnumber" for this handle - really just seeking to 33637c478bd9Sstevel@tonic-gate * get a unique number - generally only care for early allocated 33647c478bd9Sstevel@tonic-gate * handles - so we get as far as INT_MAX, just stay there 33657c478bd9Sstevel@tonic-gate */ 33667c478bd9Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 33677c478bd9Sstevel@tonic-gate for (xhp = dhashp->dnext; xhp != dhashp; xhp = xhp->dnext) 33687c478bd9Sstevel@tonic-gate if (ddi_name_to_major(xhp->name) == 33697c478bd9Sstevel@tonic-gate ddi_name_to_major(hp->name) && 33707c478bd9Sstevel@tonic-gate xhp->instance == hp->instance && 33717c478bd9Sstevel@tonic-gate xhp->type == BOFI_DMA_HDL) 33727c478bd9Sstevel@tonic-gate if (xhp->rnumber >= maxrnumber) { 33737c478bd9Sstevel@tonic-gate if (xhp->rnumber == INT_MAX) 33747c478bd9Sstevel@tonic-gate maxrnumber = INT_MAX; 33757c478bd9Sstevel@tonic-gate else 33767c478bd9Sstevel@tonic-gate maxrnumber = xhp->rnumber + 1; 33777c478bd9Sstevel@tonic-gate } 33787c478bd9Sstevel@tonic-gate hp->rnumber = maxrnumber; 33797c478bd9Sstevel@tonic-gate /* 33807c478bd9Sstevel@tonic-gate * add to dhash, hhash and inuse lists 33817c478bd9Sstevel@tonic-gate */ 33827c478bd9Sstevel@tonic-gate hp->next = shadow_list.next; 33837c478bd9Sstevel@tonic-gate shadow_list.next->prev = hp; 33847c478bd9Sstevel@tonic-gate hp->prev = &shadow_list; 33857c478bd9Sstevel@tonic-gate shadow_list.next = hp; 33867c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(*handlep); 33877c478bd9Sstevel@tonic-gate hp->hnext = hhashp->hnext; 33887c478bd9Sstevel@tonic-gate hhashp->hnext->hprev = hp; 33897c478bd9Sstevel@tonic-gate hp->hprev = hhashp; 33907c478bd9Sstevel@tonic-gate hhashp->hnext = hp; 33917c478bd9Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 33927c478bd9Sstevel@tonic-gate hp->dnext = dhashp->dnext; 33937c478bd9Sstevel@tonic-gate dhashp->dnext->dprev = hp; 33947c478bd9Sstevel@tonic-gate hp->dprev = dhashp; 33957c478bd9Sstevel@tonic-gate dhashp->dnext = hp; 33967c478bd9Sstevel@tonic-gate /* 33977c478bd9Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 33987c478bd9Sstevel@tonic-gate * acc_handle and corrupt if required (as there is an implicit 33997c478bd9Sstevel@tonic-gate * ddi_dma_sync() in this call) 34007c478bd9Sstevel@tonic-gate */ 34017c478bd9Sstevel@tonic-gate chain_on_errdefs(hp); 34027c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 34037c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 34047c478bd9Sstevel@tonic-gate return (retval); 34057c478bd9Sstevel@tonic-gate error: 34067c478bd9Sstevel@tonic-gate if (dmareqp->dmar_fp != DDI_DMA_DONTWAIT) { 34077c478bd9Sstevel@tonic-gate /* 34087c478bd9Sstevel@tonic-gate * what to do here? Wait a bit and try again 34097c478bd9Sstevel@tonic-gate */ 34107c478bd9Sstevel@tonic-gate (void) timeout((void (*)())dmareqp->dmar_fp, 34117c478bd9Sstevel@tonic-gate dmareqp->dmar_arg, 10); 34127c478bd9Sstevel@tonic-gate } 34137c478bd9Sstevel@tonic-gate error2: 34147c478bd9Sstevel@tonic-gate if (hp) { 34157c478bd9Sstevel@tonic-gate ddi_dmareq_mapout(hp->mapaddr, hp->len); 34167c478bd9Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 34177c478bd9Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 34187c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 34197c478bd9Sstevel@tonic-gate } 34207c478bd9Sstevel@tonic-gate return (retval); 34217c478bd9Sstevel@tonic-gate } 34227c478bd9Sstevel@tonic-gate 34237c478bd9Sstevel@tonic-gate 34247c478bd9Sstevel@tonic-gate /* 34257c478bd9Sstevel@tonic-gate * our ddi_dma_allochdl routine 34267c478bd9Sstevel@tonic-gate */ 34277c478bd9Sstevel@tonic-gate static int 34287c478bd9Sstevel@tonic-gate bofi_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp, 34297c478bd9Sstevel@tonic-gate int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 34307c478bd9Sstevel@tonic-gate { 34317c478bd9Sstevel@tonic-gate int retval = DDI_DMA_NORESOURCES; 34327c478bd9Sstevel@tonic-gate struct bofi_shadow *hp, *xhp; 34337c478bd9Sstevel@tonic-gate int maxrnumber = 0; 34347c478bd9Sstevel@tonic-gate struct bofi_shadow *dhashp; 34357c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 34367c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp; 34377c478bd9Sstevel@tonic-gate 34387c478bd9Sstevel@tonic-gate /* 34397c478bd9Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 34407c478bd9Sstevel@tonic-gate */ 34417c478bd9Sstevel@tonic-gate if (!driver_under_test(rdip)) 34427c478bd9Sstevel@tonic-gate return (save_bus_ops.bus_dma_allochdl(dip, rdip, attrp, 34437c478bd9Sstevel@tonic-gate waitfp, arg, handlep)); 34447c478bd9Sstevel@tonic-gate 34457c478bd9Sstevel@tonic-gate /* 34467c478bd9Sstevel@tonic-gate * allocate shadow handle structure and fill it in 34477c478bd9Sstevel@tonic-gate */ 34487c478bd9Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), 34497c478bd9Sstevel@tonic-gate ((waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP)); 34507c478bd9Sstevel@tonic-gate if (hp == NULL) { 34517c478bd9Sstevel@tonic-gate /* 34527c478bd9Sstevel@tonic-gate * what to do here? Wait a bit and try again 34537c478bd9Sstevel@tonic-gate */ 34547c478bd9Sstevel@tonic-gate if (waitfp != DDI_DMA_DONTWAIT) 34557c478bd9Sstevel@tonic-gate (void) timeout((void (*)())waitfp, arg, 10); 34567c478bd9Sstevel@tonic-gate return (retval); 34577c478bd9Sstevel@tonic-gate } 34587c478bd9Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 34597c478bd9Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 34607c478bd9Sstevel@tonic-gate hp->dip = rdip; 34617c478bd9Sstevel@tonic-gate hp->link = NULL; 34627c478bd9Sstevel@tonic-gate hp->type = BOFI_NULL; 34637c478bd9Sstevel@tonic-gate /* 34647c478bd9Sstevel@tonic-gate * call nexus to do the real work 34657c478bd9Sstevel@tonic-gate */ 34667c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_dma_allochdl(dip, rdip, attrp, waitfp, arg, 34677c478bd9Sstevel@tonic-gate handlep); 34687c478bd9Sstevel@tonic-gate if (retval != DDI_SUCCESS) { 34697c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 34707c478bd9Sstevel@tonic-gate return (retval); 34717c478bd9Sstevel@tonic-gate } 34727c478bd9Sstevel@tonic-gate /* 34737c478bd9Sstevel@tonic-gate * now point set dma_handle to point to real handle 34747c478bd9Sstevel@tonic-gate */ 34757c478bd9Sstevel@tonic-gate hp->hdl.dma_handle = *handlep; 34767c478bd9Sstevel@tonic-gate mp = (ddi_dma_impl_t *)*handlep; 34777c478bd9Sstevel@tonic-gate mp->dmai_fault_check = bofi_check_dma_hdl; 34787c478bd9Sstevel@tonic-gate /* 34797c478bd9Sstevel@tonic-gate * bind and unbind are cached in devinfo - must overwrite them 34807c478bd9Sstevel@tonic-gate * - note that our bind and unbind are quite happy dealing with 34817c478bd9Sstevel@tonic-gate * any handles for this devinfo that were previously allocated 34827c478bd9Sstevel@tonic-gate */ 34837c478bd9Sstevel@tonic-gate if (save_bus_ops.bus_dma_bindhdl == DEVI(rdip)->devi_bus_dma_bindfunc) 34847c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_bindfunc = bofi_dma_bindhdl; 34857c478bd9Sstevel@tonic-gate if (save_bus_ops.bus_dma_unbindhdl == 34867c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc) 34877c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc = bofi_dma_unbindhdl; 34887c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 34897c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 34907c478bd9Sstevel@tonic-gate /* 34917c478bd9Sstevel@tonic-gate * get an "rnumber" for this handle - really just seeking to 34927c478bd9Sstevel@tonic-gate * get a unique number - generally only care for early allocated 34937c478bd9Sstevel@tonic-gate * handles - so we get as far as INT_MAX, just stay there 34947c478bd9Sstevel@tonic-gate */ 34957c478bd9Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 34967c478bd9Sstevel@tonic-gate for (xhp = dhashp->dnext; xhp != dhashp; xhp = xhp->dnext) 34977c478bd9Sstevel@tonic-gate if (ddi_name_to_major(xhp->name) == 34987c478bd9Sstevel@tonic-gate ddi_name_to_major(hp->name) && 34997c478bd9Sstevel@tonic-gate xhp->instance == hp->instance && 35007c478bd9Sstevel@tonic-gate (xhp->type == BOFI_DMA_HDL || 35017c478bd9Sstevel@tonic-gate xhp->type == BOFI_NULL)) 35027c478bd9Sstevel@tonic-gate if (xhp->rnumber >= maxrnumber) { 35037c478bd9Sstevel@tonic-gate if (xhp->rnumber == INT_MAX) 35047c478bd9Sstevel@tonic-gate maxrnumber = INT_MAX; 35057c478bd9Sstevel@tonic-gate else 35067c478bd9Sstevel@tonic-gate maxrnumber = xhp->rnumber + 1; 35077c478bd9Sstevel@tonic-gate } 35087c478bd9Sstevel@tonic-gate hp->rnumber = maxrnumber; 35097c478bd9Sstevel@tonic-gate /* 35107c478bd9Sstevel@tonic-gate * add to dhash, hhash and inuse lists 35117c478bd9Sstevel@tonic-gate */ 35127c478bd9Sstevel@tonic-gate hp->next = shadow_list.next; 35137c478bd9Sstevel@tonic-gate shadow_list.next->prev = hp; 35147c478bd9Sstevel@tonic-gate hp->prev = &shadow_list; 35157c478bd9Sstevel@tonic-gate shadow_list.next = hp; 35167c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(*handlep); 35177c478bd9Sstevel@tonic-gate hp->hnext = hhashp->hnext; 35187c478bd9Sstevel@tonic-gate hhashp->hnext->hprev = hp; 35197c478bd9Sstevel@tonic-gate hp->hprev = hhashp; 35207c478bd9Sstevel@tonic-gate hhashp->hnext = hp; 35217c478bd9Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 35227c478bd9Sstevel@tonic-gate hp->dnext = dhashp->dnext; 35237c478bd9Sstevel@tonic-gate dhashp->dnext->dprev = hp; 35247c478bd9Sstevel@tonic-gate hp->dprev = dhashp; 35257c478bd9Sstevel@tonic-gate dhashp->dnext = hp; 35267c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 35277c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 35287c478bd9Sstevel@tonic-gate return (retval); 35297c478bd9Sstevel@tonic-gate } 35307c478bd9Sstevel@tonic-gate 35317c478bd9Sstevel@tonic-gate 35327c478bd9Sstevel@tonic-gate /* 35337c478bd9Sstevel@tonic-gate * our ddi_dma_freehdl routine 35347c478bd9Sstevel@tonic-gate */ 35357c478bd9Sstevel@tonic-gate static int 35367c478bd9Sstevel@tonic-gate bofi_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 35377c478bd9Sstevel@tonic-gate { 35387c478bd9Sstevel@tonic-gate int retval; 35397c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 35407c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 35417c478bd9Sstevel@tonic-gate 35427c478bd9Sstevel@tonic-gate /* 35437c478bd9Sstevel@tonic-gate * find shadow for this handle 35447c478bd9Sstevel@tonic-gate */ 35457c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 35467c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 35477c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 35487c478bd9Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 35497c478bd9Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 35507c478bd9Sstevel@tonic-gate break; 35517c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 35527c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 35537c478bd9Sstevel@tonic-gate /* 35547c478bd9Sstevel@tonic-gate * call nexus to do the real work 35557c478bd9Sstevel@tonic-gate */ 35567c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_dma_freehdl(dip, rdip, handle); 35577c478bd9Sstevel@tonic-gate if (retval != DDI_SUCCESS) { 35587c478bd9Sstevel@tonic-gate return (retval); 35597c478bd9Sstevel@tonic-gate } 35607c478bd9Sstevel@tonic-gate /* 35617c478bd9Sstevel@tonic-gate * did we really have a shadow for this handle 35627c478bd9Sstevel@tonic-gate */ 35637c478bd9Sstevel@tonic-gate if (hp == hhashp) 35647c478bd9Sstevel@tonic-gate return (retval); 35657c478bd9Sstevel@tonic-gate /* 35667c478bd9Sstevel@tonic-gate * yes we have - see if it's still bound 35677c478bd9Sstevel@tonic-gate */ 35687c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 35697c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 35707c478bd9Sstevel@tonic-gate if (hp->type != BOFI_NULL) 35717c478bd9Sstevel@tonic-gate panic("driver freeing bound dma_handle"); 35727c478bd9Sstevel@tonic-gate /* 35737c478bd9Sstevel@tonic-gate * remove from dhash, hhash and inuse lists 35747c478bd9Sstevel@tonic-gate */ 35757c478bd9Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 35767c478bd9Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 35777c478bd9Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 35787c478bd9Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 35797c478bd9Sstevel@tonic-gate hp->next->prev = hp->prev; 35807c478bd9Sstevel@tonic-gate hp->prev->next = hp->next; 35817c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 35827c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 35837c478bd9Sstevel@tonic-gate 35847c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 35857c478bd9Sstevel@tonic-gate return (retval); 35867c478bd9Sstevel@tonic-gate } 35877c478bd9Sstevel@tonic-gate 35887c478bd9Sstevel@tonic-gate 35897c478bd9Sstevel@tonic-gate /* 35907c478bd9Sstevel@tonic-gate * our ddi_dma_bindhdl routine 35917c478bd9Sstevel@tonic-gate */ 35927c478bd9Sstevel@tonic-gate static int 35937c478bd9Sstevel@tonic-gate bofi_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 35947c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, struct ddi_dma_req *dmareqp, 35957c478bd9Sstevel@tonic-gate ddi_dma_cookie_t *cookiep, uint_t *ccountp) 35967c478bd9Sstevel@tonic-gate { 35977c478bd9Sstevel@tonic-gate int retval = DDI_DMA_NORESOURCES; 35987c478bd9Sstevel@tonic-gate auto struct ddi_dma_req dmareq; 35997c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 36007c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 36017c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp; 36027c478bd9Sstevel@tonic-gate unsigned long pagemask = ddi_ptob(rdip, 1) - 1; 36037c478bd9Sstevel@tonic-gate 36047c478bd9Sstevel@tonic-gate /* 36057c478bd9Sstevel@tonic-gate * check we really have a shadow for this handle 36067c478bd9Sstevel@tonic-gate */ 36077c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 36087c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 36097c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 36107c478bd9Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 36117c478bd9Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 36127c478bd9Sstevel@tonic-gate break; 36137c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 36147c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 36157c478bd9Sstevel@tonic-gate if (hp == hhashp) { 36167c478bd9Sstevel@tonic-gate /* 36177c478bd9Sstevel@tonic-gate * no we don't - just call nexus to do the real work 36187c478bd9Sstevel@tonic-gate */ 36197c478bd9Sstevel@tonic-gate return save_bus_ops.bus_dma_bindhdl(dip, rdip, handle, dmareqp, 36207c478bd9Sstevel@tonic-gate cookiep, ccountp); 36217c478bd9Sstevel@tonic-gate } 36227c478bd9Sstevel@tonic-gate /* 36237c478bd9Sstevel@tonic-gate * yes we have - see if it's already bound 36247c478bd9Sstevel@tonic-gate */ 36257c478bd9Sstevel@tonic-gate if (hp->type != BOFI_NULL) 36267c478bd9Sstevel@tonic-gate return (DDI_DMA_INUSE); 36277c478bd9Sstevel@tonic-gate 36287c478bd9Sstevel@tonic-gate hp->flags = dmareqp->dmar_flags; 36297c478bd9Sstevel@tonic-gate /* 36307c478bd9Sstevel@tonic-gate * get a kernel virtual mapping 36317c478bd9Sstevel@tonic-gate */ 36327c478bd9Sstevel@tonic-gate hp->addr = ddi_dmareq_mapin(dmareqp, &hp->mapaddr, &hp->len); 36337c478bd9Sstevel@tonic-gate if (hp->addr == NULL) 36347c478bd9Sstevel@tonic-gate goto error; 36357c478bd9Sstevel@tonic-gate if (bofi_sync_check) { 36367c478bd9Sstevel@tonic-gate /* 36377c478bd9Sstevel@tonic-gate * Take a copy and pass pointers to this up to nexus instead. 36387c478bd9Sstevel@tonic-gate * Data will be copied from the original on explicit 36397c478bd9Sstevel@tonic-gate * and implicit ddi_dma_sync() 36407c478bd9Sstevel@tonic-gate * 36417c478bd9Sstevel@tonic-gate * - maintain page alignment because some devices assume it. 36427c478bd9Sstevel@tonic-gate */ 36437c478bd9Sstevel@tonic-gate hp->origaddr = hp->addr; 36447c478bd9Sstevel@tonic-gate hp->allocaddr = ddi_umem_alloc( 36457c478bd9Sstevel@tonic-gate ((uintptr_t)hp->addr & pagemask) + hp->len, 36467c478bd9Sstevel@tonic-gate (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP, 36477c478bd9Sstevel@tonic-gate &hp->umem_cookie); 36487c478bd9Sstevel@tonic-gate if (hp->allocaddr == NULL) 36497c478bd9Sstevel@tonic-gate goto error; 36507c478bd9Sstevel@tonic-gate hp->addr = hp->allocaddr + ((uintptr_t)hp->addr & pagemask); 36517c478bd9Sstevel@tonic-gate if (dmareqp->dmar_flags & DDI_DMA_WRITE) 36527c478bd9Sstevel@tonic-gate xbcopy(hp->origaddr, hp->addr, hp->len); 36537c478bd9Sstevel@tonic-gate dmareq = *dmareqp; 36547c478bd9Sstevel@tonic-gate dmareq.dmar_object.dmao_size = hp->len; 36557c478bd9Sstevel@tonic-gate dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR; 36567c478bd9Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_as = &kas; 36577c478bd9Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_addr = hp->addr; 36587c478bd9Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL; 36597c478bd9Sstevel@tonic-gate dmareqp = &dmareq; 36607c478bd9Sstevel@tonic-gate } 36617c478bd9Sstevel@tonic-gate /* 36627c478bd9Sstevel@tonic-gate * call nexus to do the real work 36637c478bd9Sstevel@tonic-gate */ 36647c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_dma_bindhdl(dip, rdip, handle, dmareqp, 36657c478bd9Sstevel@tonic-gate cookiep, ccountp); 36667c478bd9Sstevel@tonic-gate if (retval != DDI_SUCCESS) 36677c478bd9Sstevel@tonic-gate goto error2; 36687c478bd9Sstevel@tonic-gate /* 36697c478bd9Sstevel@tonic-gate * unset DMP_NOSYNC 36707c478bd9Sstevel@tonic-gate */ 36717c478bd9Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 36727c478bd9Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 36737c478bd9Sstevel@tonic-gate /* 36747c478bd9Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 36757c478bd9Sstevel@tonic-gate * acc_handle and corrupt if required (as there is an implicit 36767c478bd9Sstevel@tonic-gate * ddi_dma_sync() in this call) 36777c478bd9Sstevel@tonic-gate */ 36787c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 36797c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 36807c478bd9Sstevel@tonic-gate hp->type = BOFI_DMA_HDL; 36817c478bd9Sstevel@tonic-gate chain_on_errdefs(hp); 36827c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 36837c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 36847c478bd9Sstevel@tonic-gate return (retval); 36857c478bd9Sstevel@tonic-gate 36867c478bd9Sstevel@tonic-gate error: 36877c478bd9Sstevel@tonic-gate if (dmareqp->dmar_fp != DDI_DMA_DONTWAIT) { 36887c478bd9Sstevel@tonic-gate /* 36897c478bd9Sstevel@tonic-gate * what to do here? Wait a bit and try again 36907c478bd9Sstevel@tonic-gate */ 36917c478bd9Sstevel@tonic-gate (void) timeout((void (*)())dmareqp->dmar_fp, 36927c478bd9Sstevel@tonic-gate dmareqp->dmar_arg, 10); 36937c478bd9Sstevel@tonic-gate } 36947c478bd9Sstevel@tonic-gate error2: 36957c478bd9Sstevel@tonic-gate if (hp) { 36967c478bd9Sstevel@tonic-gate ddi_dmareq_mapout(hp->mapaddr, hp->len); 36977c478bd9Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 36987c478bd9Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 36997c478bd9Sstevel@tonic-gate hp->mapaddr = NULL; 37007c478bd9Sstevel@tonic-gate hp->allocaddr = NULL; 37017c478bd9Sstevel@tonic-gate hp->origaddr = NULL; 37027c478bd9Sstevel@tonic-gate } 37037c478bd9Sstevel@tonic-gate return (retval); 37047c478bd9Sstevel@tonic-gate } 37057c478bd9Sstevel@tonic-gate 37067c478bd9Sstevel@tonic-gate 37077c478bd9Sstevel@tonic-gate /* 37087c478bd9Sstevel@tonic-gate * our ddi_dma_unbindhdl routine 37097c478bd9Sstevel@tonic-gate */ 37107c478bd9Sstevel@tonic-gate static int 37117c478bd9Sstevel@tonic-gate bofi_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 37127c478bd9Sstevel@tonic-gate { 37137c478bd9Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 37147c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 37157c478bd9Sstevel@tonic-gate int retval; 37167c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 37177c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 37187c478bd9Sstevel@tonic-gate 37197c478bd9Sstevel@tonic-gate /* 37207c478bd9Sstevel@tonic-gate * call nexus to do the real work 37217c478bd9Sstevel@tonic-gate */ 37227c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_dma_unbindhdl(dip, rdip, handle); 37237c478bd9Sstevel@tonic-gate if (retval != DDI_SUCCESS) 37247c478bd9Sstevel@tonic-gate return (retval); 37257c478bd9Sstevel@tonic-gate /* 37267c478bd9Sstevel@tonic-gate * check we really have a shadow for this handle 37277c478bd9Sstevel@tonic-gate */ 37287c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 37297c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 37307c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 37317c478bd9Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 37327c478bd9Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 37337c478bd9Sstevel@tonic-gate break; 37347c478bd9Sstevel@tonic-gate if (hp == hhashp) { 37357c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 37367c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 37377c478bd9Sstevel@tonic-gate return (retval); 37387c478bd9Sstevel@tonic-gate } 37397c478bd9Sstevel@tonic-gate /* 37407c478bd9Sstevel@tonic-gate * yes we have - see if it's already unbound 37417c478bd9Sstevel@tonic-gate */ 37427c478bd9Sstevel@tonic-gate if (hp->type == BOFI_NULL) 37437c478bd9Sstevel@tonic-gate panic("driver unbinding unbound dma_handle"); 37447c478bd9Sstevel@tonic-gate /* 37457c478bd9Sstevel@tonic-gate * free any errdef link structures tagged on to this 37467c478bd9Sstevel@tonic-gate * shadow handle 37477c478bd9Sstevel@tonic-gate */ 37487c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 37497c478bd9Sstevel@tonic-gate next_lp = lp->link; 37507c478bd9Sstevel@tonic-gate /* 37517c478bd9Sstevel@tonic-gate * there is an implicit sync_for_cpu on free - 37527c478bd9Sstevel@tonic-gate * may need to corrupt 37537c478bd9Sstevel@tonic-gate */ 37547c478bd9Sstevel@tonic-gate ep = lp->errentp; 37557c478bd9Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_R) && 37567c478bd9Sstevel@tonic-gate (hp->flags & DDI_DMA_READ) && 37577c478bd9Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 37587c478bd9Sstevel@tonic-gate do_dma_corrupt(hp, ep, DDI_DMA_SYNC_FORCPU, 0, hp->len); 37597c478bd9Sstevel@tonic-gate } 37607c478bd9Sstevel@tonic-gate lp->link = bofi_link_freelist; 37617c478bd9Sstevel@tonic-gate bofi_link_freelist = lp; 37627c478bd9Sstevel@tonic-gate lp = next_lp; 37637c478bd9Sstevel@tonic-gate } 37647c478bd9Sstevel@tonic-gate hp->link = NULL; 37657c478bd9Sstevel@tonic-gate hp->type = BOFI_NULL; 37667c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 37677c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 37687c478bd9Sstevel@tonic-gate 37697c478bd9Sstevel@tonic-gate if (bofi_sync_check && (hp->flags & DDI_DMA_READ)) 37707c478bd9Sstevel@tonic-gate /* 37717c478bd9Sstevel@tonic-gate * implicit sync_for_cpu - copy data back 37727c478bd9Sstevel@tonic-gate */ 37737c478bd9Sstevel@tonic-gate if (hp->allocaddr) 37747c478bd9Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 37757c478bd9Sstevel@tonic-gate ddi_dmareq_mapout(hp->mapaddr, hp->len); 37767c478bd9Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 37777c478bd9Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 37787c478bd9Sstevel@tonic-gate hp->mapaddr = NULL; 37797c478bd9Sstevel@tonic-gate hp->allocaddr = NULL; 37807c478bd9Sstevel@tonic-gate hp->origaddr = NULL; 37817c478bd9Sstevel@tonic-gate return (retval); 37827c478bd9Sstevel@tonic-gate } 37837c478bd9Sstevel@tonic-gate 37847c478bd9Sstevel@tonic-gate 37857c478bd9Sstevel@tonic-gate /* 37867c478bd9Sstevel@tonic-gate * our ddi_dma_sync routine 37877c478bd9Sstevel@tonic-gate */ 37887c478bd9Sstevel@tonic-gate static int 37897c478bd9Sstevel@tonic-gate bofi_dma_flush(dev_info_t *dip, dev_info_t *rdip, 37907c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, off_t off, size_t len, uint_t flags) 37917c478bd9Sstevel@tonic-gate { 37927c478bd9Sstevel@tonic-gate struct bofi_link *lp; 37937c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 37947c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 37957c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 37967c478bd9Sstevel@tonic-gate int retval; 37977c478bd9Sstevel@tonic-gate 37987c478bd9Sstevel@tonic-gate if (flags == DDI_DMA_SYNC_FORCPU || flags == DDI_DMA_SYNC_FORKERNEL) { 37997c478bd9Sstevel@tonic-gate /* 38007c478bd9Sstevel@tonic-gate * in this case get nexus driver to do sync first 38017c478bd9Sstevel@tonic-gate */ 38027c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_dma_flush(dip, rdip, handle, off, 38037c478bd9Sstevel@tonic-gate len, flags); 38047c478bd9Sstevel@tonic-gate if (retval != DDI_SUCCESS) 38057c478bd9Sstevel@tonic-gate return (retval); 38067c478bd9Sstevel@tonic-gate } 38077c478bd9Sstevel@tonic-gate /* 38087c478bd9Sstevel@tonic-gate * check we really have a shadow for this handle 38097c478bd9Sstevel@tonic-gate */ 38107c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 38117c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 38127c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 38137c478bd9Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 38147c478bd9Sstevel@tonic-gate if (hp->hdl.dma_handle == handle && 38157c478bd9Sstevel@tonic-gate hp->type == BOFI_DMA_HDL) 38167c478bd9Sstevel@tonic-gate break; 38177c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 38187c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 38197c478bd9Sstevel@tonic-gate if (hp != hhashp) { 38207c478bd9Sstevel@tonic-gate /* 38217c478bd9Sstevel@tonic-gate * yes - do we need to copy data from original 38227c478bd9Sstevel@tonic-gate */ 38237c478bd9Sstevel@tonic-gate if (bofi_sync_check && flags == DDI_DMA_SYNC_FORDEV) 38247c478bd9Sstevel@tonic-gate if (hp->allocaddr) 38257c478bd9Sstevel@tonic-gate xbcopy(hp->origaddr+off, hp->addr+off, 38267c478bd9Sstevel@tonic-gate len ? len : (hp->len - off)); 38277c478bd9Sstevel@tonic-gate /* 38287c478bd9Sstevel@tonic-gate * yes - check if we need to corrupt the data 38297c478bd9Sstevel@tonic-gate */ 38307c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 38317c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 38327c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 38337c478bd9Sstevel@tonic-gate ep = lp->errentp; 38347c478bd9Sstevel@tonic-gate if ((((ep->errdef.access_type & BOFI_DMA_R) && 38357c478bd9Sstevel@tonic-gate (flags == DDI_DMA_SYNC_FORCPU || 38367c478bd9Sstevel@tonic-gate flags == DDI_DMA_SYNC_FORKERNEL)) || 38377c478bd9Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_W) && 38387c478bd9Sstevel@tonic-gate (flags == DDI_DMA_SYNC_FORDEV))) && 38397c478bd9Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 38407c478bd9Sstevel@tonic-gate do_dma_corrupt(hp, ep, flags, off, 38417c478bd9Sstevel@tonic-gate len ? len : (hp->len - off)); 38427c478bd9Sstevel@tonic-gate } 38437c478bd9Sstevel@tonic-gate } 38447c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 38457c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 38467c478bd9Sstevel@tonic-gate /* 38477c478bd9Sstevel@tonic-gate * do we need to copy data to original 38487c478bd9Sstevel@tonic-gate */ 38497c478bd9Sstevel@tonic-gate if (bofi_sync_check && (flags == DDI_DMA_SYNC_FORCPU || 38507c478bd9Sstevel@tonic-gate flags == DDI_DMA_SYNC_FORKERNEL)) 38517c478bd9Sstevel@tonic-gate if (hp->allocaddr) 38527c478bd9Sstevel@tonic-gate xbcopy(hp->addr+off, hp->origaddr+off, 38537c478bd9Sstevel@tonic-gate len ? len : (hp->len - off)); 38547c478bd9Sstevel@tonic-gate } 38557c478bd9Sstevel@tonic-gate if (flags == DDI_DMA_SYNC_FORDEV) 38567c478bd9Sstevel@tonic-gate /* 38577c478bd9Sstevel@tonic-gate * in this case get nexus driver to do sync last 38587c478bd9Sstevel@tonic-gate */ 38597c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_dma_flush(dip, rdip, handle, off, 38607c478bd9Sstevel@tonic-gate len, flags); 38617c478bd9Sstevel@tonic-gate return (retval); 38627c478bd9Sstevel@tonic-gate } 38637c478bd9Sstevel@tonic-gate 38647c478bd9Sstevel@tonic-gate 38657c478bd9Sstevel@tonic-gate /* 38667c478bd9Sstevel@tonic-gate * our dma_win routine 38677c478bd9Sstevel@tonic-gate */ 38687c478bd9Sstevel@tonic-gate static int 38697c478bd9Sstevel@tonic-gate bofi_dma_win(dev_info_t *dip, dev_info_t *rdip, 38707c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, uint_t win, off_t *offp, 38717c478bd9Sstevel@tonic-gate size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp) 38727c478bd9Sstevel@tonic-gate { 38737c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 38747c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 38757c478bd9Sstevel@tonic-gate int retval; 38767c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp; 38777c478bd9Sstevel@tonic-gate 38787c478bd9Sstevel@tonic-gate /* 38797c478bd9Sstevel@tonic-gate * call nexus to do the real work 38807c478bd9Sstevel@tonic-gate */ 38817c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_dma_win(dip, rdip, handle, win, offp, lenp, 38827c478bd9Sstevel@tonic-gate cookiep, ccountp); 38837c478bd9Sstevel@tonic-gate if (retval != DDI_SUCCESS) 38847c478bd9Sstevel@tonic-gate return (retval); 38857c478bd9Sstevel@tonic-gate /* 38867c478bd9Sstevel@tonic-gate * check we really have a shadow for this handle 38877c478bd9Sstevel@tonic-gate */ 38887c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 38897c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 38907c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 38917c478bd9Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 38927c478bd9Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 38937c478bd9Sstevel@tonic-gate break; 38947c478bd9Sstevel@tonic-gate if (hp != hhashp) { 38957c478bd9Sstevel@tonic-gate /* 38967c478bd9Sstevel@tonic-gate * yes - make sure DMP_NOSYNC is unset 38977c478bd9Sstevel@tonic-gate */ 38987c478bd9Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 38997c478bd9Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 39007c478bd9Sstevel@tonic-gate } 39017c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 39027c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 39037c478bd9Sstevel@tonic-gate return (retval); 39047c478bd9Sstevel@tonic-gate } 39057c478bd9Sstevel@tonic-gate 39067c478bd9Sstevel@tonic-gate 39077c478bd9Sstevel@tonic-gate /* 39087c478bd9Sstevel@tonic-gate * our dma_ctl routine 39097c478bd9Sstevel@tonic-gate */ 39107c478bd9Sstevel@tonic-gate static int 39117c478bd9Sstevel@tonic-gate bofi_dma_ctl(dev_info_t *dip, dev_info_t *rdip, 39127c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, enum ddi_dma_ctlops request, 39137c478bd9Sstevel@tonic-gate off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags) 39147c478bd9Sstevel@tonic-gate { 39157c478bd9Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 39167c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 39177c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 39187c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 39197c478bd9Sstevel@tonic-gate int retval; 39207c478bd9Sstevel@tonic-gate int i; 39217c478bd9Sstevel@tonic-gate struct bofi_shadow *dummyhp; 39227c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp; 39237c478bd9Sstevel@tonic-gate 39247c478bd9Sstevel@tonic-gate /* 39257c478bd9Sstevel@tonic-gate * get nexus to do real work 39267c478bd9Sstevel@tonic-gate */ 39277c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_dma_ctl(dip, rdip, handle, request, offp, 39287c478bd9Sstevel@tonic-gate lenp, objp, flags); 39297c478bd9Sstevel@tonic-gate if (retval != DDI_SUCCESS) 39307c478bd9Sstevel@tonic-gate return (retval); 39317c478bd9Sstevel@tonic-gate /* 39327c478bd9Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 39337c478bd9Sstevel@tonic-gate */ 39347c478bd9Sstevel@tonic-gate if (!driver_under_test(rdip)) 39357c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 39367c478bd9Sstevel@tonic-gate 39377c478bd9Sstevel@tonic-gate #if defined(__sparc) 39387c478bd9Sstevel@tonic-gate /* 39397c478bd9Sstevel@tonic-gate * check if this is a dvma_reserve - that one's like a 39407c478bd9Sstevel@tonic-gate * dma_allochdl and needs to be handled separately 39417c478bd9Sstevel@tonic-gate */ 39427c478bd9Sstevel@tonic-gate if (request == DDI_DMA_RESERVE) { 39437c478bd9Sstevel@tonic-gate bofi_dvma_reserve(rdip, *(ddi_dma_handle_t *)objp); 39447c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 39457c478bd9Sstevel@tonic-gate } 39467c478bd9Sstevel@tonic-gate #endif 39477c478bd9Sstevel@tonic-gate /* 39487c478bd9Sstevel@tonic-gate * check we really have a shadow for this handle 39497c478bd9Sstevel@tonic-gate */ 39507c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 39517c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 39527c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 39537c478bd9Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 39547c478bd9Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 39557c478bd9Sstevel@tonic-gate break; 39567c478bd9Sstevel@tonic-gate if (hp == hhashp) { 39577c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 39587c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 39597c478bd9Sstevel@tonic-gate return (retval); 39607c478bd9Sstevel@tonic-gate } 39617c478bd9Sstevel@tonic-gate /* 39627c478bd9Sstevel@tonic-gate * yes we have - see what kind of command this is 39637c478bd9Sstevel@tonic-gate */ 39647c478bd9Sstevel@tonic-gate switch (request) { 39657c478bd9Sstevel@tonic-gate case DDI_DMA_RELEASE: 39667c478bd9Sstevel@tonic-gate /* 39677c478bd9Sstevel@tonic-gate * dvma release - release dummy handle and all the index handles 39687c478bd9Sstevel@tonic-gate */ 39697c478bd9Sstevel@tonic-gate dummyhp = hp; 39707c478bd9Sstevel@tonic-gate dummyhp->hnext->hprev = dummyhp->hprev; 39717c478bd9Sstevel@tonic-gate dummyhp->hprev->hnext = dummyhp->hnext; 39727c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 39737c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 39747c478bd9Sstevel@tonic-gate for (i = 0; i < dummyhp->len; i++) { 39757c478bd9Sstevel@tonic-gate hp = dummyhp->hparrayp[i]; 39767c478bd9Sstevel@tonic-gate /* 39777c478bd9Sstevel@tonic-gate * chek none of the index handles were still loaded 39787c478bd9Sstevel@tonic-gate */ 39797c478bd9Sstevel@tonic-gate if (hp->type != BOFI_NULL) 39807c478bd9Sstevel@tonic-gate panic("driver releasing loaded dvma"); 39817c478bd9Sstevel@tonic-gate /* 39827c478bd9Sstevel@tonic-gate * remove from dhash and inuse lists 39837c478bd9Sstevel@tonic-gate */ 39847c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 39857c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 39867c478bd9Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 39877c478bd9Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 39887c478bd9Sstevel@tonic-gate hp->next->prev = hp->prev; 39897c478bd9Sstevel@tonic-gate hp->prev->next = hp->next; 39907c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 39917c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 39927c478bd9Sstevel@tonic-gate 39937c478bd9Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 39947c478bd9Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 39957c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 39967c478bd9Sstevel@tonic-gate } 39977c478bd9Sstevel@tonic-gate kmem_free(dummyhp->hparrayp, dummyhp->len * 39987c478bd9Sstevel@tonic-gate sizeof (struct bofi_shadow *)); 39997c478bd9Sstevel@tonic-gate kmem_free(dummyhp, sizeof (struct bofi_shadow)); 40007c478bd9Sstevel@tonic-gate return (retval); 40017c478bd9Sstevel@tonic-gate case DDI_DMA_FREE: 40027c478bd9Sstevel@tonic-gate /* 40037c478bd9Sstevel@tonic-gate * ddi_dma_free case - remove from dhash, hhash and inuse lists 40047c478bd9Sstevel@tonic-gate */ 40057c478bd9Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 40067c478bd9Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 40077c478bd9Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 40087c478bd9Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 40097c478bd9Sstevel@tonic-gate hp->next->prev = hp->prev; 40107c478bd9Sstevel@tonic-gate hp->prev->next = hp->next; 40117c478bd9Sstevel@tonic-gate /* 40127c478bd9Sstevel@tonic-gate * free any errdef link structures tagged on to this 40137c478bd9Sstevel@tonic-gate * shadow handle 40147c478bd9Sstevel@tonic-gate */ 40157c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 40167c478bd9Sstevel@tonic-gate next_lp = lp->link; 40177c478bd9Sstevel@tonic-gate /* 40187c478bd9Sstevel@tonic-gate * there is an implicit sync_for_cpu on free - 40197c478bd9Sstevel@tonic-gate * may need to corrupt 40207c478bd9Sstevel@tonic-gate */ 40217c478bd9Sstevel@tonic-gate ep = lp->errentp; 40227c478bd9Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_R) && 40237c478bd9Sstevel@tonic-gate (hp->flags & DDI_DMA_READ) && 40247c478bd9Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 40257c478bd9Sstevel@tonic-gate do_dma_corrupt(hp, ep, DDI_DMA_SYNC_FORCPU, 40267c478bd9Sstevel@tonic-gate 0, hp->len); 40277c478bd9Sstevel@tonic-gate } 40287c478bd9Sstevel@tonic-gate lp->link = bofi_link_freelist; 40297c478bd9Sstevel@tonic-gate bofi_link_freelist = lp; 40307c478bd9Sstevel@tonic-gate lp = next_lp; 40317c478bd9Sstevel@tonic-gate } 40327c478bd9Sstevel@tonic-gate hp->link = NULL; 40337c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 40347c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 40357c478bd9Sstevel@tonic-gate 40367c478bd9Sstevel@tonic-gate if (bofi_sync_check && (hp->flags & DDI_DMA_READ)) 40377c478bd9Sstevel@tonic-gate if (hp->allocaddr) 40387c478bd9Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 40397c478bd9Sstevel@tonic-gate ddi_dmareq_mapout(hp->mapaddr, hp->len); 40407c478bd9Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 40417c478bd9Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 40427c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 40437c478bd9Sstevel@tonic-gate return (retval); 40447c478bd9Sstevel@tonic-gate case DDI_DMA_MOVWIN: 40457c478bd9Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 40467c478bd9Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 40477c478bd9Sstevel@tonic-gate break; 40487c478bd9Sstevel@tonic-gate case DDI_DMA_NEXTWIN: 40497c478bd9Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 40507c478bd9Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 40517c478bd9Sstevel@tonic-gate break; 40527c478bd9Sstevel@tonic-gate default: 40537c478bd9Sstevel@tonic-gate break; 40547c478bd9Sstevel@tonic-gate } 40557c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 40567c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 40577c478bd9Sstevel@tonic-gate return (retval); 40587c478bd9Sstevel@tonic-gate } 40597c478bd9Sstevel@tonic-gate 40607c478bd9Sstevel@tonic-gate #if defined(__sparc) 40617c478bd9Sstevel@tonic-gate /* 40627c478bd9Sstevel@tonic-gate * dvma reserve case from bofi_dma_ctl() 40637c478bd9Sstevel@tonic-gate */ 40647c478bd9Sstevel@tonic-gate static void 40657c478bd9Sstevel@tonic-gate bofi_dvma_reserve(dev_info_t *rdip, ddi_dma_handle_t handle) 40667c478bd9Sstevel@tonic-gate { 40677c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 40687c478bd9Sstevel@tonic-gate struct bofi_shadow *dummyhp; 40697c478bd9Sstevel@tonic-gate struct bofi_shadow *dhashp; 40707c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 40717c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp; 40727c478bd9Sstevel@tonic-gate struct fast_dvma *nexus_private; 40737c478bd9Sstevel@tonic-gate int i, count; 40747c478bd9Sstevel@tonic-gate 40757c478bd9Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 40767c478bd9Sstevel@tonic-gate count = mp->dmai_ndvmapages; 40777c478bd9Sstevel@tonic-gate /* 40787c478bd9Sstevel@tonic-gate * allocate dummy shadow handle structure 40797c478bd9Sstevel@tonic-gate */ 40807c478bd9Sstevel@tonic-gate dummyhp = kmem_zalloc(sizeof (*dummyhp), KM_SLEEP); 40817c478bd9Sstevel@tonic-gate if (mp->dmai_rflags & DMP_BYPASSNEXUS) { 40827c478bd9Sstevel@tonic-gate /* 40837c478bd9Sstevel@tonic-gate * overlay our routines over the nexus's dvma routines 40847c478bd9Sstevel@tonic-gate */ 40857c478bd9Sstevel@tonic-gate nexus_private = (struct fast_dvma *)mp->dmai_nexus_private; 40867c478bd9Sstevel@tonic-gate dummyhp->save.dvma_ops = *(nexus_private->ops); 40877c478bd9Sstevel@tonic-gate nexus_private->ops = &bofi_dvma_ops; 40887c478bd9Sstevel@tonic-gate } 40897c478bd9Sstevel@tonic-gate /* 40907c478bd9Sstevel@tonic-gate * now fill in the dummy handle. This just gets put on hhash queue 40917c478bd9Sstevel@tonic-gate * so our dvma routines can find and index off to the handle they 40927c478bd9Sstevel@tonic-gate * really want. 40937c478bd9Sstevel@tonic-gate */ 40947c478bd9Sstevel@tonic-gate (void) strncpy(dummyhp->name, ddi_get_name(rdip), NAMESIZE); 40957c478bd9Sstevel@tonic-gate dummyhp->instance = ddi_get_instance(rdip); 40967c478bd9Sstevel@tonic-gate dummyhp->rnumber = -1; 40977c478bd9Sstevel@tonic-gate dummyhp->dip = rdip; 40987c478bd9Sstevel@tonic-gate dummyhp->len = count; 40997c478bd9Sstevel@tonic-gate dummyhp->hdl.dma_handle = handle; 41007c478bd9Sstevel@tonic-gate dummyhp->link = NULL; 41017c478bd9Sstevel@tonic-gate dummyhp->type = BOFI_NULL; 41027c478bd9Sstevel@tonic-gate /* 41037c478bd9Sstevel@tonic-gate * allocate space for real handles 41047c478bd9Sstevel@tonic-gate */ 41057c478bd9Sstevel@tonic-gate dummyhp->hparrayp = kmem_alloc(count * 41067c478bd9Sstevel@tonic-gate sizeof (struct bofi_shadow *), KM_SLEEP); 41077c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 41087c478bd9Sstevel@tonic-gate /* 41097c478bd9Sstevel@tonic-gate * allocate shadow handle structures and fill them in 41107c478bd9Sstevel@tonic-gate */ 41117c478bd9Sstevel@tonic-gate hp = kmem_zalloc(sizeof (*hp), KM_SLEEP); 41127c478bd9Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 41137c478bd9Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 41147c478bd9Sstevel@tonic-gate hp->rnumber = -1; 41157c478bd9Sstevel@tonic-gate hp->dip = rdip; 41167c478bd9Sstevel@tonic-gate hp->hdl.dma_handle = 0; 41177c478bd9Sstevel@tonic-gate hp->link = NULL; 41187c478bd9Sstevel@tonic-gate hp->type = BOFI_NULL; 41197c478bd9Sstevel@tonic-gate if (bofi_sync_check) { 41207c478bd9Sstevel@tonic-gate unsigned long pagemask = ddi_ptob(rdip, 1) - 1; 41217c478bd9Sstevel@tonic-gate /* 41227c478bd9Sstevel@tonic-gate * Take a copy and set this to be hp->addr 41237c478bd9Sstevel@tonic-gate * Data will be copied to and from the original on 41247c478bd9Sstevel@tonic-gate * explicit and implicit ddi_dma_sync() 41257c478bd9Sstevel@tonic-gate * 41267c478bd9Sstevel@tonic-gate * - maintain page alignment because some devices 41277c478bd9Sstevel@tonic-gate * assume it. 41287c478bd9Sstevel@tonic-gate */ 41297c478bd9Sstevel@tonic-gate hp->allocaddr = ddi_umem_alloc( 41307c478bd9Sstevel@tonic-gate ((int)hp->addr & pagemask) + pagemask + 1, 41317c478bd9Sstevel@tonic-gate KM_SLEEP, &hp->umem_cookie); 41327c478bd9Sstevel@tonic-gate hp->addr = hp->allocaddr + ((int)hp->addr & pagemask); 41337c478bd9Sstevel@tonic-gate } 41347c478bd9Sstevel@tonic-gate /* 41357c478bd9Sstevel@tonic-gate * add to dhash and inuse lists. 41367c478bd9Sstevel@tonic-gate * these don't go on hhash queue. 41377c478bd9Sstevel@tonic-gate */ 41387c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 41397c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 41407c478bd9Sstevel@tonic-gate hp->next = shadow_list.next; 41417c478bd9Sstevel@tonic-gate shadow_list.next->prev = hp; 41427c478bd9Sstevel@tonic-gate hp->prev = &shadow_list; 41437c478bd9Sstevel@tonic-gate shadow_list.next = hp; 41447c478bd9Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 41457c478bd9Sstevel@tonic-gate hp->dnext = dhashp->dnext; 41467c478bd9Sstevel@tonic-gate dhashp->dnext->dprev = hp; 41477c478bd9Sstevel@tonic-gate hp->dprev = dhashp; 41487c478bd9Sstevel@tonic-gate dhashp->dnext = hp; 41497c478bd9Sstevel@tonic-gate dummyhp->hparrayp[i] = hp; 41507c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 41517c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 41527c478bd9Sstevel@tonic-gate } 41537c478bd9Sstevel@tonic-gate /* 41547c478bd9Sstevel@tonic-gate * add dummy handle to hhash list only 41557c478bd9Sstevel@tonic-gate */ 41567c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 41577c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 41587c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 41597c478bd9Sstevel@tonic-gate dummyhp->hnext = hhashp->hnext; 41607c478bd9Sstevel@tonic-gate hhashp->hnext->hprev = dummyhp; 41617c478bd9Sstevel@tonic-gate dummyhp->hprev = hhashp; 41627c478bd9Sstevel@tonic-gate hhashp->hnext = dummyhp; 41637c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 41647c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 41657c478bd9Sstevel@tonic-gate } 41667c478bd9Sstevel@tonic-gate 41677c478bd9Sstevel@tonic-gate /* 41687c478bd9Sstevel@tonic-gate * our dvma_kaddr_load() 41697c478bd9Sstevel@tonic-gate */ 41707c478bd9Sstevel@tonic-gate static void 41717c478bd9Sstevel@tonic-gate bofi_dvma_kaddr_load(ddi_dma_handle_t h, caddr_t a, uint_t len, uint_t index, 41727c478bd9Sstevel@tonic-gate ddi_dma_cookie_t *cp) 41737c478bd9Sstevel@tonic-gate { 41747c478bd9Sstevel@tonic-gate struct bofi_shadow *dummyhp; 41757c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 41767c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 41777c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 41787c478bd9Sstevel@tonic-gate struct bofi_link *lp; 41797c478bd9Sstevel@tonic-gate 41807c478bd9Sstevel@tonic-gate /* 41817c478bd9Sstevel@tonic-gate * check we really have a dummy shadow for this handle 41827c478bd9Sstevel@tonic-gate */ 41837c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 41847c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 41857c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(h); 41867c478bd9Sstevel@tonic-gate for (dummyhp = hhashp->hnext; dummyhp != hhashp; 41877c478bd9Sstevel@tonic-gate dummyhp = dummyhp->hnext) 41887c478bd9Sstevel@tonic-gate if (dummyhp->hdl.dma_handle == h) 41897c478bd9Sstevel@tonic-gate break; 41907c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 41917c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 41927c478bd9Sstevel@tonic-gate if (dummyhp == hhashp) { 41937c478bd9Sstevel@tonic-gate /* 41947c478bd9Sstevel@tonic-gate * no dummy shadow - panic 41957c478bd9Sstevel@tonic-gate */ 41967c478bd9Sstevel@tonic-gate panic("driver dvma_kaddr_load with no reserve"); 41977c478bd9Sstevel@tonic-gate } 41987c478bd9Sstevel@tonic-gate 41997c478bd9Sstevel@tonic-gate /* 42007c478bd9Sstevel@tonic-gate * find real hp 42017c478bd9Sstevel@tonic-gate */ 42027c478bd9Sstevel@tonic-gate hp = dummyhp->hparrayp[index]; 42037c478bd9Sstevel@tonic-gate /* 42047c478bd9Sstevel@tonic-gate * check its not already loaded 42057c478bd9Sstevel@tonic-gate */ 42067c478bd9Sstevel@tonic-gate if (hp->type != BOFI_NULL) 42077c478bd9Sstevel@tonic-gate panic("driver loading loaded dvma"); 42087c478bd9Sstevel@tonic-gate /* 42097c478bd9Sstevel@tonic-gate * if were doing copying, just need to change origaddr and get 42107c478bd9Sstevel@tonic-gate * nexus to map hp->addr again 42117c478bd9Sstevel@tonic-gate * if not, set hp->addr to new address. 42127c478bd9Sstevel@tonic-gate * - note these are always kernel virtual addresses - no need to map 42137c478bd9Sstevel@tonic-gate */ 42147c478bd9Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) { 42157c478bd9Sstevel@tonic-gate hp->origaddr = a; 42167c478bd9Sstevel@tonic-gate a = hp->addr; 42177c478bd9Sstevel@tonic-gate } else 42187c478bd9Sstevel@tonic-gate hp->addr = a; 42197c478bd9Sstevel@tonic-gate hp->len = len; 42207c478bd9Sstevel@tonic-gate /* 42217c478bd9Sstevel@tonic-gate * get nexus to do the real work 42227c478bd9Sstevel@tonic-gate */ 42237c478bd9Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_kaddr_load(h, a, len, index, cp); 42247c478bd9Sstevel@tonic-gate /* 42257c478bd9Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this dma_handle 42267c478bd9Sstevel@tonic-gate * no need to corrupt - there's no implicit dma_sync on this one 42277c478bd9Sstevel@tonic-gate */ 42287c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 42297c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 42307c478bd9Sstevel@tonic-gate hp->type = BOFI_DMA_HDL; 42317c478bd9Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 42327c478bd9Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 42337c478bd9Sstevel@tonic-gate ddi_name_to_major(ep->name) && 42347c478bd9Sstevel@tonic-gate hp->instance == ep->errdef.instance && 42357c478bd9Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 42367c478bd9Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 42377c478bd9Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_RW) && 42387c478bd9Sstevel@tonic-gate (((uintptr_t)(hp->addr + ep->errdef.offset + 42397c478bd9Sstevel@tonic-gate ep->errdef.len) & ~LLSZMASK) > 42407c478bd9Sstevel@tonic-gate ((uintptr_t)((hp->addr + ep->errdef.offset) + 42417c478bd9Sstevel@tonic-gate LLSZMASK) & ~LLSZMASK)))) { 42427c478bd9Sstevel@tonic-gate lp = bofi_link_freelist; 42437c478bd9Sstevel@tonic-gate if (lp != NULL) { 42447c478bd9Sstevel@tonic-gate bofi_link_freelist = lp->link; 42457c478bd9Sstevel@tonic-gate lp->errentp = ep; 42467c478bd9Sstevel@tonic-gate lp->link = hp->link; 42477c478bd9Sstevel@tonic-gate hp->link = lp; 42487c478bd9Sstevel@tonic-gate } 42497c478bd9Sstevel@tonic-gate } 42507c478bd9Sstevel@tonic-gate } 42517c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 42527c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 42537c478bd9Sstevel@tonic-gate } 42547c478bd9Sstevel@tonic-gate 42557c478bd9Sstevel@tonic-gate /* 42567c478bd9Sstevel@tonic-gate * our dvma_unload() 42577c478bd9Sstevel@tonic-gate */ 42587c478bd9Sstevel@tonic-gate static void 42597c478bd9Sstevel@tonic-gate bofi_dvma_unload(ddi_dma_handle_t h, uint_t index, uint_t view) 42607c478bd9Sstevel@tonic-gate { 42617c478bd9Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 42627c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 42637c478bd9Sstevel@tonic-gate struct bofi_shadow *dummyhp; 42647c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 42657c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 42667c478bd9Sstevel@tonic-gate 42677c478bd9Sstevel@tonic-gate /* 42687c478bd9Sstevel@tonic-gate * check we really have a dummy shadow for this handle 42697c478bd9Sstevel@tonic-gate */ 42707c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 42717c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 42727c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(h); 42737c478bd9Sstevel@tonic-gate for (dummyhp = hhashp->hnext; dummyhp != hhashp; 42747c478bd9Sstevel@tonic-gate dummyhp = dummyhp->hnext) 42757c478bd9Sstevel@tonic-gate if (dummyhp->hdl.dma_handle == h) 42767c478bd9Sstevel@tonic-gate break; 42777c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 42787c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 42797c478bd9Sstevel@tonic-gate if (dummyhp == hhashp) { 42807c478bd9Sstevel@tonic-gate /* 42817c478bd9Sstevel@tonic-gate * no dummy shadow - panic 42827c478bd9Sstevel@tonic-gate */ 42837c478bd9Sstevel@tonic-gate panic("driver dvma_unload with no reserve"); 42847c478bd9Sstevel@tonic-gate } 42857c478bd9Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_unload(h, index, view); 42867c478bd9Sstevel@tonic-gate /* 42877c478bd9Sstevel@tonic-gate * find real hp 42887c478bd9Sstevel@tonic-gate */ 42897c478bd9Sstevel@tonic-gate hp = dummyhp->hparrayp[index]; 42907c478bd9Sstevel@tonic-gate /* 42917c478bd9Sstevel@tonic-gate * check its not already unloaded 42927c478bd9Sstevel@tonic-gate */ 42937c478bd9Sstevel@tonic-gate if (hp->type == BOFI_NULL) 42947c478bd9Sstevel@tonic-gate panic("driver unloading unloaded dvma"); 42957c478bd9Sstevel@tonic-gate /* 42967c478bd9Sstevel@tonic-gate * free any errdef link structures tagged on to this 42977c478bd9Sstevel@tonic-gate * shadow handle - do corruption if necessary 42987c478bd9Sstevel@tonic-gate */ 42997c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 43007c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 43017c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 43027c478bd9Sstevel@tonic-gate next_lp = lp->link; 43037c478bd9Sstevel@tonic-gate ep = lp->errentp; 43047c478bd9Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_R) && 43057c478bd9Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || 43067c478bd9Sstevel@tonic-gate view == DDI_DMA_SYNC_FORKERNEL) && 43077c478bd9Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 43087c478bd9Sstevel@tonic-gate do_dma_corrupt(hp, ep, view, 0, hp->len); 43097c478bd9Sstevel@tonic-gate } 43107c478bd9Sstevel@tonic-gate lp->link = bofi_link_freelist; 43117c478bd9Sstevel@tonic-gate bofi_link_freelist = lp; 43127c478bd9Sstevel@tonic-gate lp = next_lp; 43137c478bd9Sstevel@tonic-gate } 43147c478bd9Sstevel@tonic-gate hp->link = NULL; 43157c478bd9Sstevel@tonic-gate hp->type = BOFI_NULL; 43167c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 43177c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 43187c478bd9Sstevel@tonic-gate /* 43197c478bd9Sstevel@tonic-gate * if there is an explicit sync_for_cpu, then do copy to original 43207c478bd9Sstevel@tonic-gate */ 43217c478bd9Sstevel@tonic-gate if (bofi_sync_check && 43227c478bd9Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL)) 43237c478bd9Sstevel@tonic-gate if (hp->allocaddr) 43247c478bd9Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 43257c478bd9Sstevel@tonic-gate } 43267c478bd9Sstevel@tonic-gate 43277c478bd9Sstevel@tonic-gate /* 43287c478bd9Sstevel@tonic-gate * our dvma_unload() 43297c478bd9Sstevel@tonic-gate */ 43307c478bd9Sstevel@tonic-gate static void 43317c478bd9Sstevel@tonic-gate bofi_dvma_sync(ddi_dma_handle_t h, uint_t index, uint_t view) 43327c478bd9Sstevel@tonic-gate { 43337c478bd9Sstevel@tonic-gate struct bofi_link *lp; 43347c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 43357c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 43367c478bd9Sstevel@tonic-gate struct bofi_shadow *dummyhp; 43377c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 43387c478bd9Sstevel@tonic-gate 43397c478bd9Sstevel@tonic-gate /* 43407c478bd9Sstevel@tonic-gate * check we really have a dummy shadow for this handle 43417c478bd9Sstevel@tonic-gate */ 43427c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 43437c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 43447c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(h); 43457c478bd9Sstevel@tonic-gate for (dummyhp = hhashp->hnext; dummyhp != hhashp; 43467c478bd9Sstevel@tonic-gate dummyhp = dummyhp->hnext) 43477c478bd9Sstevel@tonic-gate if (dummyhp->hdl.dma_handle == h) 43487c478bd9Sstevel@tonic-gate break; 43497c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 43507c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 43517c478bd9Sstevel@tonic-gate if (dummyhp == hhashp) { 43527c478bd9Sstevel@tonic-gate /* 43537c478bd9Sstevel@tonic-gate * no dummy shadow - panic 43547c478bd9Sstevel@tonic-gate */ 43557c478bd9Sstevel@tonic-gate panic("driver dvma_sync with no reserve"); 43567c478bd9Sstevel@tonic-gate } 43577c478bd9Sstevel@tonic-gate /* 43587c478bd9Sstevel@tonic-gate * find real hp 43597c478bd9Sstevel@tonic-gate */ 43607c478bd9Sstevel@tonic-gate hp = dummyhp->hparrayp[index]; 43617c478bd9Sstevel@tonic-gate /* 43627c478bd9Sstevel@tonic-gate * check its already loaded 43637c478bd9Sstevel@tonic-gate */ 43647c478bd9Sstevel@tonic-gate if (hp->type == BOFI_NULL) 43657c478bd9Sstevel@tonic-gate panic("driver syncing unloaded dvma"); 43667c478bd9Sstevel@tonic-gate if (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL) 43677c478bd9Sstevel@tonic-gate /* 43687c478bd9Sstevel@tonic-gate * in this case do sync first 43697c478bd9Sstevel@tonic-gate */ 43707c478bd9Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_sync(h, index, view); 43717c478bd9Sstevel@tonic-gate /* 43727c478bd9Sstevel@tonic-gate * if there is an explicit sync_for_dev, then do copy from original 43737c478bd9Sstevel@tonic-gate */ 43747c478bd9Sstevel@tonic-gate if (bofi_sync_check && view == DDI_DMA_SYNC_FORDEV) { 43757c478bd9Sstevel@tonic-gate if (hp->allocaddr) 43767c478bd9Sstevel@tonic-gate xbcopy(hp->origaddr, hp->addr, hp->len); 43777c478bd9Sstevel@tonic-gate } 43787c478bd9Sstevel@tonic-gate /* 43797c478bd9Sstevel@tonic-gate * do corruption if necessary 43807c478bd9Sstevel@tonic-gate */ 43817c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 43827c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 43837c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 43847c478bd9Sstevel@tonic-gate ep = lp->errentp; 43857c478bd9Sstevel@tonic-gate if ((((ep->errdef.access_type & BOFI_DMA_R) && 43867c478bd9Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || 43877c478bd9Sstevel@tonic-gate view == DDI_DMA_SYNC_FORKERNEL)) || 43887c478bd9Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_W) && 43897c478bd9Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORDEV))) && 43907c478bd9Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 43917c478bd9Sstevel@tonic-gate do_dma_corrupt(hp, ep, view, 0, hp->len); 43927c478bd9Sstevel@tonic-gate } 43937c478bd9Sstevel@tonic-gate } 43947c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 43957c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 43967c478bd9Sstevel@tonic-gate /* 43977c478bd9Sstevel@tonic-gate * if there is an explicit sync_for_cpu, then do copy to original 43987c478bd9Sstevel@tonic-gate */ 43997c478bd9Sstevel@tonic-gate if (bofi_sync_check && 44007c478bd9Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL)) { 44017c478bd9Sstevel@tonic-gate if (hp->allocaddr) 44027c478bd9Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 44037c478bd9Sstevel@tonic-gate } 44047c478bd9Sstevel@tonic-gate if (view == DDI_DMA_SYNC_FORDEV) 44057c478bd9Sstevel@tonic-gate /* 44067c478bd9Sstevel@tonic-gate * in this case do sync last 44077c478bd9Sstevel@tonic-gate */ 44087c478bd9Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_sync(h, index, view); 44097c478bd9Sstevel@tonic-gate } 44107c478bd9Sstevel@tonic-gate #endif 44117c478bd9Sstevel@tonic-gate 44127c478bd9Sstevel@tonic-gate /* 44137c478bd9Sstevel@tonic-gate * bofi intercept routine - gets called instead of users interrupt routine 44147c478bd9Sstevel@tonic-gate */ 44157c478bd9Sstevel@tonic-gate static uint_t 44167c478bd9Sstevel@tonic-gate bofi_intercept_intr(caddr_t xp) 44177c478bd9Sstevel@tonic-gate { 44187c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 44197c478bd9Sstevel@tonic-gate struct bofi_link *lp; 44207c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 44217c478bd9Sstevel@tonic-gate int intr_count = 1; 44227c478bd9Sstevel@tonic-gate int i; 44237c478bd9Sstevel@tonic-gate uint_t retval = DDI_INTR_UNCLAIMED; 44247c478bd9Sstevel@tonic-gate uint_t result; 44257c478bd9Sstevel@tonic-gate int unclaimed_counter = 0; 44267c478bd9Sstevel@tonic-gate int jabber_detected = 0; 44277c478bd9Sstevel@tonic-gate 44287c478bd9Sstevel@tonic-gate hp = (struct bofi_shadow *)xp; 44297c478bd9Sstevel@tonic-gate /* 44307c478bd9Sstevel@tonic-gate * check if nothing to do 44317c478bd9Sstevel@tonic-gate */ 44327c478bd9Sstevel@tonic-gate if (hp->link == NULL) 44337c478bd9Sstevel@tonic-gate return (hp->save.intr.int_handler 44347c478bd9Sstevel@tonic-gate (hp->save.intr.int_handler_arg1, NULL)); 44357c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 44367c478bd9Sstevel@tonic-gate /* 44377c478bd9Sstevel@tonic-gate * look for any errdefs 44387c478bd9Sstevel@tonic-gate */ 44397c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 44407c478bd9Sstevel@tonic-gate ep = lp->errentp; 44417c478bd9Sstevel@tonic-gate if (ep->state & BOFI_DEV_ACTIVE) { 44427c478bd9Sstevel@tonic-gate /* 44437c478bd9Sstevel@tonic-gate * got one 44447c478bd9Sstevel@tonic-gate */ 44457c478bd9Sstevel@tonic-gate if ((ep->errdef.access_count || 44467c478bd9Sstevel@tonic-gate ep->errdef.fail_count) && 44477c478bd9Sstevel@tonic-gate (ep->errdef.access_type & BOFI_LOG)) 44487c478bd9Sstevel@tonic-gate log_acc_event(ep, BOFI_INTR, 0, 0, 1, 0); 44497c478bd9Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 44507c478bd9Sstevel@tonic-gate ep->errdef.access_count--; 44517c478bd9Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 44527c478bd9Sstevel@tonic-gate ep->errdef.fail_count--; 44537c478bd9Sstevel@tonic-gate ep->errdef.access_count = 0; 44547c478bd9Sstevel@tonic-gate /* 44557c478bd9Sstevel@tonic-gate * OK do "corruption" 44567c478bd9Sstevel@tonic-gate */ 44577c478bd9Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 44587c478bd9Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 44597c478bd9Sstevel@tonic-gate switch (ep->errdef.optype) { 44607c478bd9Sstevel@tonic-gate case BOFI_DELAY_INTR: 44617c478bd9Sstevel@tonic-gate if (!hp->hilevel) { 44627c478bd9Sstevel@tonic-gate drv_usecwait 44637c478bd9Sstevel@tonic-gate (ep->errdef.operand); 44647c478bd9Sstevel@tonic-gate } 44657c478bd9Sstevel@tonic-gate break; 44667c478bd9Sstevel@tonic-gate case BOFI_LOSE_INTR: 44677c478bd9Sstevel@tonic-gate intr_count = 0; 44687c478bd9Sstevel@tonic-gate break; 44697c478bd9Sstevel@tonic-gate case BOFI_EXTRA_INTR: 44707c478bd9Sstevel@tonic-gate intr_count += ep->errdef.operand; 44717c478bd9Sstevel@tonic-gate break; 44727c478bd9Sstevel@tonic-gate default: 44737c478bd9Sstevel@tonic-gate break; 44747c478bd9Sstevel@tonic-gate } 44757c478bd9Sstevel@tonic-gate } 44767c478bd9Sstevel@tonic-gate } 44777c478bd9Sstevel@tonic-gate } 44787c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 44797c478bd9Sstevel@tonic-gate /* 44807c478bd9Sstevel@tonic-gate * send extra or fewer interrupts as requested 44817c478bd9Sstevel@tonic-gate */ 44827c478bd9Sstevel@tonic-gate for (i = 0; i < intr_count; i++) { 44837c478bd9Sstevel@tonic-gate result = hp->save.intr.int_handler 44847c478bd9Sstevel@tonic-gate (hp->save.intr.int_handler_arg1, NULL); 44857c478bd9Sstevel@tonic-gate if (result == DDI_INTR_CLAIMED) 44867c478bd9Sstevel@tonic-gate unclaimed_counter >>= 1; 44877c478bd9Sstevel@tonic-gate else if (++unclaimed_counter >= 20) 44887c478bd9Sstevel@tonic-gate jabber_detected = 1; 44897c478bd9Sstevel@tonic-gate if (i == 0) 44907c478bd9Sstevel@tonic-gate retval = result; 44917c478bd9Sstevel@tonic-gate } 44927c478bd9Sstevel@tonic-gate /* 44937c478bd9Sstevel@tonic-gate * if more than 1000 spurious interrupts requested and 44947c478bd9Sstevel@tonic-gate * jabber not detected - give warning 44957c478bd9Sstevel@tonic-gate */ 44967c478bd9Sstevel@tonic-gate if (intr_count > 1000 && !jabber_detected) 44977c478bd9Sstevel@tonic-gate panic("undetected interrupt jabber: %s%d", 44987c478bd9Sstevel@tonic-gate hp->name, hp->instance); 44997c478bd9Sstevel@tonic-gate /* 45007c478bd9Sstevel@tonic-gate * return first response - or "unclaimed" if none 45017c478bd9Sstevel@tonic-gate */ 45027c478bd9Sstevel@tonic-gate return (retval); 45037c478bd9Sstevel@tonic-gate } 45047c478bd9Sstevel@tonic-gate 45057c478bd9Sstevel@tonic-gate 45067c478bd9Sstevel@tonic-gate /* 45077c478bd9Sstevel@tonic-gate * our ddi_check_acc_hdl 45087c478bd9Sstevel@tonic-gate */ 45097c478bd9Sstevel@tonic-gate /* ARGSUSED */ 45107c478bd9Sstevel@tonic-gate static int 45117c478bd9Sstevel@tonic-gate bofi_check_acc_hdl(ddi_acc_impl_t *handle) 45127c478bd9Sstevel@tonic-gate { 45137c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 45147c478bd9Sstevel@tonic-gate struct bofi_link *lp; 45157c478bd9Sstevel@tonic-gate uint_t result = 0; 45167c478bd9Sstevel@tonic-gate 45177c478bd9Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 45187c478bd9Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 45197c478bd9Sstevel@tonic-gate return (0); 45207c478bd9Sstevel@tonic-gate } 45217c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 45227c478bd9Sstevel@tonic-gate /* 45237c478bd9Sstevel@tonic-gate * OR in error state from all associated 45247c478bd9Sstevel@tonic-gate * errdef structures 45257c478bd9Sstevel@tonic-gate */ 45267c478bd9Sstevel@tonic-gate if (lp->errentp->errdef.access_count == 0 && 45277c478bd9Sstevel@tonic-gate (lp->errentp->state & BOFI_DEV_ACTIVE)) { 45287c478bd9Sstevel@tonic-gate result = (lp->errentp->errdef.acc_chk & 1); 45297c478bd9Sstevel@tonic-gate } 45307c478bd9Sstevel@tonic-gate } 45317c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 45327c478bd9Sstevel@tonic-gate return (result); 45337c478bd9Sstevel@tonic-gate } 45347c478bd9Sstevel@tonic-gate 45357c478bd9Sstevel@tonic-gate /* 45367c478bd9Sstevel@tonic-gate * our ddi_check_dma_hdl 45377c478bd9Sstevel@tonic-gate */ 45387c478bd9Sstevel@tonic-gate /* ARGSUSED */ 45397c478bd9Sstevel@tonic-gate static int 45407c478bd9Sstevel@tonic-gate bofi_check_dma_hdl(ddi_dma_impl_t *handle) 45417c478bd9Sstevel@tonic-gate { 45427c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 45437c478bd9Sstevel@tonic-gate struct bofi_link *lp; 45447c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 45457c478bd9Sstevel@tonic-gate uint_t result = 0; 45467c478bd9Sstevel@tonic-gate 45477c478bd9Sstevel@tonic-gate if (!mutex_tryenter(&bofi_mutex)) { 45487c478bd9Sstevel@tonic-gate return (0); 45497c478bd9Sstevel@tonic-gate } 45507c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 45517c478bd9Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 45527c478bd9Sstevel@tonic-gate if (hp->hdl.dma_handle == (ddi_dma_handle_t)handle) 45537c478bd9Sstevel@tonic-gate break; 45547c478bd9Sstevel@tonic-gate if (hp == hhashp) { 45557c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 45567c478bd9Sstevel@tonic-gate return (0); 45577c478bd9Sstevel@tonic-gate } 45587c478bd9Sstevel@tonic-gate if (!hp->link) { 45597c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 45607c478bd9Sstevel@tonic-gate return (0); 45617c478bd9Sstevel@tonic-gate } 45627c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 45637c478bd9Sstevel@tonic-gate /* 45647c478bd9Sstevel@tonic-gate * OR in error state from all associated 45657c478bd9Sstevel@tonic-gate * errdef structures 45667c478bd9Sstevel@tonic-gate */ 45677c478bd9Sstevel@tonic-gate if (lp->errentp->errdef.access_count == 0 && 45687c478bd9Sstevel@tonic-gate (lp->errentp->state & BOFI_DEV_ACTIVE)) { 45697c478bd9Sstevel@tonic-gate result = ((lp->errentp->errdef.acc_chk & 2) ? 1 : 0); 45707c478bd9Sstevel@tonic-gate } 45717c478bd9Sstevel@tonic-gate } 45727c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 45737c478bd9Sstevel@tonic-gate return (result); 45747c478bd9Sstevel@tonic-gate } 45757c478bd9Sstevel@tonic-gate 45767c478bd9Sstevel@tonic-gate 45777c478bd9Sstevel@tonic-gate /* ARGSUSED */ 45787c478bd9Sstevel@tonic-gate static int 45797c478bd9Sstevel@tonic-gate bofi_post_event(dev_info_t *dip, dev_info_t *rdip, 45807c478bd9Sstevel@tonic-gate ddi_eventcookie_t eventhdl, void *impl_data) 45817c478bd9Sstevel@tonic-gate { 45827c478bd9Sstevel@tonic-gate ddi_eventcookie_t ec; 45837c478bd9Sstevel@tonic-gate struct ddi_fault_event_data *arg; 45847c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 45857c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 45867c478bd9Sstevel@tonic-gate struct bofi_shadow *dhashp; 45877c478bd9Sstevel@tonic-gate struct bofi_link *lp; 45887c478bd9Sstevel@tonic-gate 45897c478bd9Sstevel@tonic-gate ASSERT(eventhdl); 45907c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dip, DDI_DEVI_FAULT_EVENT, &ec) != DDI_SUCCESS) 45917c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 45927c478bd9Sstevel@tonic-gate 45937c478bd9Sstevel@tonic-gate if (ec != eventhdl) 45947c478bd9Sstevel@tonic-gate return (save_bus_ops.bus_post_event(dip, rdip, eventhdl, 45957c478bd9Sstevel@tonic-gate impl_data)); 45967c478bd9Sstevel@tonic-gate 45977c478bd9Sstevel@tonic-gate arg = (struct ddi_fault_event_data *)impl_data; 45987c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 45997c478bd9Sstevel@tonic-gate /* 46007c478bd9Sstevel@tonic-gate * find shadow handles with appropriate dev_infos 46017c478bd9Sstevel@tonic-gate * and set error reported on all associated errdef structures 46027c478bd9Sstevel@tonic-gate */ 46037c478bd9Sstevel@tonic-gate dhashp = HDL_DHASH(arg->f_dip); 46047c478bd9Sstevel@tonic-gate for (hp = dhashp->dnext; hp != dhashp; hp = hp->dnext) { 46057c478bd9Sstevel@tonic-gate if (hp->dip == arg->f_dip) { 46067c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 46077c478bd9Sstevel@tonic-gate ep = lp->errentp; 46087c478bd9Sstevel@tonic-gate ep->errstate.errmsg_count++; 46097c478bd9Sstevel@tonic-gate if ((ep->errstate.msg_time == NULL || 46107c478bd9Sstevel@tonic-gate ep->errstate.severity > arg->f_impact) && 46117c478bd9Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 46127c478bd9Sstevel@tonic-gate ep->errstate.msg_time = bofi_gettime(); 46137c478bd9Sstevel@tonic-gate ep->errstate.severity = arg->f_impact; 46147c478bd9Sstevel@tonic-gate (void) strncpy(ep->errstate.buffer, 46157c478bd9Sstevel@tonic-gate arg->f_message, ERRMSGSIZE); 46167c478bd9Sstevel@tonic-gate ddi_trigger_softintr(ep->softintr_id); 46177c478bd9Sstevel@tonic-gate } 46187c478bd9Sstevel@tonic-gate } 46197c478bd9Sstevel@tonic-gate } 46207c478bd9Sstevel@tonic-gate } 46217c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 46227c478bd9Sstevel@tonic-gate return (save_bus_ops.bus_post_event(dip, rdip, eventhdl, impl_data)); 46237c478bd9Sstevel@tonic-gate } 46247c478bd9Sstevel@tonic-gate 46257c478bd9Sstevel@tonic-gate /* 46267c478bd9Sstevel@tonic-gate * our intr_ops routine 46277c478bd9Sstevel@tonic-gate */ 46287c478bd9Sstevel@tonic-gate static int 46297c478bd9Sstevel@tonic-gate bofi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 46307c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 46317c478bd9Sstevel@tonic-gate { 46327c478bd9Sstevel@tonic-gate int retval; 46337c478bd9Sstevel@tonic-gate struct bofi_shadow *hp; 46347c478bd9Sstevel@tonic-gate struct bofi_shadow *dhashp; 46357c478bd9Sstevel@tonic-gate struct bofi_shadow *hhashp; 46367c478bd9Sstevel@tonic-gate struct bofi_errent *ep; 46377c478bd9Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 46387c478bd9Sstevel@tonic-gate 46397c478bd9Sstevel@tonic-gate switch (intr_op) { 46407c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 46417c478bd9Sstevel@tonic-gate /* 46427c478bd9Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 46437c478bd9Sstevel@tonic-gate */ 46447c478bd9Sstevel@tonic-gate if (!driver_under_test(rdip)) 46457c478bd9Sstevel@tonic-gate return (save_bus_ops.bus_intr_op(dip, rdip, 46467c478bd9Sstevel@tonic-gate intr_op, hdlp, result)); 46477c478bd9Sstevel@tonic-gate /* 46487c478bd9Sstevel@tonic-gate * allocate shadow handle structure and fill in 46497c478bd9Sstevel@tonic-gate */ 46507c478bd9Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), KM_SLEEP); 46517c478bd9Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 46527c478bd9Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 46537c478bd9Sstevel@tonic-gate hp->save.intr.int_handler = hdlp->ih_cb_func; 46547c478bd9Sstevel@tonic-gate hp->save.intr.int_handler_arg1 = hdlp->ih_cb_arg1; 46557c478bd9Sstevel@tonic-gate hdlp->ih_cb_func = (ddi_intr_handler_t *)bofi_intercept_intr; 46567c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1 = (caddr_t)hp; 46577c478bd9Sstevel@tonic-gate hp->bofi_inum = hdlp->ih_inum; 46587c478bd9Sstevel@tonic-gate hp->dip = rdip; 46597c478bd9Sstevel@tonic-gate hp->link = NULL; 46607c478bd9Sstevel@tonic-gate hp->type = BOFI_INT_HDL; 46617c478bd9Sstevel@tonic-gate /* 46627c478bd9Sstevel@tonic-gate * save whether hilevel or not 46637c478bd9Sstevel@tonic-gate */ 46647c478bd9Sstevel@tonic-gate 46657c478bd9Sstevel@tonic-gate if (hdlp->ih_pri >= ddi_intr_get_hilevel_pri()) 46667c478bd9Sstevel@tonic-gate hp->hilevel = 1; 46677c478bd9Sstevel@tonic-gate else 46687c478bd9Sstevel@tonic-gate hp->hilevel = 0; 46697c478bd9Sstevel@tonic-gate 46707c478bd9Sstevel@tonic-gate /* 46717c478bd9Sstevel@tonic-gate * call nexus to do real work, but specifying our handler, and 46727c478bd9Sstevel@tonic-gate * our shadow handle as argument 46737c478bd9Sstevel@tonic-gate */ 46747c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_intr_op(dip, rdip, 46757c478bd9Sstevel@tonic-gate intr_op, hdlp, result); 46767c478bd9Sstevel@tonic-gate if (retval != DDI_SUCCESS) { 46777c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 46787c478bd9Sstevel@tonic-gate return (retval); 46797c478bd9Sstevel@tonic-gate } 46807c478bd9Sstevel@tonic-gate /* 46817c478bd9Sstevel@tonic-gate * add to dhash, hhash and inuse lists 46827c478bd9Sstevel@tonic-gate */ 46837c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 46847c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 46857c478bd9Sstevel@tonic-gate hp->next = shadow_list.next; 46867c478bd9Sstevel@tonic-gate shadow_list.next->prev = hp; 46877c478bd9Sstevel@tonic-gate hp->prev = &shadow_list; 46887c478bd9Sstevel@tonic-gate shadow_list.next = hp; 46897c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(hdlp->ih_inum); 46907c478bd9Sstevel@tonic-gate hp->hnext = hhashp->hnext; 46917c478bd9Sstevel@tonic-gate hhashp->hnext->hprev = hp; 46927c478bd9Sstevel@tonic-gate hp->hprev = hhashp; 46937c478bd9Sstevel@tonic-gate hhashp->hnext = hp; 46947c478bd9Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 46957c478bd9Sstevel@tonic-gate hp->dnext = dhashp->dnext; 46967c478bd9Sstevel@tonic-gate dhashp->dnext->dprev = hp; 46977c478bd9Sstevel@tonic-gate hp->dprev = dhashp; 46987c478bd9Sstevel@tonic-gate dhashp->dnext = hp; 46997c478bd9Sstevel@tonic-gate /* 47007c478bd9Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 47017c478bd9Sstevel@tonic-gate * acc_handle 47027c478bd9Sstevel@tonic-gate */ 47037c478bd9Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 47047c478bd9Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 47057c478bd9Sstevel@tonic-gate ddi_name_to_major(ep->name) && 47067c478bd9Sstevel@tonic-gate hp->instance == ep->errdef.instance && 47077c478bd9Sstevel@tonic-gate (ep->errdef.access_type & BOFI_INTR)) { 47087c478bd9Sstevel@tonic-gate lp = bofi_link_freelist; 47097c478bd9Sstevel@tonic-gate if (lp != NULL) { 47107c478bd9Sstevel@tonic-gate bofi_link_freelist = lp->link; 47117c478bd9Sstevel@tonic-gate lp->errentp = ep; 47127c478bd9Sstevel@tonic-gate lp->link = hp->link; 47137c478bd9Sstevel@tonic-gate hp->link = lp; 47147c478bd9Sstevel@tonic-gate } 47157c478bd9Sstevel@tonic-gate } 47167c478bd9Sstevel@tonic-gate } 47177c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 47187c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 47197c478bd9Sstevel@tonic-gate return (retval); 47207c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 47217c478bd9Sstevel@tonic-gate /* 47227c478bd9Sstevel@tonic-gate * call nexus routine first 47237c478bd9Sstevel@tonic-gate */ 47247c478bd9Sstevel@tonic-gate retval = save_bus_ops.bus_intr_op(dip, rdip, 47257c478bd9Sstevel@tonic-gate intr_op, hdlp, result); 47267c478bd9Sstevel@tonic-gate /* 47277c478bd9Sstevel@tonic-gate * find shadow handle 47287c478bd9Sstevel@tonic-gate */ 47297c478bd9Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 47307c478bd9Sstevel@tonic-gate mutex_enter(&bofi_mutex); 47317c478bd9Sstevel@tonic-gate hhashp = HDL_HHASH(hdlp->ih_inum); 47327c478bd9Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) { 47337c478bd9Sstevel@tonic-gate if (hp->dip == rdip && 47347c478bd9Sstevel@tonic-gate hp->type == BOFI_INT_HDL && 47357c478bd9Sstevel@tonic-gate hp->bofi_inum == hdlp->ih_inum) { 47367c478bd9Sstevel@tonic-gate break; 47377c478bd9Sstevel@tonic-gate } 47387c478bd9Sstevel@tonic-gate } 47397c478bd9Sstevel@tonic-gate if (hp == hhashp) { 47407c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 47417c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 47427c478bd9Sstevel@tonic-gate return (retval); 47437c478bd9Sstevel@tonic-gate } 47447c478bd9Sstevel@tonic-gate /* 47457c478bd9Sstevel@tonic-gate * found one - remove from dhash, hhash and inuse lists 47467c478bd9Sstevel@tonic-gate */ 47477c478bd9Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 47487c478bd9Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 47497c478bd9Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 47507c478bd9Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 47517c478bd9Sstevel@tonic-gate hp->next->prev = hp->prev; 47527c478bd9Sstevel@tonic-gate hp->prev->next = hp->next; 47537c478bd9Sstevel@tonic-gate /* 47547c478bd9Sstevel@tonic-gate * free any errdef link structures 47557c478bd9Sstevel@tonic-gate * tagged on to this shadow handle 47567c478bd9Sstevel@tonic-gate */ 47577c478bd9Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 47587c478bd9Sstevel@tonic-gate next_lp = lp->link; 47597c478bd9Sstevel@tonic-gate lp->link = bofi_link_freelist; 47607c478bd9Sstevel@tonic-gate bofi_link_freelist = lp; 47617c478bd9Sstevel@tonic-gate lp = next_lp; 47627c478bd9Sstevel@tonic-gate } 47637c478bd9Sstevel@tonic-gate hp->link = NULL; 47647c478bd9Sstevel@tonic-gate mutex_exit(&bofi_mutex); 47657c478bd9Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 47667c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 47677c478bd9Sstevel@tonic-gate return (retval); 47687c478bd9Sstevel@tonic-gate default: 47697c478bd9Sstevel@tonic-gate return (save_bus_ops.bus_intr_op(dip, rdip, 47707c478bd9Sstevel@tonic-gate intr_op, hdlp, result)); 47717c478bd9Sstevel@tonic-gate } 47727c478bd9Sstevel@tonic-gate } 4773