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