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