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