10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51865Sdilpreet * Common Development and Distribution License (the "License"). 61865Sdilpreet * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate 270Sstevel@tonic-gate #include <sys/types.h> 280Sstevel@tonic-gate #include <sys/sysmacros.h> 290Sstevel@tonic-gate #include <sys/buf.h> 300Sstevel@tonic-gate #include <sys/errno.h> 310Sstevel@tonic-gate #include <sys/modctl.h> 320Sstevel@tonic-gate #include <sys/conf.h> 330Sstevel@tonic-gate #include <sys/stat.h> 340Sstevel@tonic-gate #include <sys/kmem.h> 350Sstevel@tonic-gate #include <sys/proc.h> 360Sstevel@tonic-gate #include <sys/cpuvar.h> 370Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 380Sstevel@tonic-gate #include <sys/ddi.h> 391865Sdilpreet #include <sys/fm/protocol.h> 401865Sdilpreet #include <sys/fm/util.h> 411865Sdilpreet #include <sys/fm/io/ddi.h> 421865Sdilpreet #include <sys/sysevent/eventdefs.h> 430Sstevel@tonic-gate #include <sys/sunddi.h> 440Sstevel@tonic-gate #include <sys/sunndi.h> 450Sstevel@tonic-gate #include <sys/debug.h> 460Sstevel@tonic-gate #include <sys/bofi.h> 470Sstevel@tonic-gate #include <sys/dvma.h> 480Sstevel@tonic-gate #include <sys/bofi_impl.h> 490Sstevel@tonic-gate 500Sstevel@tonic-gate /* 510Sstevel@tonic-gate * Testing the resilience of a hardened device driver requires a suitably wide 520Sstevel@tonic-gate * range of different types of "typical" hardware faults to be injected, 530Sstevel@tonic-gate * preferably in a controlled and repeatable fashion. This is not in general 540Sstevel@tonic-gate * possible via hardware, so the "fault injection test harness" is provided. 550Sstevel@tonic-gate * This works by intercepting calls from the driver to various DDI routines, 560Sstevel@tonic-gate * and then corrupting the result of those DDI routine calls as if the 570Sstevel@tonic-gate * hardware had caused the corruption. 580Sstevel@tonic-gate * 590Sstevel@tonic-gate * Conceptually, the bofi driver consists of two parts: 600Sstevel@tonic-gate * 610Sstevel@tonic-gate * A driver interface that supports a number of ioctls which allow error 620Sstevel@tonic-gate * definitions ("errdefs") to be defined and subsequently managed. The 630Sstevel@tonic-gate * driver is a clone driver, so each open will create a separate 640Sstevel@tonic-gate * invocation. Any errdefs created by using ioctls to that invocation 650Sstevel@tonic-gate * will automatically be deleted when that invocation is closed. 660Sstevel@tonic-gate * 670Sstevel@tonic-gate * Intercept routines: When the bofi driver is attached, it edits the 680Sstevel@tonic-gate * bus_ops structure of the bus nexus specified by the "bofi-nexus" 690Sstevel@tonic-gate * field in the "bofi.conf" file, thus allowing the 700Sstevel@tonic-gate * bofi driver to intercept various ddi functions. These intercept 710Sstevel@tonic-gate * routines primarily carry out fault injections based on the errdefs 720Sstevel@tonic-gate * created for that device. 730Sstevel@tonic-gate * 740Sstevel@tonic-gate * Faults can be injected into: 750Sstevel@tonic-gate * 760Sstevel@tonic-gate * DMA (corrupting data for DMA to/from memory areas defined by 770Sstevel@tonic-gate * ddi_dma_setup(), ddi_dma_bind_handle(), etc) 780Sstevel@tonic-gate * 790Sstevel@tonic-gate * Physical IO (corrupting data sent/received via ddi_get8(), ddi_put8(), 800Sstevel@tonic-gate * etc), 810Sstevel@tonic-gate * 820Sstevel@tonic-gate * Interrupts (generating spurious interrupts, losing interrupts, 830Sstevel@tonic-gate * delaying interrupts). 840Sstevel@tonic-gate * 850Sstevel@tonic-gate * By default, ddi routines called from all drivers will be intercepted 860Sstevel@tonic-gate * and faults potentially injected. However, the "bofi-to-test" field in 870Sstevel@tonic-gate * the "bofi.conf" file can be set to a space-separated list of drivers to 880Sstevel@tonic-gate * test (or by preceding each driver name in the list with an "!", a list 890Sstevel@tonic-gate * of drivers not to test). 900Sstevel@tonic-gate * 910Sstevel@tonic-gate * In addition to fault injection, the bofi driver does a number of static 920Sstevel@tonic-gate * checks which are controlled by properties in the "bofi.conf" file. 930Sstevel@tonic-gate * 940Sstevel@tonic-gate * "bofi-ddi-check" - if set will validate that there are no PIO access 950Sstevel@tonic-gate * other than those using the DDI routines (ddi_get8(), ddi_put8(), etc). 960Sstevel@tonic-gate * 970Sstevel@tonic-gate * "bofi-range-check" - if set to values 1 (warning) or 2 (panic), will 980Sstevel@tonic-gate * validate that calls to ddi_get8(), ddi_put8(), etc are not made 990Sstevel@tonic-gate * specifying addresses outside the range of the access_handle. 1000Sstevel@tonic-gate * 1010Sstevel@tonic-gate * "bofi-sync-check" - if set will validate that calls to ddi_dma_sync() 1020Sstevel@tonic-gate * are being made correctly. 1030Sstevel@tonic-gate */ 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate extern void *bp_mapin_common(struct buf *, int); 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate static int bofi_ddi_check; 1080Sstevel@tonic-gate static int bofi_sync_check; 1090Sstevel@tonic-gate static int bofi_range_check; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate static struct bofi_link bofi_link_array[BOFI_NLINKS], *bofi_link_freelist; 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate #define LLSZMASK (sizeof (uint64_t)-1) 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate #define HDL_HASH_TBL_SIZE 64 1160Sstevel@tonic-gate static struct bofi_shadow hhash_table[HDL_HASH_TBL_SIZE]; 1170Sstevel@tonic-gate static struct bofi_shadow dhash_table[HDL_HASH_TBL_SIZE]; 1180Sstevel@tonic-gate #define HDL_DHASH(x) \ 1190Sstevel@tonic-gate (&dhash_table[((uintptr_t)(x) >> 3) & (HDL_HASH_TBL_SIZE-1)]) 1200Sstevel@tonic-gate #define HDL_HHASH(x) \ 1210Sstevel@tonic-gate (&hhash_table[((uintptr_t)(x) >> 5) & (HDL_HASH_TBL_SIZE-1)]) 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate static struct bofi_shadow shadow_list; 1240Sstevel@tonic-gate static struct bofi_errent *errent_listp; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate static char driver_list[NAMESIZE]; 1270Sstevel@tonic-gate static int driver_list_size; 1280Sstevel@tonic-gate static int driver_list_neg; 1290Sstevel@tonic-gate static char nexus_name[NAMESIZE]; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate static int initialized = 0; 1320Sstevel@tonic-gate 1335204Sstephh #define NCLONES 2560 1340Sstevel@tonic-gate static int clone_tab[NCLONES]; 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate static dev_info_t *our_dip; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate static kmutex_t bofi_mutex; 1390Sstevel@tonic-gate static kmutex_t clone_tab_mutex; 1400Sstevel@tonic-gate static kmutex_t bofi_low_mutex; 1410Sstevel@tonic-gate static ddi_iblock_cookie_t bofi_low_cookie; 1420Sstevel@tonic-gate static uint_t bofi_signal(caddr_t arg); 1430Sstevel@tonic-gate static int bofi_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 1440Sstevel@tonic-gate static int bofi_attach(dev_info_t *, ddi_attach_cmd_t); 1450Sstevel@tonic-gate static int bofi_detach(dev_info_t *, ddi_detach_cmd_t); 1460Sstevel@tonic-gate static int bofi_open(dev_t *, int, int, cred_t *); 1470Sstevel@tonic-gate static int bofi_close(dev_t, int, int, cred_t *); 1480Sstevel@tonic-gate static int bofi_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1490Sstevel@tonic-gate static int bofi_errdef_alloc(struct bofi_errdef *, char *, 1500Sstevel@tonic-gate struct bofi_errent *); 1510Sstevel@tonic-gate static int bofi_errdef_free(struct bofi_errent *); 1520Sstevel@tonic-gate static void bofi_start(struct bofi_errctl *, char *); 1530Sstevel@tonic-gate static void bofi_stop(struct bofi_errctl *, char *); 1540Sstevel@tonic-gate static void bofi_broadcast(struct bofi_errctl *, char *); 1550Sstevel@tonic-gate static void bofi_clear_acc_chk(struct bofi_errctl *, char *); 1560Sstevel@tonic-gate static void bofi_clear_errors(struct bofi_errctl *, char *); 1570Sstevel@tonic-gate static void bofi_clear_errdefs(struct bofi_errctl *, char *); 1580Sstevel@tonic-gate static int bofi_errdef_check(struct bofi_errstate *, 1590Sstevel@tonic-gate struct acc_log_elem **); 1600Sstevel@tonic-gate static int bofi_errdef_check_w(struct bofi_errstate *, 1610Sstevel@tonic-gate struct acc_log_elem **); 1620Sstevel@tonic-gate static int bofi_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 1630Sstevel@tonic-gate off_t, off_t, caddr_t *); 1640Sstevel@tonic-gate static int bofi_dma_map(dev_info_t *, dev_info_t *, 1650Sstevel@tonic-gate struct ddi_dma_req *, ddi_dma_handle_t *); 1660Sstevel@tonic-gate static int bofi_dma_allochdl(dev_info_t *, dev_info_t *, 1670Sstevel@tonic-gate ddi_dma_attr_t *, int (*)(caddr_t), caddr_t, 1680Sstevel@tonic-gate ddi_dma_handle_t *); 1690Sstevel@tonic-gate static int bofi_dma_freehdl(dev_info_t *, dev_info_t *, 1700Sstevel@tonic-gate ddi_dma_handle_t); 1710Sstevel@tonic-gate static int bofi_dma_bindhdl(dev_info_t *, dev_info_t *, 1720Sstevel@tonic-gate ddi_dma_handle_t, struct ddi_dma_req *, ddi_dma_cookie_t *, 1730Sstevel@tonic-gate uint_t *); 1740Sstevel@tonic-gate static int bofi_dma_unbindhdl(dev_info_t *, dev_info_t *, 1750Sstevel@tonic-gate ddi_dma_handle_t); 1760Sstevel@tonic-gate static int bofi_dma_flush(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 1770Sstevel@tonic-gate off_t, size_t, uint_t); 1780Sstevel@tonic-gate static int bofi_dma_ctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 1790Sstevel@tonic-gate enum ddi_dma_ctlops, off_t *, size_t *, caddr_t *, uint_t); 1800Sstevel@tonic-gate static int bofi_dma_win(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 1810Sstevel@tonic-gate uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *); 1820Sstevel@tonic-gate static int bofi_intr_ops(dev_info_t *dip, dev_info_t *rdip, 1830Sstevel@tonic-gate ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, 1840Sstevel@tonic-gate void *result); 1851865Sdilpreet static int bofi_fm_ereport_callback(sysevent_t *ev, void *cookie); 1861865Sdilpreet 1871865Sdilpreet evchan_t *bofi_error_chan; 1881865Sdilpreet 1891865Sdilpreet #define FM_SIMULATED_DMA "simulated.dma" 1901865Sdilpreet #define FM_SIMULATED_PIO "simulated.pio" 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate #if defined(__sparc) 1930Sstevel@tonic-gate static void bofi_dvma_kaddr_load(ddi_dma_handle_t, caddr_t, uint_t, 1940Sstevel@tonic-gate uint_t, ddi_dma_cookie_t *); 1950Sstevel@tonic-gate static void bofi_dvma_unload(ddi_dma_handle_t, uint_t, uint_t); 1960Sstevel@tonic-gate static void bofi_dvma_sync(ddi_dma_handle_t, uint_t, uint_t); 1970Sstevel@tonic-gate static void bofi_dvma_reserve(dev_info_t *, ddi_dma_handle_t); 1980Sstevel@tonic-gate #endif 1990Sstevel@tonic-gate static int driver_under_test(dev_info_t *); 2000Sstevel@tonic-gate static int bofi_check_acc_hdl(ddi_acc_impl_t *); 2010Sstevel@tonic-gate static int bofi_check_dma_hdl(ddi_dma_impl_t *); 2020Sstevel@tonic-gate static int bofi_post_event(dev_info_t *dip, dev_info_t *rdip, 2030Sstevel@tonic-gate ddi_eventcookie_t eventhdl, void *impl_data); 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate static struct bus_ops bofi_bus_ops = { 2060Sstevel@tonic-gate BUSO_REV, 2070Sstevel@tonic-gate bofi_map, 2080Sstevel@tonic-gate NULL, 2090Sstevel@tonic-gate NULL, 2100Sstevel@tonic-gate NULL, 2110Sstevel@tonic-gate i_ddi_map_fault, 2120Sstevel@tonic-gate bofi_dma_map, 2130Sstevel@tonic-gate bofi_dma_allochdl, 2140Sstevel@tonic-gate bofi_dma_freehdl, 2150Sstevel@tonic-gate bofi_dma_bindhdl, 2160Sstevel@tonic-gate bofi_dma_unbindhdl, 2170Sstevel@tonic-gate bofi_dma_flush, 2180Sstevel@tonic-gate bofi_dma_win, 2190Sstevel@tonic-gate bofi_dma_ctl, 2200Sstevel@tonic-gate NULL, 2210Sstevel@tonic-gate ddi_bus_prop_op, 2220Sstevel@tonic-gate ndi_busop_get_eventcookie, 2230Sstevel@tonic-gate ndi_busop_add_eventcall, 2240Sstevel@tonic-gate ndi_busop_remove_eventcall, 2250Sstevel@tonic-gate bofi_post_event, 2260Sstevel@tonic-gate NULL, 2270Sstevel@tonic-gate 0, 2280Sstevel@tonic-gate 0, 2290Sstevel@tonic-gate 0, 2300Sstevel@tonic-gate 0, 2310Sstevel@tonic-gate 0, 2320Sstevel@tonic-gate 0, 2330Sstevel@tonic-gate 0, 2340Sstevel@tonic-gate bofi_intr_ops 2350Sstevel@tonic-gate }; 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate static struct cb_ops bofi_cb_ops = { 238258Scth bofi_open, /* open */ 239258Scth bofi_close, /* close */ 240258Scth nodev, /* strategy */ 241258Scth nodev, /* print */ 2420Sstevel@tonic-gate nodev, /* dump */ 243258Scth nodev, /* read */ 244258Scth nodev, /* write */ 245258Scth bofi_ioctl, /* ioctl */ 2460Sstevel@tonic-gate nodev, /* devmap */ 247258Scth nodev, /* mmap */ 2480Sstevel@tonic-gate nodev, /* segmap */ 249258Scth nochpoll, /* chpoll */ 250258Scth ddi_prop_op, /* prop_op */ 2510Sstevel@tonic-gate NULL, /* for STREAMS drivers */ 252258Scth D_MP, /* driver compatibility flag */ 253258Scth CB_REV, /* cb_ops revision */ 254258Scth nodev, /* aread */ 255258Scth nodev /* awrite */ 2560Sstevel@tonic-gate }; 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate static struct dev_ops bofi_ops = { 2590Sstevel@tonic-gate DEVO_REV, /* driver build version */ 2600Sstevel@tonic-gate 0, /* device reference count */ 2610Sstevel@tonic-gate bofi_getinfo, 2620Sstevel@tonic-gate nulldev, 2630Sstevel@tonic-gate nulldev, /* probe */ 2640Sstevel@tonic-gate bofi_attach, 2650Sstevel@tonic-gate bofi_detach, 2660Sstevel@tonic-gate nulldev, /* reset */ 2670Sstevel@tonic-gate &bofi_cb_ops, 2680Sstevel@tonic-gate (struct bus_ops *)NULL, 269*7656SSherry.Moore@Sun.COM nulldev, /* power */ 270*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 2710Sstevel@tonic-gate }; 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* module configuration stuff */ 2740Sstevel@tonic-gate static void *statep; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate static struct modldrv modldrv = { 2770Sstevel@tonic-gate &mod_driverops, 278*7656SSherry.Moore@Sun.COM "bofi driver", 2790Sstevel@tonic-gate &bofi_ops 2800Sstevel@tonic-gate }; 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate static struct modlinkage modlinkage = { 2830Sstevel@tonic-gate MODREV_1, 2840Sstevel@tonic-gate &modldrv, 2850Sstevel@tonic-gate 0 2860Sstevel@tonic-gate }; 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate static struct bus_ops save_bus_ops; 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate #if defined(__sparc) 2910Sstevel@tonic-gate static struct dvma_ops bofi_dvma_ops = { 2920Sstevel@tonic-gate DVMAO_REV, 2930Sstevel@tonic-gate bofi_dvma_kaddr_load, 2940Sstevel@tonic-gate bofi_dvma_unload, 2950Sstevel@tonic-gate bofi_dvma_sync 2960Sstevel@tonic-gate }; 2970Sstevel@tonic-gate #endif 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate /* 3000Sstevel@tonic-gate * support routine - map user page into kernel virtual 3010Sstevel@tonic-gate */ 3020Sstevel@tonic-gate static caddr_t 3030Sstevel@tonic-gate dmareq_mapin(offset_t len, caddr_t addr, struct as *as, int flag) 3040Sstevel@tonic-gate { 3050Sstevel@tonic-gate struct buf buf; 3060Sstevel@tonic-gate struct proc proc; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate /* 3090Sstevel@tonic-gate * mock up a buf structure so we can call bp_mapin_common() 3100Sstevel@tonic-gate */ 3110Sstevel@tonic-gate buf.b_flags = B_PHYS; 3120Sstevel@tonic-gate buf.b_un.b_addr = (caddr_t)addr; 3130Sstevel@tonic-gate buf.b_bcount = (size_t)len; 3140Sstevel@tonic-gate proc.p_as = as; 3150Sstevel@tonic-gate buf.b_proc = &proc; 3160Sstevel@tonic-gate return (bp_mapin_common(&buf, flag)); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate /* 3210Sstevel@tonic-gate * support routine - map page chain into kernel virtual 3220Sstevel@tonic-gate */ 3230Sstevel@tonic-gate static caddr_t 3240Sstevel@tonic-gate dmareq_pp_mapin(offset_t len, uint_t offset, page_t *pp, int flag) 3250Sstevel@tonic-gate { 3260Sstevel@tonic-gate struct buf buf; 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* 3290Sstevel@tonic-gate * mock up a buf structure so we can call bp_mapin_common() 3300Sstevel@tonic-gate */ 3310Sstevel@tonic-gate buf.b_flags = B_PAGEIO; 3320Sstevel@tonic-gate buf.b_un.b_addr = (caddr_t)(uintptr_t)offset; 3330Sstevel@tonic-gate buf.b_bcount = (size_t)len; 3340Sstevel@tonic-gate buf.b_pages = pp; 3350Sstevel@tonic-gate return (bp_mapin_common(&buf, flag)); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate /* 3400Sstevel@tonic-gate * support routine - map page array into kernel virtual 3410Sstevel@tonic-gate */ 3420Sstevel@tonic-gate static caddr_t 3430Sstevel@tonic-gate dmareq_pplist_mapin(uint_t len, caddr_t addr, page_t **pplist, struct as *as, 3440Sstevel@tonic-gate int flag) 3450Sstevel@tonic-gate { 3460Sstevel@tonic-gate struct buf buf; 3470Sstevel@tonic-gate struct proc proc; 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate /* 3500Sstevel@tonic-gate * mock up a buf structure so we can call bp_mapin_common() 3510Sstevel@tonic-gate */ 3520Sstevel@tonic-gate buf.b_flags = B_PHYS|B_SHADOW; 3530Sstevel@tonic-gate buf.b_un.b_addr = addr; 3540Sstevel@tonic-gate buf.b_bcount = len; 3550Sstevel@tonic-gate buf.b_shadow = pplist; 3560Sstevel@tonic-gate proc.p_as = as; 3570Sstevel@tonic-gate buf.b_proc = &proc; 3580Sstevel@tonic-gate return (bp_mapin_common(&buf, flag)); 3590Sstevel@tonic-gate } 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate /* 3630Sstevel@tonic-gate * support routine - map dmareq into kernel virtual if not already 3640Sstevel@tonic-gate * fills in *lenp with length 3650Sstevel@tonic-gate * *mapaddr will be new kernel virtual address - or null if no mapping needed 3660Sstevel@tonic-gate */ 3670Sstevel@tonic-gate static caddr_t 3680Sstevel@tonic-gate ddi_dmareq_mapin(struct ddi_dma_req *dmareqp, caddr_t *mapaddrp, 3690Sstevel@tonic-gate offset_t *lenp) 3700Sstevel@tonic-gate { 3710Sstevel@tonic-gate int sleep = (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? VM_SLEEP: VM_NOSLEEP; 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate *lenp = dmareqp->dmar_object.dmao_size; 3740Sstevel@tonic-gate if (dmareqp->dmar_object.dmao_type == DMA_OTYP_PAGES) { 3750Sstevel@tonic-gate *mapaddrp = dmareq_pp_mapin(dmareqp->dmar_object.dmao_size, 3760Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.pp_obj.pp_offset, 3770Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.pp_obj.pp_pp, sleep); 3780Sstevel@tonic-gate return (*mapaddrp); 3790Sstevel@tonic-gate } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_priv != NULL) { 3800Sstevel@tonic-gate *mapaddrp = dmareq_pplist_mapin(dmareqp->dmar_object.dmao_size, 3810Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_addr, 3820Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_priv, 3830Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_as, sleep); 3840Sstevel@tonic-gate return (*mapaddrp); 3850Sstevel@tonic-gate } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_as == &kas) { 3860Sstevel@tonic-gate *mapaddrp = NULL; 3870Sstevel@tonic-gate return (dmareqp->dmar_object.dmao_obj.virt_obj.v_addr); 3880Sstevel@tonic-gate } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_as == NULL) { 3890Sstevel@tonic-gate *mapaddrp = NULL; 3900Sstevel@tonic-gate return (dmareqp->dmar_object.dmao_obj.virt_obj.v_addr); 3910Sstevel@tonic-gate } else { 3920Sstevel@tonic-gate *mapaddrp = dmareq_mapin(dmareqp->dmar_object.dmao_size, 3930Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_addr, 3940Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_as, sleep); 3950Sstevel@tonic-gate return (*mapaddrp); 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate /* 4010Sstevel@tonic-gate * support routine - free off kernel virtual mapping as allocated by 4020Sstevel@tonic-gate * ddi_dmareq_mapin() 4030Sstevel@tonic-gate */ 4040Sstevel@tonic-gate static void 4053971Sstephh ddi_dmareq_mapout(caddr_t addr, offset_t len, int map_flags, page_t *pp, 4063971Sstephh page_t **pplist) 4070Sstevel@tonic-gate { 4080Sstevel@tonic-gate struct buf buf; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate if (addr == NULL) 4110Sstevel@tonic-gate return; 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * mock up a buf structure 4140Sstevel@tonic-gate */ 4153971Sstephh buf.b_flags = B_REMAPPED | map_flags; 4160Sstevel@tonic-gate buf.b_un.b_addr = addr; 4170Sstevel@tonic-gate buf.b_bcount = (size_t)len; 4183971Sstephh buf.b_pages = pp; 4193971Sstephh buf.b_shadow = pplist; 4200Sstevel@tonic-gate bp_mapout(&buf); 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate static time_t 4240Sstevel@tonic-gate bofi_gettime() 4250Sstevel@tonic-gate { 4260Sstevel@tonic-gate timestruc_t ts; 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate gethrestime(&ts); 4290Sstevel@tonic-gate return (ts.tv_sec); 4300Sstevel@tonic-gate } 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate /* 4330Sstevel@tonic-gate * reset the bus_ops structure of the specified nexus to point to 4340Sstevel@tonic-gate * the original values in the save_bus_ops structure. 4350Sstevel@tonic-gate * 4360Sstevel@tonic-gate * Note that both this routine and modify_bus_ops() rely on the current 4370Sstevel@tonic-gate * behavior of the framework in that nexus drivers are not unloadable 4380Sstevel@tonic-gate * 4390Sstevel@tonic-gate */ 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate static int 4420Sstevel@tonic-gate reset_bus_ops(char *name, struct bus_ops *bop) 4430Sstevel@tonic-gate { 4440Sstevel@tonic-gate struct modctl *modp; 4450Sstevel@tonic-gate struct modldrv *mp; 4460Sstevel@tonic-gate struct bus_ops *bp; 4470Sstevel@tonic-gate struct dev_ops *ops; 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate mutex_enter(&mod_lock); 4500Sstevel@tonic-gate /* 4510Sstevel@tonic-gate * find specified module 4520Sstevel@tonic-gate */ 4530Sstevel@tonic-gate modp = &modules; 4540Sstevel@tonic-gate do { 4550Sstevel@tonic-gate if (strcmp(name, modp->mod_modname) == 0) { 4560Sstevel@tonic-gate if (!modp->mod_linkage) { 4570Sstevel@tonic-gate mutex_exit(&mod_lock); 4580Sstevel@tonic-gate return (0); 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate mp = modp->mod_linkage->ml_linkage[0]; 4610Sstevel@tonic-gate if (!mp || !mp->drv_dev_ops) { 4620Sstevel@tonic-gate mutex_exit(&mod_lock); 4630Sstevel@tonic-gate return (0); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate ops = mp->drv_dev_ops; 4660Sstevel@tonic-gate bp = ops->devo_bus_ops; 4670Sstevel@tonic-gate if (!bp) { 4680Sstevel@tonic-gate mutex_exit(&mod_lock); 4690Sstevel@tonic-gate return (0); 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate if (ops->devo_refcnt > 0) { 4720Sstevel@tonic-gate /* 4730Sstevel@tonic-gate * As long as devices are active with modified 4740Sstevel@tonic-gate * bus ops bofi must not go away. There may be 4750Sstevel@tonic-gate * drivers with modified access or dma handles. 4760Sstevel@tonic-gate */ 4770Sstevel@tonic-gate mutex_exit(&mod_lock); 4780Sstevel@tonic-gate return (0); 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate cmn_err(CE_NOTE, "bofi reset bus_ops for %s", 4810Sstevel@tonic-gate mp->drv_linkinfo); 4820Sstevel@tonic-gate bp->bus_intr_op = bop->bus_intr_op; 4830Sstevel@tonic-gate bp->bus_post_event = bop->bus_post_event; 4840Sstevel@tonic-gate bp->bus_map = bop->bus_map; 4850Sstevel@tonic-gate bp->bus_dma_map = bop->bus_dma_map; 4860Sstevel@tonic-gate bp->bus_dma_allochdl = bop->bus_dma_allochdl; 4870Sstevel@tonic-gate bp->bus_dma_freehdl = bop->bus_dma_freehdl; 4880Sstevel@tonic-gate bp->bus_dma_bindhdl = bop->bus_dma_bindhdl; 4890Sstevel@tonic-gate bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl; 4900Sstevel@tonic-gate bp->bus_dma_flush = bop->bus_dma_flush; 4910Sstevel@tonic-gate bp->bus_dma_win = bop->bus_dma_win; 4920Sstevel@tonic-gate bp->bus_dma_ctl = bop->bus_dma_ctl; 4930Sstevel@tonic-gate mutex_exit(&mod_lock); 4940Sstevel@tonic-gate return (1); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules); 4970Sstevel@tonic-gate mutex_exit(&mod_lock); 4980Sstevel@tonic-gate return (0); 4990Sstevel@tonic-gate } 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate /* 5020Sstevel@tonic-gate * modify the bus_ops structure of the specified nexus to point to bofi 5030Sstevel@tonic-gate * routines, saving the original values in the save_bus_ops structure 5040Sstevel@tonic-gate */ 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate static int 5070Sstevel@tonic-gate modify_bus_ops(char *name, struct bus_ops *bop) 5080Sstevel@tonic-gate { 5090Sstevel@tonic-gate struct modctl *modp; 5100Sstevel@tonic-gate struct modldrv *mp; 5110Sstevel@tonic-gate struct bus_ops *bp; 5120Sstevel@tonic-gate struct dev_ops *ops; 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate if (ddi_name_to_major(name) == -1) 5150Sstevel@tonic-gate return (0); 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate mutex_enter(&mod_lock); 5180Sstevel@tonic-gate /* 5190Sstevel@tonic-gate * find specified module 5200Sstevel@tonic-gate */ 5210Sstevel@tonic-gate modp = &modules; 5220Sstevel@tonic-gate do { 5230Sstevel@tonic-gate if (strcmp(name, modp->mod_modname) == 0) { 5240Sstevel@tonic-gate if (!modp->mod_linkage) { 5250Sstevel@tonic-gate mutex_exit(&mod_lock); 5260Sstevel@tonic-gate return (0); 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate mp = modp->mod_linkage->ml_linkage[0]; 5290Sstevel@tonic-gate if (!mp || !mp->drv_dev_ops) { 5300Sstevel@tonic-gate mutex_exit(&mod_lock); 5310Sstevel@tonic-gate return (0); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate ops = mp->drv_dev_ops; 5340Sstevel@tonic-gate bp = ops->devo_bus_ops; 5350Sstevel@tonic-gate if (!bp) { 5360Sstevel@tonic-gate mutex_exit(&mod_lock); 5370Sstevel@tonic-gate return (0); 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate if (ops->devo_refcnt == 0) { 5400Sstevel@tonic-gate /* 5410Sstevel@tonic-gate * If there is no device active for this 5420Sstevel@tonic-gate * module then there is nothing to do for bofi. 5430Sstevel@tonic-gate */ 5440Sstevel@tonic-gate mutex_exit(&mod_lock); 5450Sstevel@tonic-gate return (0); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate cmn_err(CE_NOTE, "bofi modify bus_ops for %s", 5480Sstevel@tonic-gate mp->drv_linkinfo); 5490Sstevel@tonic-gate save_bus_ops = *bp; 5500Sstevel@tonic-gate bp->bus_intr_op = bop->bus_intr_op; 5510Sstevel@tonic-gate bp->bus_post_event = bop->bus_post_event; 5520Sstevel@tonic-gate bp->bus_map = bop->bus_map; 5530Sstevel@tonic-gate bp->bus_dma_map = bop->bus_dma_map; 5540Sstevel@tonic-gate bp->bus_dma_allochdl = bop->bus_dma_allochdl; 5550Sstevel@tonic-gate bp->bus_dma_freehdl = bop->bus_dma_freehdl; 5560Sstevel@tonic-gate bp->bus_dma_bindhdl = bop->bus_dma_bindhdl; 5570Sstevel@tonic-gate bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl; 5580Sstevel@tonic-gate bp->bus_dma_flush = bop->bus_dma_flush; 5590Sstevel@tonic-gate bp->bus_dma_win = bop->bus_dma_win; 5600Sstevel@tonic-gate bp->bus_dma_ctl = bop->bus_dma_ctl; 5610Sstevel@tonic-gate mutex_exit(&mod_lock); 5620Sstevel@tonic-gate return (1); 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules); 5650Sstevel@tonic-gate mutex_exit(&mod_lock); 5660Sstevel@tonic-gate return (0); 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate int 5710Sstevel@tonic-gate _init(void) 5720Sstevel@tonic-gate { 5730Sstevel@tonic-gate int e; 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate e = ddi_soft_state_init(&statep, sizeof (struct bofi_errent), 1); 5760Sstevel@tonic-gate if (e != 0) 5770Sstevel@tonic-gate return (e); 5780Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) 5790Sstevel@tonic-gate ddi_soft_state_fini(&statep); 5800Sstevel@tonic-gate return (e); 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate int 5850Sstevel@tonic-gate _fini(void) 5860Sstevel@tonic-gate { 5870Sstevel@tonic-gate int e; 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) != 0) 5900Sstevel@tonic-gate return (e); 5910Sstevel@tonic-gate ddi_soft_state_fini(&statep); 5920Sstevel@tonic-gate return (e); 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate int 5970Sstevel@tonic-gate _info(struct modinfo *modinfop) 5980Sstevel@tonic-gate { 5990Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate static int 6040Sstevel@tonic-gate bofi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 6050Sstevel@tonic-gate { 6060Sstevel@tonic-gate char *name; 6070Sstevel@tonic-gate char buf[80]; 6080Sstevel@tonic-gate int i; 6090Sstevel@tonic-gate int s, ss; 6100Sstevel@tonic-gate int size = NAMESIZE; 6110Sstevel@tonic-gate int new_string; 6120Sstevel@tonic-gate char *ptr; 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate if (cmd != DDI_ATTACH) 6150Sstevel@tonic-gate return (DDI_FAILURE); 6160Sstevel@tonic-gate /* 6170Sstevel@tonic-gate * only one instance - but we clone using the open routine 6180Sstevel@tonic-gate */ 6190Sstevel@tonic-gate if (ddi_get_instance(dip) > 0) 6200Sstevel@tonic-gate return (DDI_FAILURE); 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate if (!initialized) { 6230Sstevel@tonic-gate if ((name = ddi_get_name(dip)) == NULL) 6240Sstevel@tonic-gate return (DDI_FAILURE); 6250Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s,ctl", name); 6260Sstevel@tonic-gate if (ddi_create_minor_node(dip, buf, S_IFCHR, 0, 6270Sstevel@tonic-gate DDI_PSEUDO, NULL) == DDI_FAILURE) 6280Sstevel@tonic-gate return (DDI_FAILURE); 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_MED, 6310Sstevel@tonic-gate &bofi_low_cookie) != DDI_SUCCESS) { 6320Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 6330Sstevel@tonic-gate return (DDI_FAILURE); /* fail attach */ 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate /* 6360Sstevel@tonic-gate * get nexus name (from conf file) 6370Sstevel@tonic-gate */ 6380Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0, 6390Sstevel@tonic-gate "bofi-nexus", nexus_name, &size) != DDI_PROP_SUCCESS) { 6400Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 6410Sstevel@tonic-gate return (DDI_FAILURE); 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate /* 6440Sstevel@tonic-gate * get whether to do dma map kmem private checking 6450Sstevel@tonic-gate */ 6460Sstevel@tonic-gate if ((bofi_range_check = ddi_prop_lookup_string(DDI_DEV_T_ANY, 6470Sstevel@tonic-gate dip, 0, "bofi-range-check", &ptr)) != DDI_PROP_SUCCESS) 6480Sstevel@tonic-gate bofi_range_check = 0; 6490Sstevel@tonic-gate else if (strcmp(ptr, "panic") == 0) 6500Sstevel@tonic-gate bofi_range_check = 2; 6510Sstevel@tonic-gate else if (strcmp(ptr, "warn") == 0) 6520Sstevel@tonic-gate bofi_range_check = 1; 6530Sstevel@tonic-gate else 6540Sstevel@tonic-gate bofi_range_check = 0; 6550Sstevel@tonic-gate ddi_prop_free(ptr); 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate /* 6580Sstevel@tonic-gate * get whether to prevent direct access to register 6590Sstevel@tonic-gate */ 6600Sstevel@tonic-gate if ((bofi_ddi_check = ddi_prop_lookup_string(DDI_DEV_T_ANY, 6610Sstevel@tonic-gate dip, 0, "bofi-ddi-check", &ptr)) != DDI_PROP_SUCCESS) 6620Sstevel@tonic-gate bofi_ddi_check = 0; 6630Sstevel@tonic-gate else if (strcmp(ptr, "on") == 0) 6640Sstevel@tonic-gate bofi_ddi_check = 1; 6650Sstevel@tonic-gate else 6660Sstevel@tonic-gate bofi_ddi_check = 0; 6670Sstevel@tonic-gate ddi_prop_free(ptr); 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate /* 6700Sstevel@tonic-gate * get whether to do copy on ddi_dma_sync 6710Sstevel@tonic-gate */ 6720Sstevel@tonic-gate if ((bofi_sync_check = ddi_prop_lookup_string(DDI_DEV_T_ANY, 6730Sstevel@tonic-gate dip, 0, "bofi-sync-check", &ptr)) != DDI_PROP_SUCCESS) 6740Sstevel@tonic-gate bofi_sync_check = 0; 6750Sstevel@tonic-gate else if (strcmp(ptr, "on") == 0) 6760Sstevel@tonic-gate bofi_sync_check = 1; 6770Sstevel@tonic-gate else 6780Sstevel@tonic-gate bofi_sync_check = 0; 6790Sstevel@tonic-gate ddi_prop_free(ptr); 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate /* 6820Sstevel@tonic-gate * get driver-under-test names (from conf file) 6830Sstevel@tonic-gate */ 6840Sstevel@tonic-gate size = NAMESIZE; 6850Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0, 6860Sstevel@tonic-gate "bofi-to-test", driver_list, &size) != DDI_PROP_SUCCESS) 6870Sstevel@tonic-gate driver_list[0] = 0; 6880Sstevel@tonic-gate /* 6890Sstevel@tonic-gate * and convert into a sequence of strings 6900Sstevel@tonic-gate */ 6910Sstevel@tonic-gate driver_list_neg = 1; 6920Sstevel@tonic-gate new_string = 1; 6930Sstevel@tonic-gate driver_list_size = strlen(driver_list); 6940Sstevel@tonic-gate for (i = 0; i < driver_list_size; i++) { 6950Sstevel@tonic-gate if (driver_list[i] == ' ') { 6960Sstevel@tonic-gate driver_list[i] = '\0'; 6970Sstevel@tonic-gate new_string = 1; 6980Sstevel@tonic-gate } else if (new_string) { 6990Sstevel@tonic-gate if (driver_list[i] != '!') 7000Sstevel@tonic-gate driver_list_neg = 0; 7010Sstevel@tonic-gate new_string = 0; 7020Sstevel@tonic-gate } 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate /* 7050Sstevel@tonic-gate * initialize mutex, lists 7060Sstevel@tonic-gate */ 7070Sstevel@tonic-gate mutex_init(&clone_tab_mutex, NULL, MUTEX_DRIVER, 7080Sstevel@tonic-gate NULL); 7090Sstevel@tonic-gate /* 7100Sstevel@tonic-gate * fake up iblock cookie - need to protect outselves 7110Sstevel@tonic-gate * against drivers that use hilevel interrupts 7120Sstevel@tonic-gate */ 7130Sstevel@tonic-gate ss = spl8(); 7140Sstevel@tonic-gate s = spl8(); 7150Sstevel@tonic-gate splx(ss); 7160Sstevel@tonic-gate mutex_init(&bofi_mutex, NULL, MUTEX_SPIN, (void *)(uintptr_t)s); 7170Sstevel@tonic-gate mutex_init(&bofi_low_mutex, NULL, MUTEX_DRIVER, 7180Sstevel@tonic-gate (void *)bofi_low_cookie); 7190Sstevel@tonic-gate shadow_list.next = &shadow_list; 7200Sstevel@tonic-gate shadow_list.prev = &shadow_list; 7210Sstevel@tonic-gate for (i = 0; i < HDL_HASH_TBL_SIZE; i++) { 7220Sstevel@tonic-gate hhash_table[i].hnext = &hhash_table[i]; 7230Sstevel@tonic-gate hhash_table[i].hprev = &hhash_table[i]; 7240Sstevel@tonic-gate dhash_table[i].dnext = &dhash_table[i]; 7250Sstevel@tonic-gate dhash_table[i].dprev = &dhash_table[i]; 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate for (i = 1; i < BOFI_NLINKS; i++) 7280Sstevel@tonic-gate bofi_link_array[i].link = &bofi_link_array[i-1]; 7290Sstevel@tonic-gate bofi_link_freelist = &bofi_link_array[BOFI_NLINKS - 1]; 7300Sstevel@tonic-gate /* 7310Sstevel@tonic-gate * overlay bus_ops structure 7320Sstevel@tonic-gate */ 7330Sstevel@tonic-gate if (modify_bus_ops(nexus_name, &bofi_bus_ops) == 0) { 7340Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 7350Sstevel@tonic-gate mutex_destroy(&clone_tab_mutex); 7360Sstevel@tonic-gate mutex_destroy(&bofi_mutex); 7370Sstevel@tonic-gate mutex_destroy(&bofi_low_mutex); 7380Sstevel@tonic-gate return (DDI_FAILURE); 7390Sstevel@tonic-gate } 7401865Sdilpreet if (sysevent_evc_bind(FM_ERROR_CHAN, &bofi_error_chan, 0) == 0) 7411865Sdilpreet (void) sysevent_evc_subscribe(bofi_error_chan, "bofi", 7421865Sdilpreet EC_FM, bofi_fm_ereport_callback, NULL, 0); 7431865Sdilpreet 7440Sstevel@tonic-gate /* 7450Sstevel@tonic-gate * save dip for getinfo 7460Sstevel@tonic-gate */ 7470Sstevel@tonic-gate our_dip = dip; 7480Sstevel@tonic-gate ddi_report_dev(dip); 7490Sstevel@tonic-gate initialized = 1; 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate return (DDI_SUCCESS); 7520Sstevel@tonic-gate } 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate static int 7560Sstevel@tonic-gate bofi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 7570Sstevel@tonic-gate { 7580Sstevel@tonic-gate char *name; 7590Sstevel@tonic-gate char buf[80]; 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate if (cmd != DDI_DETACH) 7620Sstevel@tonic-gate return (DDI_FAILURE); 7630Sstevel@tonic-gate if (ddi_get_instance(dip) > 0) 7640Sstevel@tonic-gate return (DDI_FAILURE); 7650Sstevel@tonic-gate if ((name = ddi_get_name(dip)) == NULL) 7660Sstevel@tonic-gate return (DDI_FAILURE); 7670Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s,ctl", name); 7680Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 7690Sstevel@tonic-gate mutex_enter(&bofi_mutex); 7700Sstevel@tonic-gate /* 7710Sstevel@tonic-gate * make sure test bofi is no longer in use 7720Sstevel@tonic-gate */ 7730Sstevel@tonic-gate if (shadow_list.next != &shadow_list || errent_listp != NULL) { 7740Sstevel@tonic-gate mutex_exit(&bofi_mutex); 7750Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 7760Sstevel@tonic-gate return (DDI_FAILURE); 7770Sstevel@tonic-gate } 7780Sstevel@tonic-gate mutex_exit(&bofi_mutex); 7790Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate /* 7820Sstevel@tonic-gate * restore bus_ops structure 7830Sstevel@tonic-gate */ 7840Sstevel@tonic-gate if (reset_bus_ops(nexus_name, &save_bus_ops) == 0) 7850Sstevel@tonic-gate return (DDI_FAILURE); 7860Sstevel@tonic-gate 7871865Sdilpreet sysevent_evc_unbind(bofi_error_chan); 7881865Sdilpreet 7890Sstevel@tonic-gate mutex_destroy(&clone_tab_mutex); 7900Sstevel@tonic-gate mutex_destroy(&bofi_mutex); 7910Sstevel@tonic-gate mutex_destroy(&bofi_low_mutex); 7920Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 7930Sstevel@tonic-gate our_dip = NULL; 7940Sstevel@tonic-gate initialized = 0; 7950Sstevel@tonic-gate return (DDI_SUCCESS); 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate /* ARGSUSED */ 8000Sstevel@tonic-gate static int 8010Sstevel@tonic-gate bofi_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 8020Sstevel@tonic-gate { 8030Sstevel@tonic-gate dev_t dev = (dev_t)arg; 8040Sstevel@tonic-gate int minor = (int)getminor(dev); 8050Sstevel@tonic-gate int retval; 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate switch (cmd) { 8080Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 8090Sstevel@tonic-gate if (minor != 0 || our_dip == NULL) { 8100Sstevel@tonic-gate *result = (void *)NULL; 8110Sstevel@tonic-gate retval = DDI_FAILURE; 8120Sstevel@tonic-gate } else { 8130Sstevel@tonic-gate *result = (void *)our_dip; 8140Sstevel@tonic-gate retval = DDI_SUCCESS; 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate break; 8170Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 8180Sstevel@tonic-gate *result = (void *)0; 8190Sstevel@tonic-gate retval = DDI_SUCCESS; 8200Sstevel@tonic-gate break; 8210Sstevel@tonic-gate default: 8220Sstevel@tonic-gate retval = DDI_FAILURE; 8230Sstevel@tonic-gate } 8240Sstevel@tonic-gate return (retval); 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate /* ARGSUSED */ 8290Sstevel@tonic-gate static int 8300Sstevel@tonic-gate bofi_open(dev_t *devp, int flag, int otyp, cred_t *credp) 8310Sstevel@tonic-gate { 8320Sstevel@tonic-gate int minor = (int)getminor(*devp); 8330Sstevel@tonic-gate struct bofi_errent *softc; 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate /* 8360Sstevel@tonic-gate * only allow open on minor=0 - the clone device 8370Sstevel@tonic-gate */ 8380Sstevel@tonic-gate if (minor != 0) 8390Sstevel@tonic-gate return (ENXIO); 8400Sstevel@tonic-gate /* 8410Sstevel@tonic-gate * fail if not attached 8420Sstevel@tonic-gate */ 8430Sstevel@tonic-gate if (!initialized) 8440Sstevel@tonic-gate return (ENXIO); 8450Sstevel@tonic-gate /* 8460Sstevel@tonic-gate * find a free slot and grab it 8470Sstevel@tonic-gate */ 8480Sstevel@tonic-gate mutex_enter(&clone_tab_mutex); 8490Sstevel@tonic-gate for (minor = 1; minor < NCLONES; minor++) { 8500Sstevel@tonic-gate if (clone_tab[minor] == 0) { 8510Sstevel@tonic-gate clone_tab[minor] = 1; 8520Sstevel@tonic-gate break; 8530Sstevel@tonic-gate } 8540Sstevel@tonic-gate } 8550Sstevel@tonic-gate mutex_exit(&clone_tab_mutex); 8560Sstevel@tonic-gate if (minor == NCLONES) 8570Sstevel@tonic-gate return (EAGAIN); 8580Sstevel@tonic-gate /* 8590Sstevel@tonic-gate * soft state structure for this clone is used to maintain a list 8600Sstevel@tonic-gate * of allocated errdefs so they can be freed on close 8610Sstevel@tonic-gate */ 8620Sstevel@tonic-gate if (ddi_soft_state_zalloc(statep, minor) != DDI_SUCCESS) { 8630Sstevel@tonic-gate mutex_enter(&clone_tab_mutex); 8640Sstevel@tonic-gate clone_tab[minor] = 0; 8650Sstevel@tonic-gate mutex_exit(&clone_tab_mutex); 8660Sstevel@tonic-gate return (EAGAIN); 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate softc = ddi_get_soft_state(statep, minor); 8690Sstevel@tonic-gate softc->cnext = softc; 8700Sstevel@tonic-gate softc->cprev = softc; 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), minor); 8730Sstevel@tonic-gate return (0); 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate /* ARGSUSED */ 8780Sstevel@tonic-gate static int 8790Sstevel@tonic-gate bofi_close(dev_t dev, int flag, int otyp, cred_t *credp) 8800Sstevel@tonic-gate { 8810Sstevel@tonic-gate int minor = (int)getminor(dev); 8820Sstevel@tonic-gate struct bofi_errent *softc; 8830Sstevel@tonic-gate struct bofi_errent *ep, *next_ep; 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate softc = ddi_get_soft_state(statep, minor); 8860Sstevel@tonic-gate if (softc == NULL) 8870Sstevel@tonic-gate return (ENXIO); 8880Sstevel@tonic-gate /* 8890Sstevel@tonic-gate * find list of errdefs and free them off 8900Sstevel@tonic-gate */ 8910Sstevel@tonic-gate for (ep = softc->cnext; ep != softc; ) { 8920Sstevel@tonic-gate next_ep = ep->cnext; 8930Sstevel@tonic-gate (void) bofi_errdef_free(ep); 8940Sstevel@tonic-gate ep = next_ep; 8950Sstevel@tonic-gate } 8960Sstevel@tonic-gate /* 8970Sstevel@tonic-gate * free clone tab slot 8980Sstevel@tonic-gate */ 8990Sstevel@tonic-gate mutex_enter(&clone_tab_mutex); 9000Sstevel@tonic-gate clone_tab[minor] = 0; 9010Sstevel@tonic-gate mutex_exit(&clone_tab_mutex); 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate ddi_soft_state_free(statep, minor); 9040Sstevel@tonic-gate return (0); 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate /* ARGSUSED */ 9090Sstevel@tonic-gate static int 9100Sstevel@tonic-gate bofi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 9110Sstevel@tonic-gate int *rvalp) 9120Sstevel@tonic-gate { 9130Sstevel@tonic-gate struct bofi_errent *softc; 9140Sstevel@tonic-gate int minor = (int)getminor(dev); 9150Sstevel@tonic-gate struct bofi_errdef errdef; 9160Sstevel@tonic-gate struct bofi_errctl errctl; 9170Sstevel@tonic-gate struct bofi_errstate errstate; 9180Sstevel@tonic-gate void *ed_handle; 9190Sstevel@tonic-gate struct bofi_get_handles get_handles; 9200Sstevel@tonic-gate struct bofi_get_hdl_info hdl_info; 9210Sstevel@tonic-gate struct handle_info *hdlip; 9220Sstevel@tonic-gate struct handle_info *hib; 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate char *buffer; 9250Sstevel@tonic-gate char *bufptr; 9260Sstevel@tonic-gate char *endbuf; 9270Sstevel@tonic-gate int req_count, count, err; 9280Sstevel@tonic-gate char *namep; 9290Sstevel@tonic-gate struct bofi_shadow *hp; 9300Sstevel@tonic-gate int retval; 9310Sstevel@tonic-gate struct bofi_shadow *hhashp; 9320Sstevel@tonic-gate int i; 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate switch (cmd) { 9350Sstevel@tonic-gate case BOFI_ADD_DEF: 9360Sstevel@tonic-gate /* 9370Sstevel@tonic-gate * add a new error definition 9380Sstevel@tonic-gate */ 9390Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 9400Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 9410Sstevel@tonic-gate case DDI_MODEL_ILP32: 9420Sstevel@tonic-gate { 9430Sstevel@tonic-gate /* 9440Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 9450Sstevel@tonic-gate * 64 bit ioctl 9460Sstevel@tonic-gate */ 9470Sstevel@tonic-gate struct bofi_errdef32 errdef_32; 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errdef_32, 9500Sstevel@tonic-gate sizeof (struct bofi_errdef32), mode)) { 9510Sstevel@tonic-gate return (EFAULT); 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate errdef.namesize = errdef_32.namesize; 9540Sstevel@tonic-gate (void) strncpy(errdef.name, errdef_32.name, NAMESIZE); 9550Sstevel@tonic-gate errdef.instance = errdef_32.instance; 9560Sstevel@tonic-gate errdef.rnumber = errdef_32.rnumber; 9570Sstevel@tonic-gate errdef.offset = errdef_32.offset; 9580Sstevel@tonic-gate errdef.len = errdef_32.len; 9590Sstevel@tonic-gate errdef.access_type = errdef_32.access_type; 9600Sstevel@tonic-gate errdef.access_count = errdef_32.access_count; 9610Sstevel@tonic-gate errdef.fail_count = errdef_32.fail_count; 9620Sstevel@tonic-gate errdef.acc_chk = errdef_32.acc_chk; 9630Sstevel@tonic-gate errdef.optype = errdef_32.optype; 9640Sstevel@tonic-gate errdef.operand = errdef_32.operand; 9650Sstevel@tonic-gate errdef.log.logsize = errdef_32.log.logsize; 9660Sstevel@tonic-gate errdef.log.entries = errdef_32.log.entries; 9670Sstevel@tonic-gate errdef.log.flags = errdef_32.log.flags; 9680Sstevel@tonic-gate errdef.log.wrapcnt = errdef_32.log.wrapcnt; 9690Sstevel@tonic-gate errdef.log.start_time = errdef_32.log.start_time; 9700Sstevel@tonic-gate errdef.log.stop_time = errdef_32.log.stop_time; 9710Sstevel@tonic-gate errdef.log.logbase = 9720Sstevel@tonic-gate (caddr_t)(uintptr_t)errdef_32.log.logbase; 9730Sstevel@tonic-gate errdef.errdef_handle = errdef_32.errdef_handle; 9740Sstevel@tonic-gate break; 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate case DDI_MODEL_NONE: 9770Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errdef, 9780Sstevel@tonic-gate sizeof (struct bofi_errdef), mode)) 9790Sstevel@tonic-gate return (EFAULT); 9800Sstevel@tonic-gate break; 9810Sstevel@tonic-gate } 9820Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 9830Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errdef, 9840Sstevel@tonic-gate sizeof (struct bofi_errdef), mode) != 0) 9850Sstevel@tonic-gate return (EFAULT); 9860Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 9870Sstevel@tonic-gate /* 9880Sstevel@tonic-gate * do some validation 9890Sstevel@tonic-gate */ 9900Sstevel@tonic-gate if (errdef.fail_count == 0) 9910Sstevel@tonic-gate errdef.optype = 0; 9920Sstevel@tonic-gate if (errdef.optype != 0) { 9930Sstevel@tonic-gate if (errdef.access_type & BOFI_INTR && 9940Sstevel@tonic-gate errdef.optype != BOFI_DELAY_INTR && 9950Sstevel@tonic-gate errdef.optype != BOFI_LOSE_INTR && 9960Sstevel@tonic-gate errdef.optype != BOFI_EXTRA_INTR) 9970Sstevel@tonic-gate return (EINVAL); 9980Sstevel@tonic-gate if ((errdef.access_type & (BOFI_DMA_RW|BOFI_PIO_R)) && 9990Sstevel@tonic-gate errdef.optype == BOFI_NO_TRANSFER) 10000Sstevel@tonic-gate return (EINVAL); 10010Sstevel@tonic-gate if ((errdef.access_type & (BOFI_PIO_RW)) && 10020Sstevel@tonic-gate errdef.optype != BOFI_EQUAL && 10030Sstevel@tonic-gate errdef.optype != BOFI_OR && 10040Sstevel@tonic-gate errdef.optype != BOFI_XOR && 10050Sstevel@tonic-gate errdef.optype != BOFI_AND && 10060Sstevel@tonic-gate errdef.optype != BOFI_NO_TRANSFER) 10070Sstevel@tonic-gate return (EINVAL); 10080Sstevel@tonic-gate } 10090Sstevel@tonic-gate /* 10100Sstevel@tonic-gate * find softstate for this clone, so we can tag 10110Sstevel@tonic-gate * new errdef on to it 10120Sstevel@tonic-gate */ 10130Sstevel@tonic-gate softc = ddi_get_soft_state(statep, minor); 10140Sstevel@tonic-gate if (softc == NULL) 10150Sstevel@tonic-gate return (ENXIO); 10160Sstevel@tonic-gate /* 10170Sstevel@tonic-gate * read in name 10180Sstevel@tonic-gate */ 10190Sstevel@tonic-gate if (errdef.namesize > NAMESIZE) 10200Sstevel@tonic-gate return (EINVAL); 10210Sstevel@tonic-gate namep = kmem_zalloc(errdef.namesize+1, KM_SLEEP); 10220Sstevel@tonic-gate (void) strncpy(namep, errdef.name, errdef.namesize); 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate if (bofi_errdef_alloc(&errdef, namep, softc) != DDI_SUCCESS) { 10250Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 10260Sstevel@tonic-gate (uintptr_t)errdef.errdef_handle); 10270Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 10280Sstevel@tonic-gate return (EINVAL); 10290Sstevel@tonic-gate } 10300Sstevel@tonic-gate /* 10310Sstevel@tonic-gate * copy out errdef again, including filled in errdef_handle 10320Sstevel@tonic-gate */ 10330Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 10340Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 10350Sstevel@tonic-gate case DDI_MODEL_ILP32: 10360Sstevel@tonic-gate { 10370Sstevel@tonic-gate /* 10380Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 10390Sstevel@tonic-gate * 64 bit ioctl 10400Sstevel@tonic-gate */ 10410Sstevel@tonic-gate struct bofi_errdef32 errdef_32; 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate errdef_32.namesize = errdef.namesize; 10440Sstevel@tonic-gate (void) strncpy(errdef_32.name, errdef.name, NAMESIZE); 10450Sstevel@tonic-gate errdef_32.instance = errdef.instance; 10460Sstevel@tonic-gate errdef_32.rnumber = errdef.rnumber; 10470Sstevel@tonic-gate errdef_32.offset = errdef.offset; 10480Sstevel@tonic-gate errdef_32.len = errdef.len; 10490Sstevel@tonic-gate errdef_32.access_type = errdef.access_type; 10500Sstevel@tonic-gate errdef_32.access_count = errdef.access_count; 10510Sstevel@tonic-gate errdef_32.fail_count = errdef.fail_count; 10520Sstevel@tonic-gate errdef_32.acc_chk = errdef.acc_chk; 10530Sstevel@tonic-gate errdef_32.optype = errdef.optype; 10540Sstevel@tonic-gate errdef_32.operand = errdef.operand; 10550Sstevel@tonic-gate errdef_32.log.logsize = errdef.log.logsize; 10560Sstevel@tonic-gate errdef_32.log.entries = errdef.log.entries; 10570Sstevel@tonic-gate errdef_32.log.flags = errdef.log.flags; 10580Sstevel@tonic-gate errdef_32.log.wrapcnt = errdef.log.wrapcnt; 10590Sstevel@tonic-gate errdef_32.log.start_time = errdef.log.start_time; 10600Sstevel@tonic-gate errdef_32.log.stop_time = errdef.log.stop_time; 10610Sstevel@tonic-gate errdef_32.log.logbase = 10620Sstevel@tonic-gate (caddr32_t)(uintptr_t)errdef.log.logbase; 10630Sstevel@tonic-gate errdef_32.errdef_handle = errdef.errdef_handle; 10640Sstevel@tonic-gate if (ddi_copyout(&errdef_32, (void *)arg, 10650Sstevel@tonic-gate sizeof (struct bofi_errdef32), mode) != 0) { 10660Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 10670Sstevel@tonic-gate errdef.errdef_handle); 10680Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 10690Sstevel@tonic-gate return (EFAULT); 10700Sstevel@tonic-gate } 10710Sstevel@tonic-gate break; 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate case DDI_MODEL_NONE: 10740Sstevel@tonic-gate if (ddi_copyout(&errdef, (void *)arg, 10750Sstevel@tonic-gate sizeof (struct bofi_errdef), mode) != 0) { 10760Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 10770Sstevel@tonic-gate errdef.errdef_handle); 10780Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 10790Sstevel@tonic-gate return (EFAULT); 10800Sstevel@tonic-gate } 10810Sstevel@tonic-gate break; 10820Sstevel@tonic-gate } 10830Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 10840Sstevel@tonic-gate if (ddi_copyout(&errdef, (void *)arg, 10850Sstevel@tonic-gate sizeof (struct bofi_errdef), mode) != 0) { 10860Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 10870Sstevel@tonic-gate (uintptr_t)errdef.errdef_handle); 10880Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 10890Sstevel@tonic-gate return (EFAULT); 10900Sstevel@tonic-gate } 10910Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 10920Sstevel@tonic-gate return (0); 10930Sstevel@tonic-gate case BOFI_DEL_DEF: 10940Sstevel@tonic-gate /* 10950Sstevel@tonic-gate * delete existing errdef 10960Sstevel@tonic-gate */ 10970Sstevel@tonic-gate if (ddi_copyin((void *)arg, &ed_handle, 10980Sstevel@tonic-gate sizeof (void *), mode) != 0) 10990Sstevel@tonic-gate return (EFAULT); 11000Sstevel@tonic-gate return (bofi_errdef_free((struct bofi_errent *)ed_handle)); 11010Sstevel@tonic-gate case BOFI_START: 11020Sstevel@tonic-gate /* 11030Sstevel@tonic-gate * start all errdefs corresponding to 11040Sstevel@tonic-gate * this name and instance 11050Sstevel@tonic-gate */ 11060Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 11070Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 11080Sstevel@tonic-gate return (EFAULT); 11090Sstevel@tonic-gate /* 11100Sstevel@tonic-gate * copy in name 11110Sstevel@tonic-gate */ 11120Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 11130Sstevel@tonic-gate return (EINVAL); 11140Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 11150Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 11160Sstevel@tonic-gate bofi_start(&errctl, namep); 11170Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 11180Sstevel@tonic-gate return (0); 11190Sstevel@tonic-gate case BOFI_STOP: 11200Sstevel@tonic-gate /* 11210Sstevel@tonic-gate * stop all errdefs corresponding to 11220Sstevel@tonic-gate * this name and instance 11230Sstevel@tonic-gate */ 11240Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 11250Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 11260Sstevel@tonic-gate return (EFAULT); 11270Sstevel@tonic-gate /* 11280Sstevel@tonic-gate * copy in name 11290Sstevel@tonic-gate */ 11300Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 11310Sstevel@tonic-gate return (EINVAL); 11320Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 11330Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 11340Sstevel@tonic-gate bofi_stop(&errctl, namep); 11350Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 11360Sstevel@tonic-gate return (0); 11370Sstevel@tonic-gate case BOFI_BROADCAST: 11380Sstevel@tonic-gate /* 11390Sstevel@tonic-gate * wakeup all errdefs corresponding to 11400Sstevel@tonic-gate * this name and instance 11410Sstevel@tonic-gate */ 11420Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 11430Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 11440Sstevel@tonic-gate return (EFAULT); 11450Sstevel@tonic-gate /* 11460Sstevel@tonic-gate * copy in name 11470Sstevel@tonic-gate */ 11480Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 11490Sstevel@tonic-gate return (EINVAL); 11500Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 11510Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 11520Sstevel@tonic-gate bofi_broadcast(&errctl, namep); 11530Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 11540Sstevel@tonic-gate return (0); 11550Sstevel@tonic-gate case BOFI_CLEAR_ACC_CHK: 11560Sstevel@tonic-gate /* 11570Sstevel@tonic-gate * clear "acc_chk" for all errdefs corresponding to 11580Sstevel@tonic-gate * this name and instance 11590Sstevel@tonic-gate */ 11600Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 11610Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 11620Sstevel@tonic-gate return (EFAULT); 11630Sstevel@tonic-gate /* 11640Sstevel@tonic-gate * copy in name 11650Sstevel@tonic-gate */ 11660Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 11670Sstevel@tonic-gate return (EINVAL); 11680Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 11690Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 11700Sstevel@tonic-gate bofi_clear_acc_chk(&errctl, namep); 11710Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 11720Sstevel@tonic-gate return (0); 11730Sstevel@tonic-gate case BOFI_CLEAR_ERRORS: 11740Sstevel@tonic-gate /* 11750Sstevel@tonic-gate * set "fail_count" to 0 for all errdefs corresponding to 11760Sstevel@tonic-gate * this name and instance whose "access_count" 11770Sstevel@tonic-gate * has expired. 11780Sstevel@tonic-gate */ 11790Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 11800Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 11810Sstevel@tonic-gate return (EFAULT); 11820Sstevel@tonic-gate /* 11830Sstevel@tonic-gate * copy in name 11840Sstevel@tonic-gate */ 11850Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 11860Sstevel@tonic-gate return (EINVAL); 11870Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 11880Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 11890Sstevel@tonic-gate bofi_clear_errors(&errctl, namep); 11900Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 11910Sstevel@tonic-gate return (0); 11920Sstevel@tonic-gate case BOFI_CLEAR_ERRDEFS: 11930Sstevel@tonic-gate /* 11940Sstevel@tonic-gate * set "access_count" and "fail_count" to 0 for all errdefs 11950Sstevel@tonic-gate * corresponding to this name and instance 11960Sstevel@tonic-gate */ 11970Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 11980Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 11990Sstevel@tonic-gate return (EFAULT); 12000Sstevel@tonic-gate /* 12010Sstevel@tonic-gate * copy in name 12020Sstevel@tonic-gate */ 12030Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 12040Sstevel@tonic-gate return (EINVAL); 12050Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 12060Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 12070Sstevel@tonic-gate bofi_clear_errdefs(&errctl, namep); 12080Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 12090Sstevel@tonic-gate return (0); 12100Sstevel@tonic-gate case BOFI_CHK_STATE: 12110Sstevel@tonic-gate { 12120Sstevel@tonic-gate struct acc_log_elem *klg; 12130Sstevel@tonic-gate size_t uls; 12140Sstevel@tonic-gate /* 12150Sstevel@tonic-gate * get state for this errdef - read in dummy errstate 12160Sstevel@tonic-gate * with just the errdef_handle filled in 12170Sstevel@tonic-gate */ 12180Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 12190Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 12200Sstevel@tonic-gate case DDI_MODEL_ILP32: 12210Sstevel@tonic-gate { 12220Sstevel@tonic-gate /* 12230Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 12240Sstevel@tonic-gate * 64 bit ioctl 12250Sstevel@tonic-gate */ 12260Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate_32, 12290Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) { 12300Sstevel@tonic-gate return (EFAULT); 12310Sstevel@tonic-gate } 12320Sstevel@tonic-gate errstate.fail_time = errstate_32.fail_time; 12330Sstevel@tonic-gate errstate.msg_time = errstate_32.msg_time; 12340Sstevel@tonic-gate errstate.access_count = errstate_32.access_count; 12350Sstevel@tonic-gate errstate.fail_count = errstate_32.fail_count; 12360Sstevel@tonic-gate errstate.acc_chk = errstate_32.acc_chk; 12370Sstevel@tonic-gate errstate.errmsg_count = errstate_32.errmsg_count; 12380Sstevel@tonic-gate (void) strncpy(errstate.buffer, errstate_32.buffer, 12390Sstevel@tonic-gate ERRMSGSIZE); 12400Sstevel@tonic-gate errstate.severity = errstate_32.severity; 12410Sstevel@tonic-gate errstate.log.logsize = errstate_32.log.logsize; 12420Sstevel@tonic-gate errstate.log.entries = errstate_32.log.entries; 12430Sstevel@tonic-gate errstate.log.flags = errstate_32.log.flags; 12440Sstevel@tonic-gate errstate.log.wrapcnt = errstate_32.log.wrapcnt; 12450Sstevel@tonic-gate errstate.log.start_time = errstate_32.log.start_time; 12460Sstevel@tonic-gate errstate.log.stop_time = errstate_32.log.stop_time; 12470Sstevel@tonic-gate errstate.log.logbase = 12480Sstevel@tonic-gate (caddr_t)(uintptr_t)errstate_32.log.logbase; 12490Sstevel@tonic-gate errstate.errdef_handle = errstate_32.errdef_handle; 12500Sstevel@tonic-gate break; 12510Sstevel@tonic-gate } 12520Sstevel@tonic-gate case DDI_MODEL_NONE: 12530Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 12540Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 12550Sstevel@tonic-gate return (EFAULT); 12560Sstevel@tonic-gate break; 12570Sstevel@tonic-gate } 12580Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 12590Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 12600Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 12610Sstevel@tonic-gate return (EFAULT); 12620Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 12630Sstevel@tonic-gate if ((retval = bofi_errdef_check(&errstate, &klg)) == EINVAL) 12640Sstevel@tonic-gate return (EINVAL); 12650Sstevel@tonic-gate /* 12660Sstevel@tonic-gate * copy out real errstate structure 12670Sstevel@tonic-gate */ 12680Sstevel@tonic-gate uls = errstate.log.logsize; 12690Sstevel@tonic-gate if (errstate.log.entries > uls && uls) 12700Sstevel@tonic-gate /* insufficient user memory */ 12710Sstevel@tonic-gate errstate.log.entries = uls; 12720Sstevel@tonic-gate /* always pass back a time */ 12730Sstevel@tonic-gate if (errstate.log.stop_time == 0ul) 12740Sstevel@tonic-gate (void) drv_getparm(TIME, &(errstate.log.stop_time)); 12750Sstevel@tonic-gate 12760Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 12770Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 12780Sstevel@tonic-gate case DDI_MODEL_ILP32: 12790Sstevel@tonic-gate { 12800Sstevel@tonic-gate /* 12810Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 12820Sstevel@tonic-gate * 64 bit ioctl 12830Sstevel@tonic-gate */ 12840Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate errstate_32.fail_time = errstate.fail_time; 12870Sstevel@tonic-gate errstate_32.msg_time = errstate.msg_time; 12880Sstevel@tonic-gate errstate_32.access_count = errstate.access_count; 12890Sstevel@tonic-gate errstate_32.fail_count = errstate.fail_count; 12900Sstevel@tonic-gate errstate_32.acc_chk = errstate.acc_chk; 12910Sstevel@tonic-gate errstate_32.errmsg_count = errstate.errmsg_count; 12920Sstevel@tonic-gate (void) strncpy(errstate_32.buffer, errstate.buffer, 12930Sstevel@tonic-gate ERRMSGSIZE); 12940Sstevel@tonic-gate errstate_32.severity = errstate.severity; 12950Sstevel@tonic-gate errstate_32.log.logsize = errstate.log.logsize; 12960Sstevel@tonic-gate errstate_32.log.entries = errstate.log.entries; 12970Sstevel@tonic-gate errstate_32.log.flags = errstate.log.flags; 12980Sstevel@tonic-gate errstate_32.log.wrapcnt = errstate.log.wrapcnt; 12990Sstevel@tonic-gate errstate_32.log.start_time = errstate.log.start_time; 13000Sstevel@tonic-gate errstate_32.log.stop_time = errstate.log.stop_time; 13010Sstevel@tonic-gate errstate_32.log.logbase = 13020Sstevel@tonic-gate (caddr32_t)(uintptr_t)errstate.log.logbase; 13030Sstevel@tonic-gate errstate_32.errdef_handle = errstate.errdef_handle; 13040Sstevel@tonic-gate if (ddi_copyout(&errstate_32, (void *)arg, 13050Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) 13060Sstevel@tonic-gate return (EFAULT); 13070Sstevel@tonic-gate break; 13080Sstevel@tonic-gate } 13090Sstevel@tonic-gate case DDI_MODEL_NONE: 13100Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 13110Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 13120Sstevel@tonic-gate return (EFAULT); 13130Sstevel@tonic-gate break; 13140Sstevel@tonic-gate } 13150Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 13160Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 13170Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 13180Sstevel@tonic-gate return (EFAULT); 13190Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 13200Sstevel@tonic-gate if (uls && errstate.log.entries && 13210Sstevel@tonic-gate ddi_copyout(klg, errstate.log.logbase, 13220Sstevel@tonic-gate errstate.log.entries * sizeof (struct acc_log_elem), 13230Sstevel@tonic-gate mode) != 0) { 13240Sstevel@tonic-gate return (EFAULT); 13250Sstevel@tonic-gate } 13260Sstevel@tonic-gate return (retval); 13270Sstevel@tonic-gate } 13280Sstevel@tonic-gate case BOFI_CHK_STATE_W: 13290Sstevel@tonic-gate { 13300Sstevel@tonic-gate struct acc_log_elem *klg; 13310Sstevel@tonic-gate size_t uls; 13320Sstevel@tonic-gate /* 13330Sstevel@tonic-gate * get state for this errdef - read in dummy errstate 13340Sstevel@tonic-gate * with just the errdef_handle filled in. Then wait for 13350Sstevel@tonic-gate * a ddi_report_fault message to come back 13360Sstevel@tonic-gate */ 13370Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 13380Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 13390Sstevel@tonic-gate case DDI_MODEL_ILP32: 13400Sstevel@tonic-gate { 13410Sstevel@tonic-gate /* 13420Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 13430Sstevel@tonic-gate * 64 bit ioctl 13440Sstevel@tonic-gate */ 13450Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate_32, 13480Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) { 13490Sstevel@tonic-gate return (EFAULT); 13500Sstevel@tonic-gate } 13510Sstevel@tonic-gate errstate.fail_time = errstate_32.fail_time; 13520Sstevel@tonic-gate errstate.msg_time = errstate_32.msg_time; 13530Sstevel@tonic-gate errstate.access_count = errstate_32.access_count; 13540Sstevel@tonic-gate errstate.fail_count = errstate_32.fail_count; 13550Sstevel@tonic-gate errstate.acc_chk = errstate_32.acc_chk; 13560Sstevel@tonic-gate errstate.errmsg_count = errstate_32.errmsg_count; 13570Sstevel@tonic-gate (void) strncpy(errstate.buffer, errstate_32.buffer, 13580Sstevel@tonic-gate ERRMSGSIZE); 13590Sstevel@tonic-gate errstate.severity = errstate_32.severity; 13600Sstevel@tonic-gate errstate.log.logsize = errstate_32.log.logsize; 13610Sstevel@tonic-gate errstate.log.entries = errstate_32.log.entries; 13620Sstevel@tonic-gate errstate.log.flags = errstate_32.log.flags; 13630Sstevel@tonic-gate errstate.log.wrapcnt = errstate_32.log.wrapcnt; 13640Sstevel@tonic-gate errstate.log.start_time = errstate_32.log.start_time; 13650Sstevel@tonic-gate errstate.log.stop_time = errstate_32.log.stop_time; 13660Sstevel@tonic-gate errstate.log.logbase = 13670Sstevel@tonic-gate (caddr_t)(uintptr_t)errstate_32.log.logbase; 13680Sstevel@tonic-gate errstate.errdef_handle = errstate_32.errdef_handle; 13690Sstevel@tonic-gate break; 13700Sstevel@tonic-gate } 13710Sstevel@tonic-gate case DDI_MODEL_NONE: 13720Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 13730Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 13740Sstevel@tonic-gate return (EFAULT); 13750Sstevel@tonic-gate break; 13760Sstevel@tonic-gate } 13770Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 13780Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 13790Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 13800Sstevel@tonic-gate return (EFAULT); 13810Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 13820Sstevel@tonic-gate if ((retval = bofi_errdef_check_w(&errstate, &klg)) == EINVAL) 13830Sstevel@tonic-gate return (EINVAL); 13840Sstevel@tonic-gate /* 13850Sstevel@tonic-gate * copy out real errstate structure 13860Sstevel@tonic-gate */ 13870Sstevel@tonic-gate uls = errstate.log.logsize; 13880Sstevel@tonic-gate uls = errstate.log.logsize; 13890Sstevel@tonic-gate if (errstate.log.entries > uls && uls) 13900Sstevel@tonic-gate /* insufficient user memory */ 13910Sstevel@tonic-gate errstate.log.entries = uls; 13920Sstevel@tonic-gate /* always pass back a time */ 13930Sstevel@tonic-gate if (errstate.log.stop_time == 0ul) 13940Sstevel@tonic-gate (void) drv_getparm(TIME, &(errstate.log.stop_time)); 13950Sstevel@tonic-gate 13960Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 13970Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 13980Sstevel@tonic-gate case DDI_MODEL_ILP32: 13990Sstevel@tonic-gate { 14000Sstevel@tonic-gate /* 14010Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 14020Sstevel@tonic-gate * 64 bit ioctl 14030Sstevel@tonic-gate */ 14040Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate errstate_32.fail_time = errstate.fail_time; 14070Sstevel@tonic-gate errstate_32.msg_time = errstate.msg_time; 14080Sstevel@tonic-gate errstate_32.access_count = errstate.access_count; 14090Sstevel@tonic-gate errstate_32.fail_count = errstate.fail_count; 14100Sstevel@tonic-gate errstate_32.acc_chk = errstate.acc_chk; 14110Sstevel@tonic-gate errstate_32.errmsg_count = errstate.errmsg_count; 14120Sstevel@tonic-gate (void) strncpy(errstate_32.buffer, errstate.buffer, 14130Sstevel@tonic-gate ERRMSGSIZE); 14140Sstevel@tonic-gate errstate_32.severity = errstate.severity; 14150Sstevel@tonic-gate errstate_32.log.logsize = errstate.log.logsize; 14160Sstevel@tonic-gate errstate_32.log.entries = errstate.log.entries; 14170Sstevel@tonic-gate errstate_32.log.flags = errstate.log.flags; 14180Sstevel@tonic-gate errstate_32.log.wrapcnt = errstate.log.wrapcnt; 14190Sstevel@tonic-gate errstate_32.log.start_time = errstate.log.start_time; 14200Sstevel@tonic-gate errstate_32.log.stop_time = errstate.log.stop_time; 14210Sstevel@tonic-gate errstate_32.log.logbase = 14220Sstevel@tonic-gate (caddr32_t)(uintptr_t)errstate.log.logbase; 14230Sstevel@tonic-gate errstate_32.errdef_handle = errstate.errdef_handle; 14240Sstevel@tonic-gate if (ddi_copyout(&errstate_32, (void *)arg, 14250Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) 14260Sstevel@tonic-gate return (EFAULT); 14270Sstevel@tonic-gate break; 14280Sstevel@tonic-gate } 14290Sstevel@tonic-gate case DDI_MODEL_NONE: 14300Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 14310Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 14320Sstevel@tonic-gate return (EFAULT); 14330Sstevel@tonic-gate break; 14340Sstevel@tonic-gate } 14350Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 14360Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 14370Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 14380Sstevel@tonic-gate return (EFAULT); 14390Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate if (uls && errstate.log.entries && 14420Sstevel@tonic-gate ddi_copyout(klg, errstate.log.logbase, 14430Sstevel@tonic-gate errstate.log.entries * sizeof (struct acc_log_elem), 14440Sstevel@tonic-gate mode) != 0) { 14450Sstevel@tonic-gate return (EFAULT); 14460Sstevel@tonic-gate } 14470Sstevel@tonic-gate return (retval); 14480Sstevel@tonic-gate } 14490Sstevel@tonic-gate case BOFI_GET_HANDLES: 14500Sstevel@tonic-gate /* 14510Sstevel@tonic-gate * display existing handles 14520Sstevel@tonic-gate */ 14530Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 14540Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 14550Sstevel@tonic-gate case DDI_MODEL_ILP32: 14560Sstevel@tonic-gate { 14570Sstevel@tonic-gate /* 14580Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 14590Sstevel@tonic-gate * 64 bit ioctl 14600Sstevel@tonic-gate */ 14610Sstevel@tonic-gate struct bofi_get_handles32 get_handles_32; 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate if (ddi_copyin((void *)arg, &get_handles_32, 14640Sstevel@tonic-gate sizeof (get_handles_32), mode) != 0) { 14650Sstevel@tonic-gate return (EFAULT); 14660Sstevel@tonic-gate } 14670Sstevel@tonic-gate get_handles.namesize = get_handles_32.namesize; 14680Sstevel@tonic-gate (void) strncpy(get_handles.name, get_handles_32.name, 14690Sstevel@tonic-gate NAMESIZE); 14700Sstevel@tonic-gate get_handles.instance = get_handles_32.instance; 14710Sstevel@tonic-gate get_handles.count = get_handles_32.count; 14720Sstevel@tonic-gate get_handles.buffer = 14730Sstevel@tonic-gate (caddr_t)(uintptr_t)get_handles_32.buffer; 14740Sstevel@tonic-gate break; 14750Sstevel@tonic-gate } 14760Sstevel@tonic-gate case DDI_MODEL_NONE: 14770Sstevel@tonic-gate if (ddi_copyin((void *)arg, &get_handles, 14780Sstevel@tonic-gate sizeof (get_handles), mode) != 0) 14790Sstevel@tonic-gate return (EFAULT); 14800Sstevel@tonic-gate break; 14810Sstevel@tonic-gate } 14820Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 14830Sstevel@tonic-gate if (ddi_copyin((void *)arg, &get_handles, 14840Sstevel@tonic-gate sizeof (get_handles), mode) != 0) 14850Sstevel@tonic-gate return (EFAULT); 14860Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 14870Sstevel@tonic-gate /* 14880Sstevel@tonic-gate * read in name 14890Sstevel@tonic-gate */ 14900Sstevel@tonic-gate if (get_handles.namesize > NAMESIZE) 14910Sstevel@tonic-gate return (EINVAL); 14920Sstevel@tonic-gate namep = kmem_zalloc(get_handles.namesize+1, KM_SLEEP); 14930Sstevel@tonic-gate (void) strncpy(namep, get_handles.name, get_handles.namesize); 14940Sstevel@tonic-gate req_count = get_handles.count; 14950Sstevel@tonic-gate bufptr = buffer = kmem_zalloc(req_count, KM_SLEEP); 14960Sstevel@tonic-gate endbuf = bufptr + req_count; 14970Sstevel@tonic-gate /* 14980Sstevel@tonic-gate * display existing handles 14990Sstevel@tonic-gate */ 15000Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 15010Sstevel@tonic-gate mutex_enter(&bofi_mutex); 15020Sstevel@tonic-gate for (i = 0; i < HDL_HASH_TBL_SIZE; i++) { 15030Sstevel@tonic-gate hhashp = &hhash_table[i]; 15040Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) { 15050Sstevel@tonic-gate if (!driver_under_test(hp->dip)) 15060Sstevel@tonic-gate continue; 15070Sstevel@tonic-gate if (ddi_name_to_major(ddi_get_name(hp->dip)) != 15080Sstevel@tonic-gate ddi_name_to_major(namep)) 15090Sstevel@tonic-gate continue; 15100Sstevel@tonic-gate if (hp->instance != get_handles.instance) 15110Sstevel@tonic-gate continue; 15120Sstevel@tonic-gate /* 15130Sstevel@tonic-gate * print information per handle - note that 15140Sstevel@tonic-gate * DMA* means an unbound DMA handle 15150Sstevel@tonic-gate */ 15160Sstevel@tonic-gate (void) snprintf(bufptr, (size_t)(endbuf-bufptr), 15170Sstevel@tonic-gate " %s %d %s ", hp->name, hp->instance, 15180Sstevel@tonic-gate (hp->type == BOFI_INT_HDL) ? "INTR" : 15190Sstevel@tonic-gate (hp->type == BOFI_ACC_HDL) ? "PIO" : 15200Sstevel@tonic-gate (hp->type == BOFI_DMA_HDL) ? "DMA" : 15210Sstevel@tonic-gate (hp->hparrayp != NULL) ? "DVMA" : "DMA*"); 15220Sstevel@tonic-gate bufptr += strlen(bufptr); 15230Sstevel@tonic-gate if (hp->type == BOFI_ACC_HDL) { 15240Sstevel@tonic-gate if (hp->len == INT_MAX - hp->offset) 15250Sstevel@tonic-gate (void) snprintf(bufptr, 15260Sstevel@tonic-gate (size_t)(endbuf-bufptr), 15270Sstevel@tonic-gate "reg set %d off 0x%llx\n", 15280Sstevel@tonic-gate hp->rnumber, hp->offset); 15290Sstevel@tonic-gate else 15300Sstevel@tonic-gate (void) snprintf(bufptr, 15310Sstevel@tonic-gate (size_t)(endbuf-bufptr), 15320Sstevel@tonic-gate "reg set %d off 0x%llx" 15330Sstevel@tonic-gate " len 0x%llx\n", 15340Sstevel@tonic-gate hp->rnumber, hp->offset, 15350Sstevel@tonic-gate hp->len); 15360Sstevel@tonic-gate } else if (hp->type == BOFI_DMA_HDL) 15370Sstevel@tonic-gate (void) snprintf(bufptr, 15380Sstevel@tonic-gate (size_t)(endbuf-bufptr), 15390Sstevel@tonic-gate "handle no %d len 0x%llx" 15400Sstevel@tonic-gate " addr 0x%p\n", hp->rnumber, 15410Sstevel@tonic-gate hp->len, (void *)hp->addr); 15420Sstevel@tonic-gate else if (hp->type == BOFI_NULL && 15430Sstevel@tonic-gate hp->hparrayp == NULL) 15440Sstevel@tonic-gate (void) snprintf(bufptr, 15450Sstevel@tonic-gate (size_t)(endbuf-bufptr), 15460Sstevel@tonic-gate "handle no %d\n", hp->rnumber); 15470Sstevel@tonic-gate else 15480Sstevel@tonic-gate (void) snprintf(bufptr, 15490Sstevel@tonic-gate (size_t)(endbuf-bufptr), "\n"); 15500Sstevel@tonic-gate bufptr += strlen(bufptr); 15510Sstevel@tonic-gate } 15520Sstevel@tonic-gate } 15530Sstevel@tonic-gate mutex_exit(&bofi_mutex); 15540Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 15550Sstevel@tonic-gate err = ddi_copyout(buffer, get_handles.buffer, req_count, mode); 15560Sstevel@tonic-gate kmem_free(namep, get_handles.namesize+1); 15570Sstevel@tonic-gate kmem_free(buffer, req_count); 15580Sstevel@tonic-gate if (err != 0) 15590Sstevel@tonic-gate return (EFAULT); 15600Sstevel@tonic-gate else 15610Sstevel@tonic-gate return (0); 15620Sstevel@tonic-gate case BOFI_GET_HANDLE_INFO: 15630Sstevel@tonic-gate /* 15640Sstevel@tonic-gate * display existing handles 15650Sstevel@tonic-gate */ 15660Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 15670Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 15680Sstevel@tonic-gate case DDI_MODEL_ILP32: 15690Sstevel@tonic-gate { 15700Sstevel@tonic-gate /* 15710Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 15720Sstevel@tonic-gate * 64 bit ioctl 15730Sstevel@tonic-gate */ 15740Sstevel@tonic-gate struct bofi_get_hdl_info32 hdl_info_32; 15750Sstevel@tonic-gate 15760Sstevel@tonic-gate if (ddi_copyin((void *)arg, &hdl_info_32, 15770Sstevel@tonic-gate sizeof (hdl_info_32), mode)) { 15780Sstevel@tonic-gate return (EFAULT); 15790Sstevel@tonic-gate } 15800Sstevel@tonic-gate hdl_info.namesize = hdl_info_32.namesize; 15810Sstevel@tonic-gate (void) strncpy(hdl_info.name, hdl_info_32.name, 15820Sstevel@tonic-gate NAMESIZE); 15830Sstevel@tonic-gate hdl_info.count = hdl_info_32.count; 15840Sstevel@tonic-gate hdl_info.hdli = (caddr_t)(uintptr_t)hdl_info_32.hdli; 15850Sstevel@tonic-gate break; 15860Sstevel@tonic-gate } 15870Sstevel@tonic-gate case DDI_MODEL_NONE: 15880Sstevel@tonic-gate if (ddi_copyin((void *)arg, &hdl_info, 15890Sstevel@tonic-gate sizeof (hdl_info), mode)) 15900Sstevel@tonic-gate return (EFAULT); 15910Sstevel@tonic-gate break; 15920Sstevel@tonic-gate } 15930Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 15940Sstevel@tonic-gate if (ddi_copyin((void *)arg, &hdl_info, 15950Sstevel@tonic-gate sizeof (hdl_info), mode)) 15960Sstevel@tonic-gate return (EFAULT); 15970Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 15980Sstevel@tonic-gate if (hdl_info.namesize > NAMESIZE) 15990Sstevel@tonic-gate return (EINVAL); 16000Sstevel@tonic-gate namep = kmem_zalloc(hdl_info.namesize + 1, KM_SLEEP); 16010Sstevel@tonic-gate (void) strncpy(namep, hdl_info.name, hdl_info.namesize); 16020Sstevel@tonic-gate req_count = hdl_info.count; 16030Sstevel@tonic-gate count = hdl_info.count = 0; /* the actual no of handles */ 16040Sstevel@tonic-gate if (req_count > 0) { 16050Sstevel@tonic-gate hib = hdlip = 16060Sstevel@tonic-gate kmem_zalloc(req_count * sizeof (struct handle_info), 16070Sstevel@tonic-gate KM_SLEEP); 16080Sstevel@tonic-gate } else { 16090Sstevel@tonic-gate hib = hdlip = 0; 16100Sstevel@tonic-gate req_count = hdl_info.count = 0; 16110Sstevel@tonic-gate } 16120Sstevel@tonic-gate 16130Sstevel@tonic-gate /* 16140Sstevel@tonic-gate * display existing handles 16150Sstevel@tonic-gate */ 16160Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 16170Sstevel@tonic-gate mutex_enter(&bofi_mutex); 16180Sstevel@tonic-gate for (i = 0; i < HDL_HASH_TBL_SIZE; i++) { 16190Sstevel@tonic-gate hhashp = &hhash_table[i]; 16200Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) { 16210Sstevel@tonic-gate if (!driver_under_test(hp->dip) || 16220Sstevel@tonic-gate ddi_name_to_major(ddi_get_name(hp->dip)) != 16230Sstevel@tonic-gate ddi_name_to_major(namep) || 16240Sstevel@tonic-gate ++(hdl_info.count) > req_count || 16250Sstevel@tonic-gate count == req_count) 16260Sstevel@tonic-gate continue; 16270Sstevel@tonic-gate 16280Sstevel@tonic-gate hdlip->instance = hp->instance; 16290Sstevel@tonic-gate hdlip->rnumber = hp->rnumber; 16300Sstevel@tonic-gate switch (hp->type) { 16310Sstevel@tonic-gate case BOFI_ACC_HDL: 16320Sstevel@tonic-gate hdlip->access_type = BOFI_PIO_RW; 16330Sstevel@tonic-gate hdlip->offset = hp->offset; 16340Sstevel@tonic-gate hdlip->len = hp->len; 16350Sstevel@tonic-gate break; 16360Sstevel@tonic-gate case BOFI_DMA_HDL: 16370Sstevel@tonic-gate hdlip->access_type = 0; 16380Sstevel@tonic-gate if (hp->flags & DDI_DMA_WRITE) 16390Sstevel@tonic-gate hdlip->access_type |= 16400Sstevel@tonic-gate BOFI_DMA_W; 16410Sstevel@tonic-gate if (hp->flags & DDI_DMA_READ) 16420Sstevel@tonic-gate hdlip->access_type |= 16430Sstevel@tonic-gate BOFI_DMA_R; 16440Sstevel@tonic-gate hdlip->len = hp->len; 16450Sstevel@tonic-gate hdlip->addr_cookie = 16460Sstevel@tonic-gate (uint64_t)(uintptr_t)hp->addr; 16470Sstevel@tonic-gate break; 16480Sstevel@tonic-gate case BOFI_INT_HDL: 16490Sstevel@tonic-gate hdlip->access_type = BOFI_INTR; 16500Sstevel@tonic-gate break; 16510Sstevel@tonic-gate default: 16520Sstevel@tonic-gate hdlip->access_type = 0; 16530Sstevel@tonic-gate break; 16540Sstevel@tonic-gate } 16550Sstevel@tonic-gate hdlip++; 16560Sstevel@tonic-gate count++; 16570Sstevel@tonic-gate } 16580Sstevel@tonic-gate } 16590Sstevel@tonic-gate mutex_exit(&bofi_mutex); 16600Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 16610Sstevel@tonic-gate err = 0; 16620Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 16630Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 16640Sstevel@tonic-gate case DDI_MODEL_ILP32: 16650Sstevel@tonic-gate { 16660Sstevel@tonic-gate /* 16670Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 16680Sstevel@tonic-gate * 64 bit ioctl 16690Sstevel@tonic-gate */ 16700Sstevel@tonic-gate struct bofi_get_hdl_info32 hdl_info_32; 16710Sstevel@tonic-gate 16720Sstevel@tonic-gate hdl_info_32.namesize = hdl_info.namesize; 16730Sstevel@tonic-gate (void) strncpy(hdl_info_32.name, hdl_info.name, 16740Sstevel@tonic-gate NAMESIZE); 16750Sstevel@tonic-gate hdl_info_32.count = hdl_info.count; 16760Sstevel@tonic-gate hdl_info_32.hdli = (caddr32_t)(uintptr_t)hdl_info.hdli; 16770Sstevel@tonic-gate if (ddi_copyout(&hdl_info_32, (void *)arg, 16780Sstevel@tonic-gate sizeof (hdl_info_32), mode) != 0) { 16790Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 16800Sstevel@tonic-gate if (req_count > 0) 16810Sstevel@tonic-gate kmem_free(hib, 16820Sstevel@tonic-gate req_count * sizeof (*hib)); 16830Sstevel@tonic-gate return (EFAULT); 16840Sstevel@tonic-gate } 16850Sstevel@tonic-gate break; 16860Sstevel@tonic-gate } 16870Sstevel@tonic-gate case DDI_MODEL_NONE: 16880Sstevel@tonic-gate if (ddi_copyout(&hdl_info, (void *)arg, 16890Sstevel@tonic-gate sizeof (hdl_info), mode) != 0) { 16900Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 16910Sstevel@tonic-gate if (req_count > 0) 16920Sstevel@tonic-gate kmem_free(hib, 16930Sstevel@tonic-gate req_count * sizeof (*hib)); 16940Sstevel@tonic-gate return (EFAULT); 16950Sstevel@tonic-gate } 16960Sstevel@tonic-gate break; 16970Sstevel@tonic-gate } 16980Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 16990Sstevel@tonic-gate if (ddi_copyout(&hdl_info, (void *)arg, 17000Sstevel@tonic-gate sizeof (hdl_info), mode) != 0) { 17010Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 17020Sstevel@tonic-gate if (req_count > 0) 17030Sstevel@tonic-gate kmem_free(hib, req_count * sizeof (*hib)); 17040Sstevel@tonic-gate return (EFAULT); 17050Sstevel@tonic-gate } 17060Sstevel@tonic-gate #endif /* ! _MULTI_DATAMODEL */ 17070Sstevel@tonic-gate if (count > 0) { 17080Sstevel@tonic-gate if (ddi_copyout(hib, hdl_info.hdli, 17090Sstevel@tonic-gate count * sizeof (*hib), mode) != 0) { 17100Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 17110Sstevel@tonic-gate if (req_count > 0) 17120Sstevel@tonic-gate kmem_free(hib, 17130Sstevel@tonic-gate req_count * sizeof (*hib)); 17140Sstevel@tonic-gate return (EFAULT); 17150Sstevel@tonic-gate } 17160Sstevel@tonic-gate } 17170Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 17180Sstevel@tonic-gate if (req_count > 0) 17190Sstevel@tonic-gate kmem_free(hib, req_count * sizeof (*hib)); 17200Sstevel@tonic-gate return (err); 17210Sstevel@tonic-gate default: 17220Sstevel@tonic-gate return (ENOTTY); 17230Sstevel@tonic-gate } 17240Sstevel@tonic-gate } 17250Sstevel@tonic-gate 17260Sstevel@tonic-gate 17270Sstevel@tonic-gate /* 17280Sstevel@tonic-gate * add a new error definition 17290Sstevel@tonic-gate */ 17300Sstevel@tonic-gate static int 17310Sstevel@tonic-gate bofi_errdef_alloc(struct bofi_errdef *errdefp, char *namep, 17320Sstevel@tonic-gate struct bofi_errent *softc) 17330Sstevel@tonic-gate { 17340Sstevel@tonic-gate struct bofi_errent *ep; 17350Sstevel@tonic-gate struct bofi_shadow *hp; 17360Sstevel@tonic-gate struct bofi_link *lp; 17370Sstevel@tonic-gate 17380Sstevel@tonic-gate /* 17390Sstevel@tonic-gate * allocate errdef structure and put on in-use list 17400Sstevel@tonic-gate */ 17410Sstevel@tonic-gate ep = kmem_zalloc(sizeof (struct bofi_errent), KM_SLEEP); 17420Sstevel@tonic-gate ep->errdef = *errdefp; 17430Sstevel@tonic-gate ep->name = namep; 17440Sstevel@tonic-gate ep->errdef.errdef_handle = (uint64_t)(uintptr_t)ep; 17451865Sdilpreet ep->errstate.severity = DDI_SERVICE_RESTORED; 17460Sstevel@tonic-gate ep->errstate.errdef_handle = (uint64_t)(uintptr_t)ep; 17470Sstevel@tonic-gate cv_init(&ep->cv, NULL, CV_DRIVER, NULL); 17480Sstevel@tonic-gate /* 17490Sstevel@tonic-gate * allocate space for logging 17500Sstevel@tonic-gate */ 17510Sstevel@tonic-gate ep->errdef.log.entries = 0; 17520Sstevel@tonic-gate ep->errdef.log.wrapcnt = 0; 17530Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) 17540Sstevel@tonic-gate ep->logbase = kmem_alloc(sizeof (struct acc_log_elem) * 17550Sstevel@tonic-gate ep->errdef.log.logsize, KM_SLEEP); 17560Sstevel@tonic-gate else 17570Sstevel@tonic-gate ep->logbase = NULL; 17580Sstevel@tonic-gate /* 17590Sstevel@tonic-gate * put on in-use list 17600Sstevel@tonic-gate */ 17610Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 17620Sstevel@tonic-gate mutex_enter(&bofi_mutex); 17630Sstevel@tonic-gate ep->next = errent_listp; 17640Sstevel@tonic-gate errent_listp = ep; 17650Sstevel@tonic-gate /* 17660Sstevel@tonic-gate * and add it to the per-clone list 17670Sstevel@tonic-gate */ 17680Sstevel@tonic-gate ep->cnext = softc->cnext; 17690Sstevel@tonic-gate softc->cnext->cprev = ep; 17700Sstevel@tonic-gate ep->cprev = softc; 17710Sstevel@tonic-gate softc->cnext = ep; 17720Sstevel@tonic-gate 17730Sstevel@tonic-gate /* 17740Sstevel@tonic-gate * look for corresponding shadow handle structures and if we find any 17750Sstevel@tonic-gate * tag this errdef structure on to their link lists. 17760Sstevel@tonic-gate */ 17770Sstevel@tonic-gate for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) { 17780Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == ddi_name_to_major(namep) && 17790Sstevel@tonic-gate hp->instance == errdefp->instance && 17800Sstevel@tonic-gate (((errdefp->access_type & BOFI_DMA_RW) && 17810Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 17820Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 17830Sstevel@tonic-gate hp->type == BOFI_DMA_HDL && 17840Sstevel@tonic-gate (((uintptr_t)(hp->addr + ep->errdef.offset + 17850Sstevel@tonic-gate ep->errdef.len) & ~LLSZMASK) > 17860Sstevel@tonic-gate ((uintptr_t)((hp->addr + ep->errdef.offset) + 17870Sstevel@tonic-gate LLSZMASK) & ~LLSZMASK))) || 17880Sstevel@tonic-gate ((errdefp->access_type & BOFI_INTR) && 17890Sstevel@tonic-gate hp->type == BOFI_INT_HDL) || 17900Sstevel@tonic-gate ((errdefp->access_type & BOFI_PIO_RW) && 17910Sstevel@tonic-gate hp->type == BOFI_ACC_HDL && 17920Sstevel@tonic-gate (errdefp->rnumber == -1 || 17930Sstevel@tonic-gate hp->rnumber == errdefp->rnumber) && 17940Sstevel@tonic-gate (errdefp->len == 0 || 17950Sstevel@tonic-gate hp->offset < errdefp->offset + errdefp->len) && 17960Sstevel@tonic-gate hp->offset + hp->len > errdefp->offset))) { 17970Sstevel@tonic-gate lp = bofi_link_freelist; 17980Sstevel@tonic-gate if (lp != NULL) { 17990Sstevel@tonic-gate bofi_link_freelist = lp->link; 18000Sstevel@tonic-gate lp->errentp = ep; 18010Sstevel@tonic-gate lp->link = hp->link; 18020Sstevel@tonic-gate hp->link = lp; 18030Sstevel@tonic-gate } 18040Sstevel@tonic-gate } 18050Sstevel@tonic-gate } 18060Sstevel@tonic-gate errdefp->errdef_handle = (uint64_t)(uintptr_t)ep; 18070Sstevel@tonic-gate mutex_exit(&bofi_mutex); 18080Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 18090Sstevel@tonic-gate ep->softintr_id = NULL; 18100Sstevel@tonic-gate return (ddi_add_softintr(our_dip, DDI_SOFTINT_MED, &ep->softintr_id, 18110Sstevel@tonic-gate NULL, NULL, bofi_signal, (caddr_t)&ep->errdef)); 18120Sstevel@tonic-gate } 18130Sstevel@tonic-gate 18140Sstevel@tonic-gate 18150Sstevel@tonic-gate /* 18160Sstevel@tonic-gate * delete existing errdef 18170Sstevel@tonic-gate */ 18180Sstevel@tonic-gate static int 18190Sstevel@tonic-gate bofi_errdef_free(struct bofi_errent *ep) 18200Sstevel@tonic-gate { 18210Sstevel@tonic-gate struct bofi_errent *hep, *prev_hep; 18220Sstevel@tonic-gate struct bofi_link *lp, *prev_lp, *next_lp; 18230Sstevel@tonic-gate struct bofi_shadow *hp; 18240Sstevel@tonic-gate 18250Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 18260Sstevel@tonic-gate mutex_enter(&bofi_mutex); 18270Sstevel@tonic-gate /* 18280Sstevel@tonic-gate * don't just assume its a valid ep - check that its on the 18290Sstevel@tonic-gate * in-use list 18300Sstevel@tonic-gate */ 18310Sstevel@tonic-gate prev_hep = NULL; 18320Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; ) { 18330Sstevel@tonic-gate if (hep == ep) 18340Sstevel@tonic-gate break; 18350Sstevel@tonic-gate prev_hep = hep; 18360Sstevel@tonic-gate hep = hep->next; 18370Sstevel@tonic-gate } 18380Sstevel@tonic-gate if (hep == NULL) { 18390Sstevel@tonic-gate mutex_exit(&bofi_mutex); 18400Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 18410Sstevel@tonic-gate return (EINVAL); 18420Sstevel@tonic-gate } 18430Sstevel@tonic-gate /* 18440Sstevel@tonic-gate * found it - delete from in-use list 18450Sstevel@tonic-gate */ 18460Sstevel@tonic-gate 18470Sstevel@tonic-gate if (prev_hep) 18480Sstevel@tonic-gate prev_hep->next = hep->next; 18490Sstevel@tonic-gate else 18500Sstevel@tonic-gate errent_listp = hep->next; 18510Sstevel@tonic-gate /* 18520Sstevel@tonic-gate * and take it off the per-clone list 18530Sstevel@tonic-gate */ 18540Sstevel@tonic-gate hep->cnext->cprev = hep->cprev; 18550Sstevel@tonic-gate hep->cprev->cnext = hep->cnext; 18560Sstevel@tonic-gate /* 18570Sstevel@tonic-gate * see if we are on any shadow handle link lists - and if we 18580Sstevel@tonic-gate * are then take us off 18590Sstevel@tonic-gate */ 18600Sstevel@tonic-gate for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) { 18610Sstevel@tonic-gate prev_lp = NULL; 18620Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 18630Sstevel@tonic-gate if (lp->errentp == ep) { 18640Sstevel@tonic-gate if (prev_lp) 18650Sstevel@tonic-gate prev_lp->link = lp->link; 18660Sstevel@tonic-gate else 18670Sstevel@tonic-gate hp->link = lp->link; 18680Sstevel@tonic-gate next_lp = lp->link; 18690Sstevel@tonic-gate lp->link = bofi_link_freelist; 18700Sstevel@tonic-gate bofi_link_freelist = lp; 18710Sstevel@tonic-gate lp = next_lp; 18720Sstevel@tonic-gate } else { 18730Sstevel@tonic-gate prev_lp = lp; 18740Sstevel@tonic-gate lp = lp->link; 18750Sstevel@tonic-gate } 18760Sstevel@tonic-gate } 18770Sstevel@tonic-gate } 18780Sstevel@tonic-gate mutex_exit(&bofi_mutex); 18790Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 18800Sstevel@tonic-gate 18810Sstevel@tonic-gate cv_destroy(&ep->cv); 18820Sstevel@tonic-gate kmem_free(ep->name, ep->errdef.namesize+1); 18830Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_LOG) && 18845204Sstephh ep->errdef.log.logsize && ep->logbase) /* double check */ 18850Sstevel@tonic-gate kmem_free(ep->logbase, 18860Sstevel@tonic-gate sizeof (struct acc_log_elem) * ep->errdef.log.logsize); 18870Sstevel@tonic-gate 18880Sstevel@tonic-gate if (ep->softintr_id) 18890Sstevel@tonic-gate ddi_remove_softintr(ep->softintr_id); 18900Sstevel@tonic-gate kmem_free(ep, sizeof (struct bofi_errent)); 18910Sstevel@tonic-gate return (0); 18920Sstevel@tonic-gate } 18930Sstevel@tonic-gate 18940Sstevel@tonic-gate 18950Sstevel@tonic-gate /* 18960Sstevel@tonic-gate * start all errdefs corresponding to this name and instance 18970Sstevel@tonic-gate */ 18980Sstevel@tonic-gate static void 18990Sstevel@tonic-gate bofi_start(struct bofi_errctl *errctlp, char *namep) 19000Sstevel@tonic-gate { 19010Sstevel@tonic-gate struct bofi_errent *ep; 19020Sstevel@tonic-gate 19030Sstevel@tonic-gate /* 19040Sstevel@tonic-gate * look for any errdefs with matching name and instance 19050Sstevel@tonic-gate */ 19060Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 19070Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 19080Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 19090Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 19100Sstevel@tonic-gate ep->state |= BOFI_DEV_ACTIVE; 19110Sstevel@tonic-gate (void) drv_getparm(TIME, &(ep->errdef.log.start_time)); 19120Sstevel@tonic-gate ep->errdef.log.stop_time = 0ul; 19130Sstevel@tonic-gate } 19140Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 19150Sstevel@tonic-gate } 19160Sstevel@tonic-gate 19170Sstevel@tonic-gate 19180Sstevel@tonic-gate /* 19190Sstevel@tonic-gate * stop all errdefs corresponding to this name and instance 19200Sstevel@tonic-gate */ 19210Sstevel@tonic-gate static void 19220Sstevel@tonic-gate bofi_stop(struct bofi_errctl *errctlp, char *namep) 19230Sstevel@tonic-gate { 19240Sstevel@tonic-gate struct bofi_errent *ep; 19250Sstevel@tonic-gate 19260Sstevel@tonic-gate /* 19270Sstevel@tonic-gate * look for any errdefs with matching name and instance 19280Sstevel@tonic-gate */ 19290Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 19300Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 19310Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 19320Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 19330Sstevel@tonic-gate ep->state &= ~BOFI_DEV_ACTIVE; 19340Sstevel@tonic-gate if (ep->errdef.log.stop_time == 0ul) 19350Sstevel@tonic-gate (void) drv_getparm(TIME, 19360Sstevel@tonic-gate &(ep->errdef.log.stop_time)); 19370Sstevel@tonic-gate } 19380Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 19390Sstevel@tonic-gate } 19400Sstevel@tonic-gate 19410Sstevel@tonic-gate 19420Sstevel@tonic-gate /* 19430Sstevel@tonic-gate * wake up any thread waiting on this errdefs 19440Sstevel@tonic-gate */ 19450Sstevel@tonic-gate static uint_t 19460Sstevel@tonic-gate bofi_signal(caddr_t arg) 19470Sstevel@tonic-gate { 19480Sstevel@tonic-gate struct bofi_errdef *edp = (struct bofi_errdef *)arg; 19490Sstevel@tonic-gate struct bofi_errent *hep; 19500Sstevel@tonic-gate struct bofi_errent *ep = 19510Sstevel@tonic-gate (struct bofi_errent *)(uintptr_t)edp->errdef_handle; 19520Sstevel@tonic-gate 19530Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 19540Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; ) { 19550Sstevel@tonic-gate if (hep == ep) 19560Sstevel@tonic-gate break; 19570Sstevel@tonic-gate hep = hep->next; 19580Sstevel@tonic-gate } 19590Sstevel@tonic-gate if (hep == NULL) { 19600Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 19610Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 19620Sstevel@tonic-gate } 19630Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_LOG) && 19640Sstevel@tonic-gate (edp->log.flags & BOFI_LOG_FULL)) { 19650Sstevel@tonic-gate edp->log.stop_time = bofi_gettime(); 19660Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 19670Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 19680Sstevel@tonic-gate cv_broadcast(&ep->cv); 19690Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 19700Sstevel@tonic-gate } 19710Sstevel@tonic-gate if (ep->errstate.msg_time != 0) { 19720Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 19730Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 19740Sstevel@tonic-gate cv_broadcast(&ep->cv); 19750Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 19760Sstevel@tonic-gate } 19770Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 19780Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 19790Sstevel@tonic-gate } 19800Sstevel@tonic-gate 19810Sstevel@tonic-gate 19820Sstevel@tonic-gate /* 19830Sstevel@tonic-gate * wake up all errdefs corresponding to this name and instance 19840Sstevel@tonic-gate */ 19850Sstevel@tonic-gate static void 19860Sstevel@tonic-gate bofi_broadcast(struct bofi_errctl *errctlp, char *namep) 19870Sstevel@tonic-gate { 19880Sstevel@tonic-gate struct bofi_errent *ep; 19890Sstevel@tonic-gate 19900Sstevel@tonic-gate /* 19910Sstevel@tonic-gate * look for any errdefs with matching name and instance 19920Sstevel@tonic-gate */ 19930Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 19940Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 19950Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 19960Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 19970Sstevel@tonic-gate /* 19980Sstevel@tonic-gate * wake up sleepers 19990Sstevel@tonic-gate */ 20000Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 20010Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 20020Sstevel@tonic-gate cv_broadcast(&ep->cv); 20030Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 20040Sstevel@tonic-gate } 20050Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 20060Sstevel@tonic-gate } 20070Sstevel@tonic-gate 20080Sstevel@tonic-gate 20090Sstevel@tonic-gate /* 20100Sstevel@tonic-gate * clear "acc_chk" for all errdefs corresponding to this name and instance 20110Sstevel@tonic-gate * and wake them up. 20120Sstevel@tonic-gate */ 20130Sstevel@tonic-gate static void 20140Sstevel@tonic-gate bofi_clear_acc_chk(struct bofi_errctl *errctlp, char *namep) 20150Sstevel@tonic-gate { 20160Sstevel@tonic-gate struct bofi_errent *ep; 20170Sstevel@tonic-gate 20180Sstevel@tonic-gate /* 20190Sstevel@tonic-gate * look for any errdefs with matching name and instance 20200Sstevel@tonic-gate */ 20210Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 20220Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 20230Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 20240Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 20250Sstevel@tonic-gate mutex_enter(&bofi_mutex); 20260Sstevel@tonic-gate if (ep->errdef.access_count == 0 && 20270Sstevel@tonic-gate ep->errdef.fail_count == 0) 20280Sstevel@tonic-gate ep->errdef.acc_chk = 0; 20290Sstevel@tonic-gate mutex_exit(&bofi_mutex); 20300Sstevel@tonic-gate /* 20310Sstevel@tonic-gate * wake up sleepers 20320Sstevel@tonic-gate */ 20330Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 20340Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 20350Sstevel@tonic-gate cv_broadcast(&ep->cv); 20360Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 20370Sstevel@tonic-gate } 20380Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 20390Sstevel@tonic-gate } 20400Sstevel@tonic-gate 20410Sstevel@tonic-gate 20420Sstevel@tonic-gate /* 20430Sstevel@tonic-gate * set "fail_count" to 0 for all errdefs corresponding to this name and instance 20440Sstevel@tonic-gate * whose "access_count" has expired, set "acc_chk" to 0 and wake them up. 20450Sstevel@tonic-gate */ 20460Sstevel@tonic-gate static void 20470Sstevel@tonic-gate bofi_clear_errors(struct bofi_errctl *errctlp, char *namep) 20480Sstevel@tonic-gate { 20490Sstevel@tonic-gate struct bofi_errent *ep; 20500Sstevel@tonic-gate 20510Sstevel@tonic-gate /* 20520Sstevel@tonic-gate * look for any errdefs with matching name and instance 20530Sstevel@tonic-gate */ 20540Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 20550Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 20560Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 20570Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 20580Sstevel@tonic-gate mutex_enter(&bofi_mutex); 20590Sstevel@tonic-gate if (ep->errdef.access_count == 0) { 20600Sstevel@tonic-gate ep->errdef.acc_chk = 0; 20610Sstevel@tonic-gate ep->errdef.fail_count = 0; 20620Sstevel@tonic-gate mutex_exit(&bofi_mutex); 20630Sstevel@tonic-gate if (ep->errdef.log.stop_time == 0ul) 20640Sstevel@tonic-gate (void) drv_getparm(TIME, 20650Sstevel@tonic-gate &(ep->errdef.log.stop_time)); 20660Sstevel@tonic-gate } else 20670Sstevel@tonic-gate mutex_exit(&bofi_mutex); 20680Sstevel@tonic-gate /* 20690Sstevel@tonic-gate * wake up sleepers 20700Sstevel@tonic-gate */ 20710Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 20720Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 20730Sstevel@tonic-gate cv_broadcast(&ep->cv); 20740Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 20750Sstevel@tonic-gate } 20760Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 20770Sstevel@tonic-gate } 20780Sstevel@tonic-gate 20790Sstevel@tonic-gate 20800Sstevel@tonic-gate /* 20810Sstevel@tonic-gate * set "access_count" and "fail_count" to 0 for all errdefs corresponding to 20820Sstevel@tonic-gate * this name and instance, set "acc_chk" to 0, and wake them up. 20830Sstevel@tonic-gate */ 20840Sstevel@tonic-gate static void 20850Sstevel@tonic-gate bofi_clear_errdefs(struct bofi_errctl *errctlp, char *namep) 20860Sstevel@tonic-gate { 20870Sstevel@tonic-gate struct bofi_errent *ep; 20880Sstevel@tonic-gate 20890Sstevel@tonic-gate /* 20900Sstevel@tonic-gate * look for any errdefs with matching name and instance 20910Sstevel@tonic-gate */ 20920Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 20930Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 20940Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 20950Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 20960Sstevel@tonic-gate mutex_enter(&bofi_mutex); 20970Sstevel@tonic-gate ep->errdef.acc_chk = 0; 20980Sstevel@tonic-gate ep->errdef.access_count = 0; 20990Sstevel@tonic-gate ep->errdef.fail_count = 0; 21000Sstevel@tonic-gate mutex_exit(&bofi_mutex); 21010Sstevel@tonic-gate if (ep->errdef.log.stop_time == 0ul) 21020Sstevel@tonic-gate (void) drv_getparm(TIME, 21030Sstevel@tonic-gate &(ep->errdef.log.stop_time)); 21040Sstevel@tonic-gate /* 21050Sstevel@tonic-gate * wake up sleepers 21060Sstevel@tonic-gate */ 21070Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 21080Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 21090Sstevel@tonic-gate cv_broadcast(&ep->cv); 21100Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 21110Sstevel@tonic-gate } 21120Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 21130Sstevel@tonic-gate } 21140Sstevel@tonic-gate 21150Sstevel@tonic-gate 21160Sstevel@tonic-gate /* 21170Sstevel@tonic-gate * get state for this errdef 21180Sstevel@tonic-gate */ 21190Sstevel@tonic-gate static int 21200Sstevel@tonic-gate bofi_errdef_check(struct bofi_errstate *errstatep, struct acc_log_elem **logpp) 21210Sstevel@tonic-gate { 21220Sstevel@tonic-gate struct bofi_errent *hep; 21230Sstevel@tonic-gate struct bofi_errent *ep; 21240Sstevel@tonic-gate 21250Sstevel@tonic-gate ep = (struct bofi_errent *)(uintptr_t)errstatep->errdef_handle; 21260Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 21270Sstevel@tonic-gate /* 21280Sstevel@tonic-gate * don't just assume its a valid ep - check that its on the 21290Sstevel@tonic-gate * in-use list 21300Sstevel@tonic-gate */ 21310Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; hep = hep->next) 21320Sstevel@tonic-gate if (hep == ep) 21330Sstevel@tonic-gate break; 21340Sstevel@tonic-gate if (hep == NULL) { 21350Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 21360Sstevel@tonic-gate return (EINVAL); 21370Sstevel@tonic-gate } 21380Sstevel@tonic-gate mutex_enter(&bofi_mutex); 21390Sstevel@tonic-gate ep->errstate.access_count = ep->errdef.access_count; 21400Sstevel@tonic-gate ep->errstate.fail_count = ep->errdef.fail_count; 21410Sstevel@tonic-gate ep->errstate.acc_chk = ep->errdef.acc_chk; 21420Sstevel@tonic-gate ep->errstate.log = ep->errdef.log; 21430Sstevel@tonic-gate *logpp = ep->logbase; 21440Sstevel@tonic-gate *errstatep = ep->errstate; 21450Sstevel@tonic-gate mutex_exit(&bofi_mutex); 21460Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 21470Sstevel@tonic-gate return (0); 21480Sstevel@tonic-gate } 21490Sstevel@tonic-gate 21500Sstevel@tonic-gate 21510Sstevel@tonic-gate /* 21520Sstevel@tonic-gate * Wait for a ddi_report_fault message to come back for this errdef 21530Sstevel@tonic-gate * Then return state for this errdef. 21540Sstevel@tonic-gate * fault report is intercepted by bofi_post_event, which triggers 21550Sstevel@tonic-gate * bofi_signal via a softint, which will wake up this routine if 21560Sstevel@tonic-gate * we are waiting 21570Sstevel@tonic-gate */ 21580Sstevel@tonic-gate static int 21590Sstevel@tonic-gate bofi_errdef_check_w(struct bofi_errstate *errstatep, 21600Sstevel@tonic-gate struct acc_log_elem **logpp) 21610Sstevel@tonic-gate { 21620Sstevel@tonic-gate struct bofi_errent *hep; 21630Sstevel@tonic-gate struct bofi_errent *ep; 21640Sstevel@tonic-gate int rval = 0; 21650Sstevel@tonic-gate 21660Sstevel@tonic-gate ep = (struct bofi_errent *)(uintptr_t)errstatep->errdef_handle; 21670Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 21680Sstevel@tonic-gate retry: 21690Sstevel@tonic-gate /* 21700Sstevel@tonic-gate * don't just assume its a valid ep - check that its on the 21710Sstevel@tonic-gate * in-use list 21720Sstevel@tonic-gate */ 21730Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; hep = hep->next) 21740Sstevel@tonic-gate if (hep == ep) 21750Sstevel@tonic-gate break; 21760Sstevel@tonic-gate if (hep == NULL) { 21770Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 21780Sstevel@tonic-gate return (EINVAL); 21790Sstevel@tonic-gate } 21800Sstevel@tonic-gate /* 21810Sstevel@tonic-gate * wait for ddi_report_fault for the devinfo corresponding 21820Sstevel@tonic-gate * to this errdef 21830Sstevel@tonic-gate */ 21840Sstevel@tonic-gate if (rval == 0 && !(ep->state & BOFI_NEW_MESSAGE)) { 21850Sstevel@tonic-gate ep->state |= BOFI_MESSAGE_WAIT; 21861865Sdilpreet if (cv_wait_sig(&ep->cv, &bofi_low_mutex) == 0) { 21871865Sdilpreet if (!(ep->state & BOFI_NEW_MESSAGE)) 21881865Sdilpreet rval = EINTR; 21891865Sdilpreet } 21900Sstevel@tonic-gate goto retry; 21910Sstevel@tonic-gate } 21920Sstevel@tonic-gate ep->state &= ~BOFI_NEW_MESSAGE; 21930Sstevel@tonic-gate /* 21940Sstevel@tonic-gate * we either didn't need to sleep, we've been woken up or we've been 21950Sstevel@tonic-gate * signaled - either way return state now 21960Sstevel@tonic-gate */ 21970Sstevel@tonic-gate mutex_enter(&bofi_mutex); 21980Sstevel@tonic-gate ep->errstate.access_count = ep->errdef.access_count; 21990Sstevel@tonic-gate ep->errstate.fail_count = ep->errdef.fail_count; 22000Sstevel@tonic-gate ep->errstate.acc_chk = ep->errdef.acc_chk; 22010Sstevel@tonic-gate ep->errstate.log = ep->errdef.log; 22020Sstevel@tonic-gate *logpp = ep->logbase; 22030Sstevel@tonic-gate *errstatep = ep->errstate; 22040Sstevel@tonic-gate mutex_exit(&bofi_mutex); 22050Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 22060Sstevel@tonic-gate return (rval); 22070Sstevel@tonic-gate } 22080Sstevel@tonic-gate 22090Sstevel@tonic-gate 22100Sstevel@tonic-gate /* 22110Sstevel@tonic-gate * support routine - check if requested driver is defined as under test in the 22120Sstevel@tonic-gate * conf file. 22130Sstevel@tonic-gate */ 22140Sstevel@tonic-gate static int 22150Sstevel@tonic-gate driver_under_test(dev_info_t *rdip) 22160Sstevel@tonic-gate { 22170Sstevel@tonic-gate int i; 22180Sstevel@tonic-gate char *rname; 22190Sstevel@tonic-gate major_t rmaj; 22200Sstevel@tonic-gate 22210Sstevel@tonic-gate rname = ddi_get_name(rdip); 22220Sstevel@tonic-gate rmaj = ddi_name_to_major(rname); 22230Sstevel@tonic-gate 22240Sstevel@tonic-gate /* 22250Sstevel@tonic-gate * Enforce the user to specifically request the following drivers. 22260Sstevel@tonic-gate */ 22270Sstevel@tonic-gate for (i = 0; i < driver_list_size; i += (1 + strlen(&driver_list[i]))) { 22280Sstevel@tonic-gate if (driver_list_neg == 0) { 22290Sstevel@tonic-gate if (rmaj == ddi_name_to_major(&driver_list[i])) 22300Sstevel@tonic-gate return (1); 22310Sstevel@tonic-gate } else { 22320Sstevel@tonic-gate if (rmaj == ddi_name_to_major(&driver_list[i+1])) 22330Sstevel@tonic-gate return (0); 22340Sstevel@tonic-gate } 22350Sstevel@tonic-gate } 22360Sstevel@tonic-gate if (driver_list_neg == 0) 22370Sstevel@tonic-gate return (0); 22380Sstevel@tonic-gate else 22390Sstevel@tonic-gate return (1); 22400Sstevel@tonic-gate 22410Sstevel@tonic-gate } 22420Sstevel@tonic-gate 22430Sstevel@tonic-gate 22440Sstevel@tonic-gate static void 22450Sstevel@tonic-gate log_acc_event(struct bofi_errent *ep, uint_t at, offset_t offset, off_t len, 22460Sstevel@tonic-gate size_t repcount, uint64_t *valuep) 22470Sstevel@tonic-gate { 22480Sstevel@tonic-gate struct bofi_errdef *edp = &(ep->errdef); 22490Sstevel@tonic-gate struct acc_log *log = &edp->log; 22500Sstevel@tonic-gate 22510Sstevel@tonic-gate ASSERT(log != NULL); 22520Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 22530Sstevel@tonic-gate 22540Sstevel@tonic-gate if (log->flags & BOFI_LOG_REPIO) 22550Sstevel@tonic-gate repcount = 1; 22560Sstevel@tonic-gate else if (repcount == 0 && edp->access_count > 0 && 22575204Sstephh (log->flags & BOFI_LOG_FULL) == 0) 22580Sstevel@tonic-gate edp->access_count += 1; 22590Sstevel@tonic-gate 22600Sstevel@tonic-gate if (repcount && log->entries < log->logsize) { 22610Sstevel@tonic-gate struct acc_log_elem *elem = ep->logbase + log->entries; 22620Sstevel@tonic-gate 22630Sstevel@tonic-gate if (log->flags & BOFI_LOG_TIMESTAMP) 22640Sstevel@tonic-gate elem->access_time = bofi_gettime(); 22650Sstevel@tonic-gate elem->access_type = at; 22660Sstevel@tonic-gate elem->offset = offset; 22670Sstevel@tonic-gate elem->value = valuep ? *valuep : 0ll; 22680Sstevel@tonic-gate elem->size = len; 22690Sstevel@tonic-gate elem->repcount = repcount; 22700Sstevel@tonic-gate ++log->entries; 22710Sstevel@tonic-gate if (log->entries == log->logsize) { 22720Sstevel@tonic-gate log->flags |= BOFI_LOG_FULL; 22730Sstevel@tonic-gate ddi_trigger_softintr(((struct bofi_errent *) 22740Sstevel@tonic-gate (uintptr_t)edp->errdef_handle)->softintr_id); 22750Sstevel@tonic-gate } 22760Sstevel@tonic-gate } 22770Sstevel@tonic-gate if ((log->flags & BOFI_LOG_WRAP) && edp->access_count <= 1) { 22780Sstevel@tonic-gate log->wrapcnt++; 22790Sstevel@tonic-gate edp->access_count = log->logsize; 22800Sstevel@tonic-gate log->entries = 0; /* wrap back to the start */ 22810Sstevel@tonic-gate } 22820Sstevel@tonic-gate } 22830Sstevel@tonic-gate 22840Sstevel@tonic-gate 22850Sstevel@tonic-gate /* 22860Sstevel@tonic-gate * got a condition match on dma read/write - check counts and corrupt 22870Sstevel@tonic-gate * data if necessary 22880Sstevel@tonic-gate * 22890Sstevel@tonic-gate * bofi_mutex always held when this is called. 22900Sstevel@tonic-gate */ 22910Sstevel@tonic-gate static void 22920Sstevel@tonic-gate do_dma_corrupt(struct bofi_shadow *hp, struct bofi_errent *ep, 22930Sstevel@tonic-gate uint_t synctype, off_t off, off_t length) 22940Sstevel@tonic-gate { 22950Sstevel@tonic-gate uint64_t operand; 22960Sstevel@tonic-gate int i; 22970Sstevel@tonic-gate off_t len; 22980Sstevel@tonic-gate caddr_t logaddr; 22990Sstevel@tonic-gate uint64_t *addr; 23000Sstevel@tonic-gate uint64_t *endaddr; 23011865Sdilpreet ddi_dma_impl_t *hdlp; 23021865Sdilpreet ndi_err_t *errp; 23030Sstevel@tonic-gate 23040Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 23050Sstevel@tonic-gate if ((ep->errdef.access_count || 23065204Sstephh ep->errdef.fail_count) && 23075204Sstephh (ep->errdef.access_type & BOFI_LOG)) { 23080Sstevel@tonic-gate uint_t atype; 23090Sstevel@tonic-gate 23100Sstevel@tonic-gate if (synctype == DDI_DMA_SYNC_FORDEV) 23110Sstevel@tonic-gate atype = BOFI_DMA_W; 23120Sstevel@tonic-gate else if (synctype == DDI_DMA_SYNC_FORCPU || 23135204Sstephh synctype == DDI_DMA_SYNC_FORKERNEL) 23140Sstevel@tonic-gate atype = BOFI_DMA_R; 23150Sstevel@tonic-gate else 23160Sstevel@tonic-gate atype = 0; 23170Sstevel@tonic-gate if ((off <= ep->errdef.offset && 23185204Sstephh off + length > ep->errdef.offset) || 23195204Sstephh (off > ep->errdef.offset && 23205204Sstephh off < ep->errdef.offset + ep->errdef.len)) { 23210Sstevel@tonic-gate logaddr = (caddr_t)((uintptr_t)(hp->addr + 23220Sstevel@tonic-gate off + LLSZMASK) & ~LLSZMASK); 23230Sstevel@tonic-gate 23240Sstevel@tonic-gate log_acc_event(ep, atype, logaddr - hp->addr, 23250Sstevel@tonic-gate length, 1, 0); 23260Sstevel@tonic-gate } 23270Sstevel@tonic-gate } 23280Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 23290Sstevel@tonic-gate ep->errdef.access_count--; 23300Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 23310Sstevel@tonic-gate ep->errdef.fail_count--; 23320Sstevel@tonic-gate ep->errdef.access_count = 0; 23330Sstevel@tonic-gate /* 23340Sstevel@tonic-gate * OK do the corruption 23350Sstevel@tonic-gate */ 23360Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 23370Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 23380Sstevel@tonic-gate /* 23390Sstevel@tonic-gate * work out how much to corrupt 23400Sstevel@tonic-gate * 23410Sstevel@tonic-gate * Make sure endaddr isn't greater than hp->addr + hp->len. 23420Sstevel@tonic-gate * If endaddr becomes less than addr len becomes negative 23430Sstevel@tonic-gate * and the following loop isn't entered. 23440Sstevel@tonic-gate */ 23450Sstevel@tonic-gate addr = (uint64_t *)((uintptr_t)((hp->addr + 23460Sstevel@tonic-gate ep->errdef.offset) + LLSZMASK) & ~LLSZMASK); 23470Sstevel@tonic-gate endaddr = (uint64_t *)((uintptr_t)(hp->addr + min(hp->len, 23480Sstevel@tonic-gate ep->errdef.offset + ep->errdef.len)) & ~LLSZMASK); 23490Sstevel@tonic-gate len = endaddr - addr; 23500Sstevel@tonic-gate operand = ep->errdef.operand; 23511865Sdilpreet hdlp = (ddi_dma_impl_t *)(hp->hdl.dma_handle); 23521865Sdilpreet errp = &hdlp->dmai_error; 23531865Sdilpreet if (ep->errdef.acc_chk & 2) { 23541865Sdilpreet uint64_t ena; 23551865Sdilpreet char buf[FM_MAX_CLASS]; 23561865Sdilpreet 23571865Sdilpreet errp->err_status = DDI_FM_NONFATAL; 23581865Sdilpreet (void) snprintf(buf, FM_MAX_CLASS, FM_SIMULATED_DMA); 23591865Sdilpreet ena = fm_ena_generate(0, FM_ENA_FMT1); 23601865Sdilpreet ddi_fm_ereport_post(hp->dip, buf, ena, 23611865Sdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 23621865Sdilpreet FM_EREPORT_VERS0, NULL); 23631865Sdilpreet } 23640Sstevel@tonic-gate switch (ep->errdef.optype) { 23650Sstevel@tonic-gate case BOFI_EQUAL : 23660Sstevel@tonic-gate for (i = 0; i < len; i++) 23670Sstevel@tonic-gate *(addr + i) = operand; 23680Sstevel@tonic-gate break; 23690Sstevel@tonic-gate case BOFI_AND : 23700Sstevel@tonic-gate for (i = 0; i < len; i++) 23710Sstevel@tonic-gate *(addr + i) &= operand; 23720Sstevel@tonic-gate break; 23730Sstevel@tonic-gate case BOFI_OR : 23740Sstevel@tonic-gate for (i = 0; i < len; i++) 23750Sstevel@tonic-gate *(addr + i) |= operand; 23760Sstevel@tonic-gate break; 23770Sstevel@tonic-gate case BOFI_XOR : 23780Sstevel@tonic-gate for (i = 0; i < len; i++) 23790Sstevel@tonic-gate *(addr + i) ^= operand; 23800Sstevel@tonic-gate break; 23810Sstevel@tonic-gate default: 23820Sstevel@tonic-gate /* do nothing */ 23830Sstevel@tonic-gate break; 23840Sstevel@tonic-gate } 23850Sstevel@tonic-gate } 23860Sstevel@tonic-gate } 23870Sstevel@tonic-gate 23880Sstevel@tonic-gate 23890Sstevel@tonic-gate static uint64_t do_bofi_rd8(struct bofi_shadow *, caddr_t); 23900Sstevel@tonic-gate static uint64_t do_bofi_rd16(struct bofi_shadow *, caddr_t); 23910Sstevel@tonic-gate static uint64_t do_bofi_rd32(struct bofi_shadow *, caddr_t); 23920Sstevel@tonic-gate static uint64_t do_bofi_rd64(struct bofi_shadow *, caddr_t); 23930Sstevel@tonic-gate 23940Sstevel@tonic-gate 23950Sstevel@tonic-gate /* 23960Sstevel@tonic-gate * check all errdefs linked to this shadow handle. If we've got a condition 23970Sstevel@tonic-gate * match check counts and corrupt data if necessary 23980Sstevel@tonic-gate * 23990Sstevel@tonic-gate * bofi_mutex always held when this is called. 24000Sstevel@tonic-gate * 24010Sstevel@tonic-gate * because of possibility of BOFI_NO_TRANSFER, we couldn't get data 24020Sstevel@tonic-gate * from io-space before calling this, so we pass in the func to do the 24030Sstevel@tonic-gate * transfer as a parameter. 24040Sstevel@tonic-gate */ 24050Sstevel@tonic-gate static uint64_t 24060Sstevel@tonic-gate do_pior_corrupt(struct bofi_shadow *hp, caddr_t addr, 24070Sstevel@tonic-gate uint64_t (*func)(), size_t repcount, size_t accsize) 24080Sstevel@tonic-gate { 24090Sstevel@tonic-gate struct bofi_errent *ep; 24100Sstevel@tonic-gate struct bofi_link *lp; 24110Sstevel@tonic-gate uint64_t operand; 24120Sstevel@tonic-gate uintptr_t minlen; 24130Sstevel@tonic-gate intptr_t base; 24140Sstevel@tonic-gate int done_get = 0; 24150Sstevel@tonic-gate uint64_t get_val, gv; 24161865Sdilpreet ddi_acc_impl_t *hdlp; 24171865Sdilpreet ndi_err_t *errp; 24180Sstevel@tonic-gate 24190Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 24200Sstevel@tonic-gate /* 24210Sstevel@tonic-gate * check through all errdefs associated with this shadow handle 24220Sstevel@tonic-gate */ 24230Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 24240Sstevel@tonic-gate ep = lp->errentp; 24250Sstevel@tonic-gate if (ep->errdef.len == 0) 24260Sstevel@tonic-gate minlen = hp->len; 24270Sstevel@tonic-gate else 24280Sstevel@tonic-gate minlen = min(hp->len, ep->errdef.len); 24290Sstevel@tonic-gate base = addr - hp->addr - ep->errdef.offset + hp->offset; 24300Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_PIO_R) && 24310Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE) && 24320Sstevel@tonic-gate base >= 0 && base < minlen) { 24330Sstevel@tonic-gate /* 24340Sstevel@tonic-gate * condition match for pio read 24350Sstevel@tonic-gate */ 24360Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 24370Sstevel@tonic-gate ep->errdef.access_count--; 24380Sstevel@tonic-gate if (done_get == 0) { 24390Sstevel@tonic-gate done_get = 1; 24400Sstevel@tonic-gate gv = get_val = func(hp, addr); 24410Sstevel@tonic-gate } 24420Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) { 24430Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_R, 24440Sstevel@tonic-gate addr - hp->addr, 24450Sstevel@tonic-gate accsize, repcount, &gv); 24460Sstevel@tonic-gate } 24470Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 24480Sstevel@tonic-gate ep->errdef.fail_count--; 24490Sstevel@tonic-gate ep->errdef.access_count = 0; 24500Sstevel@tonic-gate /* 24510Sstevel@tonic-gate * OK do corruption 24520Sstevel@tonic-gate */ 24530Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 24540Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 24550Sstevel@tonic-gate operand = ep->errdef.operand; 24560Sstevel@tonic-gate if (done_get == 0) { 24570Sstevel@tonic-gate if (ep->errdef.optype == 24580Sstevel@tonic-gate BOFI_NO_TRANSFER) 24590Sstevel@tonic-gate /* 24600Sstevel@tonic-gate * no transfer - bomb out 24610Sstevel@tonic-gate */ 24620Sstevel@tonic-gate return (operand); 24630Sstevel@tonic-gate done_get = 1; 24640Sstevel@tonic-gate gv = get_val = func(hp, addr); 24650Sstevel@tonic-gate 24660Sstevel@tonic-gate } 24670Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) { 24680Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_R, 24690Sstevel@tonic-gate addr - hp->addr, 24700Sstevel@tonic-gate accsize, repcount, &gv); 24710Sstevel@tonic-gate } 24721865Sdilpreet hdlp = (ddi_acc_impl_t *)(hp->hdl.acc_handle); 24731865Sdilpreet errp = hdlp->ahi_err; 24741865Sdilpreet if (ep->errdef.acc_chk & 1) { 24751865Sdilpreet uint64_t ena; 24761865Sdilpreet char buf[FM_MAX_CLASS]; 24771865Sdilpreet 24781865Sdilpreet errp->err_status = DDI_FM_NONFATAL; 24791865Sdilpreet (void) snprintf(buf, FM_MAX_CLASS, 24801865Sdilpreet FM_SIMULATED_PIO); 24811865Sdilpreet ena = fm_ena_generate(0, FM_ENA_FMT1); 24821865Sdilpreet ddi_fm_ereport_post(hp->dip, buf, ena, 24831865Sdilpreet DDI_NOSLEEP, FM_VERSION, 24841865Sdilpreet DATA_TYPE_UINT8, FM_EREPORT_VERS0, 24851865Sdilpreet NULL); 24861865Sdilpreet } 24870Sstevel@tonic-gate switch (ep->errdef.optype) { 24880Sstevel@tonic-gate case BOFI_EQUAL : 24890Sstevel@tonic-gate get_val = operand; 24900Sstevel@tonic-gate break; 24910Sstevel@tonic-gate case BOFI_AND : 24920Sstevel@tonic-gate get_val &= operand; 24930Sstevel@tonic-gate break; 24940Sstevel@tonic-gate case BOFI_OR : 24950Sstevel@tonic-gate get_val |= operand; 24960Sstevel@tonic-gate break; 24970Sstevel@tonic-gate case BOFI_XOR : 24980Sstevel@tonic-gate get_val ^= operand; 24990Sstevel@tonic-gate break; 25000Sstevel@tonic-gate default: 25010Sstevel@tonic-gate /* do nothing */ 25020Sstevel@tonic-gate break; 25030Sstevel@tonic-gate } 25040Sstevel@tonic-gate } 25050Sstevel@tonic-gate } 25060Sstevel@tonic-gate } 25070Sstevel@tonic-gate if (done_get == 0) 25080Sstevel@tonic-gate return (func(hp, addr)); 25090Sstevel@tonic-gate else 25100Sstevel@tonic-gate return (get_val); 25110Sstevel@tonic-gate } 25120Sstevel@tonic-gate 25130Sstevel@tonic-gate 25140Sstevel@tonic-gate /* 25150Sstevel@tonic-gate * check all errdefs linked to this shadow handle. If we've got a condition 25160Sstevel@tonic-gate * match check counts and corrupt data if necessary 25170Sstevel@tonic-gate * 25180Sstevel@tonic-gate * bofi_mutex always held when this is called. 25190Sstevel@tonic-gate * 25200Sstevel@tonic-gate * because of possibility of BOFI_NO_TRANSFER, we return 0 if no data 25210Sstevel@tonic-gate * is to be written out to io-space, 1 otherwise 25220Sstevel@tonic-gate */ 25230Sstevel@tonic-gate static int 25240Sstevel@tonic-gate do_piow_corrupt(struct bofi_shadow *hp, caddr_t addr, uint64_t *valuep, 25250Sstevel@tonic-gate size_t size, size_t repcount) 25260Sstevel@tonic-gate { 25270Sstevel@tonic-gate struct bofi_errent *ep; 25280Sstevel@tonic-gate struct bofi_link *lp; 25290Sstevel@tonic-gate uintptr_t minlen; 25300Sstevel@tonic-gate intptr_t base; 25310Sstevel@tonic-gate uint64_t v = *valuep; 25321865Sdilpreet ddi_acc_impl_t *hdlp; 25331865Sdilpreet ndi_err_t *errp; 25340Sstevel@tonic-gate 25350Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 25360Sstevel@tonic-gate /* 25370Sstevel@tonic-gate * check through all errdefs associated with this shadow handle 25380Sstevel@tonic-gate */ 25390Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 25400Sstevel@tonic-gate ep = lp->errentp; 25410Sstevel@tonic-gate if (ep->errdef.len == 0) 25420Sstevel@tonic-gate minlen = hp->len; 25430Sstevel@tonic-gate else 25440Sstevel@tonic-gate minlen = min(hp->len, ep->errdef.len); 25450Sstevel@tonic-gate base = (caddr_t)addr - hp->addr - ep->errdef.offset +hp->offset; 25460Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_PIO_W) && 25470Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE) && 25480Sstevel@tonic-gate base >= 0 && base < minlen) { 25490Sstevel@tonic-gate /* 25500Sstevel@tonic-gate * condition match for pio write 25510Sstevel@tonic-gate */ 25520Sstevel@tonic-gate 25530Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 25540Sstevel@tonic-gate ep->errdef.access_count--; 25550Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) 25560Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_W, 25570Sstevel@tonic-gate addr - hp->addr, size, 25580Sstevel@tonic-gate repcount, &v); 25590Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 25600Sstevel@tonic-gate ep->errdef.fail_count--; 25610Sstevel@tonic-gate ep->errdef.access_count = 0; 25620Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) 25630Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_W, 25640Sstevel@tonic-gate addr - hp->addr, size, 25650Sstevel@tonic-gate repcount, &v); 25660Sstevel@tonic-gate /* 25670Sstevel@tonic-gate * OK do corruption 25680Sstevel@tonic-gate */ 25690Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 25700Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 25711865Sdilpreet hdlp = (ddi_acc_impl_t *)(hp->hdl.acc_handle); 25721865Sdilpreet errp = hdlp->ahi_err; 25731865Sdilpreet if (ep->errdef.acc_chk & 1) { 25741865Sdilpreet uint64_t ena; 25751865Sdilpreet char buf[FM_MAX_CLASS]; 25761865Sdilpreet 25771865Sdilpreet errp->err_status = DDI_FM_NONFATAL; 25781865Sdilpreet (void) snprintf(buf, FM_MAX_CLASS, 25791865Sdilpreet FM_SIMULATED_PIO); 25801865Sdilpreet ena = fm_ena_generate(0, FM_ENA_FMT1); 25811865Sdilpreet ddi_fm_ereport_post(hp->dip, buf, ena, 25821865Sdilpreet DDI_NOSLEEP, FM_VERSION, 25831865Sdilpreet DATA_TYPE_UINT8, FM_EREPORT_VERS0, 25841865Sdilpreet NULL); 25851865Sdilpreet } 25860Sstevel@tonic-gate switch (ep->errdef.optype) { 25870Sstevel@tonic-gate case BOFI_EQUAL : 25880Sstevel@tonic-gate *valuep = ep->errdef.operand; 25890Sstevel@tonic-gate break; 25900Sstevel@tonic-gate case BOFI_AND : 25910Sstevel@tonic-gate *valuep &= ep->errdef.operand; 25920Sstevel@tonic-gate break; 25930Sstevel@tonic-gate case BOFI_OR : 25940Sstevel@tonic-gate *valuep |= ep->errdef.operand; 25950Sstevel@tonic-gate break; 25960Sstevel@tonic-gate case BOFI_XOR : 25970Sstevel@tonic-gate *valuep ^= ep->errdef.operand; 25980Sstevel@tonic-gate break; 25990Sstevel@tonic-gate case BOFI_NO_TRANSFER : 26000Sstevel@tonic-gate /* 26010Sstevel@tonic-gate * no transfer - bomb out 26020Sstevel@tonic-gate */ 26030Sstevel@tonic-gate return (0); 26040Sstevel@tonic-gate default: 26050Sstevel@tonic-gate /* do nothing */ 26060Sstevel@tonic-gate break; 26070Sstevel@tonic-gate } 26080Sstevel@tonic-gate } 26090Sstevel@tonic-gate } 26100Sstevel@tonic-gate } 26110Sstevel@tonic-gate return (1); 26120Sstevel@tonic-gate } 26130Sstevel@tonic-gate 26140Sstevel@tonic-gate 26150Sstevel@tonic-gate static uint64_t 26160Sstevel@tonic-gate do_bofi_rd8(struct bofi_shadow *hp, caddr_t addr) 26170Sstevel@tonic-gate { 26180Sstevel@tonic-gate return (hp->save.acc.ahi_get8(&hp->save.acc, (uint8_t *)addr)); 26190Sstevel@tonic-gate } 26200Sstevel@tonic-gate 26210Sstevel@tonic-gate #define BOFI_READ_CHECKS(type) \ 26220Sstevel@tonic-gate if (bofi_ddi_check) \ 26230Sstevel@tonic-gate addr = (type *)((uintptr_t)addr - 64 + hp->addr); \ 26240Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)addr < hp->addr || \ 26250Sstevel@tonic-gate (caddr_t)addr - hp->addr >= hp->len)) { \ 26260Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 26270Sstevel@tonic-gate "ddi_get() out of range addr %p not in %p/%llx", \ 26280Sstevel@tonic-gate (void *)addr, (void *)hp->addr, hp->len); \ 26290Sstevel@tonic-gate return (0); \ 26300Sstevel@tonic-gate } 26310Sstevel@tonic-gate 26320Sstevel@tonic-gate /* 26330Sstevel@tonic-gate * our getb() routine - use tryenter 26340Sstevel@tonic-gate */ 26350Sstevel@tonic-gate static uint8_t 26360Sstevel@tonic-gate bofi_rd8(ddi_acc_impl_t *handle, uint8_t *addr) 26370Sstevel@tonic-gate { 26380Sstevel@tonic-gate struct bofi_shadow *hp; 26390Sstevel@tonic-gate uint8_t retval; 26400Sstevel@tonic-gate 26410Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 26420Sstevel@tonic-gate BOFI_READ_CHECKS(uint8_t) 26430Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 26440Sstevel@tonic-gate return (hp->save.acc.ahi_get8(&hp->save.acc, addr)); 26450Sstevel@tonic-gate retval = (uint8_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd8, 1, 26460Sstevel@tonic-gate 1); 26470Sstevel@tonic-gate mutex_exit(&bofi_mutex); 26480Sstevel@tonic-gate return (retval); 26490Sstevel@tonic-gate } 26500Sstevel@tonic-gate 26510Sstevel@tonic-gate 26520Sstevel@tonic-gate static uint64_t 26530Sstevel@tonic-gate do_bofi_rd16(struct bofi_shadow *hp, caddr_t addr) 26540Sstevel@tonic-gate { 26550Sstevel@tonic-gate return (hp->save.acc.ahi_get16(&hp->save.acc, (uint16_t *)addr)); 26560Sstevel@tonic-gate } 26570Sstevel@tonic-gate 26580Sstevel@tonic-gate 26590Sstevel@tonic-gate /* 26600Sstevel@tonic-gate * our getw() routine - use tryenter 26610Sstevel@tonic-gate */ 26620Sstevel@tonic-gate static uint16_t 26630Sstevel@tonic-gate bofi_rd16(ddi_acc_impl_t *handle, uint16_t *addr) 26640Sstevel@tonic-gate { 26650Sstevel@tonic-gate struct bofi_shadow *hp; 26660Sstevel@tonic-gate uint16_t retval; 26670Sstevel@tonic-gate 26680Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 26690Sstevel@tonic-gate BOFI_READ_CHECKS(uint16_t) 26700Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 26710Sstevel@tonic-gate return (hp->save.acc.ahi_get16(&hp->save.acc, addr)); 26720Sstevel@tonic-gate retval = (uint16_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd16, 1, 26730Sstevel@tonic-gate 2); 26740Sstevel@tonic-gate mutex_exit(&bofi_mutex); 26750Sstevel@tonic-gate return (retval); 26760Sstevel@tonic-gate } 26770Sstevel@tonic-gate 26780Sstevel@tonic-gate 26790Sstevel@tonic-gate static uint64_t 26800Sstevel@tonic-gate do_bofi_rd32(struct bofi_shadow *hp, caddr_t addr) 26810Sstevel@tonic-gate { 26820Sstevel@tonic-gate return (hp->save.acc.ahi_get32(&hp->save.acc, (uint32_t *)addr)); 26830Sstevel@tonic-gate } 26840Sstevel@tonic-gate 26850Sstevel@tonic-gate 26860Sstevel@tonic-gate /* 26870Sstevel@tonic-gate * our getl() routine - use tryenter 26880Sstevel@tonic-gate */ 26890Sstevel@tonic-gate static uint32_t 26900Sstevel@tonic-gate bofi_rd32(ddi_acc_impl_t *handle, uint32_t *addr) 26910Sstevel@tonic-gate { 26920Sstevel@tonic-gate struct bofi_shadow *hp; 26930Sstevel@tonic-gate uint32_t retval; 26940Sstevel@tonic-gate 26950Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 26960Sstevel@tonic-gate BOFI_READ_CHECKS(uint32_t) 26970Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 26980Sstevel@tonic-gate return (hp->save.acc.ahi_get32(&hp->save.acc, addr)); 26990Sstevel@tonic-gate retval = (uint32_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd32, 1, 27000Sstevel@tonic-gate 4); 27010Sstevel@tonic-gate mutex_exit(&bofi_mutex); 27020Sstevel@tonic-gate return (retval); 27030Sstevel@tonic-gate } 27040Sstevel@tonic-gate 27050Sstevel@tonic-gate 27060Sstevel@tonic-gate static uint64_t 27070Sstevel@tonic-gate do_bofi_rd64(struct bofi_shadow *hp, caddr_t addr) 27080Sstevel@tonic-gate { 27090Sstevel@tonic-gate return (hp->save.acc.ahi_get64(&hp->save.acc, (uint64_t *)addr)); 27100Sstevel@tonic-gate } 27110Sstevel@tonic-gate 27120Sstevel@tonic-gate 27130Sstevel@tonic-gate /* 27140Sstevel@tonic-gate * our getll() routine - use tryenter 27150Sstevel@tonic-gate */ 27160Sstevel@tonic-gate static uint64_t 27170Sstevel@tonic-gate bofi_rd64(ddi_acc_impl_t *handle, uint64_t *addr) 27180Sstevel@tonic-gate { 27190Sstevel@tonic-gate struct bofi_shadow *hp; 27200Sstevel@tonic-gate uint64_t retval; 27210Sstevel@tonic-gate 27220Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 27230Sstevel@tonic-gate BOFI_READ_CHECKS(uint64_t) 27240Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 27250Sstevel@tonic-gate return (hp->save.acc.ahi_get64(&hp->save.acc, addr)); 27260Sstevel@tonic-gate retval = (uint64_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd64, 1, 27270Sstevel@tonic-gate 8); 27280Sstevel@tonic-gate mutex_exit(&bofi_mutex); 27290Sstevel@tonic-gate return (retval); 27300Sstevel@tonic-gate } 27310Sstevel@tonic-gate 27320Sstevel@tonic-gate #define BOFI_WRITE_TESTS(type) \ 27330Sstevel@tonic-gate if (bofi_ddi_check) \ 27340Sstevel@tonic-gate addr = (type *)((uintptr_t)addr - 64 + hp->addr); \ 27350Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)addr < hp->addr || \ 27360Sstevel@tonic-gate (caddr_t)addr - hp->addr >= hp->len)) { \ 27370Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 27380Sstevel@tonic-gate "ddi_put() out of range addr %p not in %p/%llx\n", \ 27390Sstevel@tonic-gate (void *)addr, (void *)hp->addr, hp->len); \ 27400Sstevel@tonic-gate return; \ 27410Sstevel@tonic-gate } 27420Sstevel@tonic-gate 27430Sstevel@tonic-gate /* 27440Sstevel@tonic-gate * our putb() routine - use tryenter 27450Sstevel@tonic-gate */ 27460Sstevel@tonic-gate static void 27470Sstevel@tonic-gate bofi_wr8(ddi_acc_impl_t *handle, uint8_t *addr, uint8_t value) 27480Sstevel@tonic-gate { 27490Sstevel@tonic-gate struct bofi_shadow *hp; 27500Sstevel@tonic-gate uint64_t llvalue = value; 27510Sstevel@tonic-gate 27520Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 27530Sstevel@tonic-gate BOFI_WRITE_TESTS(uint8_t) 27540Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 27550Sstevel@tonic-gate hp->save.acc.ahi_put8(&hp->save.acc, addr, (uint8_t)llvalue); 27560Sstevel@tonic-gate return; 27570Sstevel@tonic-gate } 27580Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 1, 1)) 27590Sstevel@tonic-gate hp->save.acc.ahi_put8(&hp->save.acc, addr, (uint8_t)llvalue); 27600Sstevel@tonic-gate mutex_exit(&bofi_mutex); 27610Sstevel@tonic-gate } 27620Sstevel@tonic-gate 27630Sstevel@tonic-gate 27640Sstevel@tonic-gate /* 27650Sstevel@tonic-gate * our putw() routine - use tryenter 27660Sstevel@tonic-gate */ 27670Sstevel@tonic-gate static void 27680Sstevel@tonic-gate bofi_wr16(ddi_acc_impl_t *handle, uint16_t *addr, uint16_t value) 27690Sstevel@tonic-gate { 27700Sstevel@tonic-gate struct bofi_shadow *hp; 27710Sstevel@tonic-gate uint64_t llvalue = value; 27720Sstevel@tonic-gate 27730Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 27740Sstevel@tonic-gate BOFI_WRITE_TESTS(uint16_t) 27750Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 27760Sstevel@tonic-gate hp->save.acc.ahi_put16(&hp->save.acc, addr, (uint16_t)llvalue); 27770Sstevel@tonic-gate return; 27780Sstevel@tonic-gate } 27790Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 2, 1)) 27800Sstevel@tonic-gate hp->save.acc.ahi_put16(&hp->save.acc, addr, (uint16_t)llvalue); 27810Sstevel@tonic-gate mutex_exit(&bofi_mutex); 27820Sstevel@tonic-gate } 27830Sstevel@tonic-gate 27840Sstevel@tonic-gate 27850Sstevel@tonic-gate /* 27860Sstevel@tonic-gate * our putl() routine - use tryenter 27870Sstevel@tonic-gate */ 27880Sstevel@tonic-gate static void 27890Sstevel@tonic-gate bofi_wr32(ddi_acc_impl_t *handle, uint32_t *addr, uint32_t value) 27900Sstevel@tonic-gate { 27910Sstevel@tonic-gate struct bofi_shadow *hp; 27920Sstevel@tonic-gate uint64_t llvalue = value; 27930Sstevel@tonic-gate 27940Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 27950Sstevel@tonic-gate BOFI_WRITE_TESTS(uint32_t) 27960Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 27970Sstevel@tonic-gate hp->save.acc.ahi_put32(&hp->save.acc, addr, (uint32_t)llvalue); 27980Sstevel@tonic-gate return; 27990Sstevel@tonic-gate } 28000Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 4, 1)) 28010Sstevel@tonic-gate hp->save.acc.ahi_put32(&hp->save.acc, addr, (uint32_t)llvalue); 28020Sstevel@tonic-gate mutex_exit(&bofi_mutex); 28030Sstevel@tonic-gate } 28040Sstevel@tonic-gate 28050Sstevel@tonic-gate 28060Sstevel@tonic-gate /* 28070Sstevel@tonic-gate * our putll() routine - use tryenter 28080Sstevel@tonic-gate */ 28090Sstevel@tonic-gate static void 28100Sstevel@tonic-gate bofi_wr64(ddi_acc_impl_t *handle, uint64_t *addr, uint64_t value) 28110Sstevel@tonic-gate { 28120Sstevel@tonic-gate struct bofi_shadow *hp; 28130Sstevel@tonic-gate uint64_t llvalue = value; 28140Sstevel@tonic-gate 28150Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 28160Sstevel@tonic-gate BOFI_WRITE_TESTS(uint64_t) 28170Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 28180Sstevel@tonic-gate hp->save.acc.ahi_put64(&hp->save.acc, addr, (uint64_t)llvalue); 28190Sstevel@tonic-gate return; 28200Sstevel@tonic-gate } 28210Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 8, 1)) 28220Sstevel@tonic-gate hp->save.acc.ahi_put64(&hp->save.acc, addr, (uint64_t)llvalue); 28230Sstevel@tonic-gate mutex_exit(&bofi_mutex); 28240Sstevel@tonic-gate } 28250Sstevel@tonic-gate 28260Sstevel@tonic-gate #define BOFI_REP_READ_TESTS(type) \ 28270Sstevel@tonic-gate if (bofi_ddi_check) \ 28280Sstevel@tonic-gate dev_addr = (type *)((uintptr_t)dev_addr - 64 + hp->addr); \ 28290Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)dev_addr < hp->addr || \ 28300Sstevel@tonic-gate (caddr_t)(dev_addr + repcount) - hp->addr > hp->len)) { \ 28310Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 28320Sstevel@tonic-gate "ddi_rep_get() out of range addr %p not in %p/%llx\n", \ 28330Sstevel@tonic-gate (void *)dev_addr, (void *)hp->addr, hp->len); \ 28340Sstevel@tonic-gate if ((caddr_t)dev_addr < hp->addr || \ 28350Sstevel@tonic-gate (caddr_t)dev_addr - hp->addr >= hp->len) \ 28360Sstevel@tonic-gate return; \ 28370Sstevel@tonic-gate repcount = (type *)(hp->addr + hp->len) - dev_addr; \ 28380Sstevel@tonic-gate } 28390Sstevel@tonic-gate 28400Sstevel@tonic-gate /* 28410Sstevel@tonic-gate * our rep_getb() routine - use tryenter 28420Sstevel@tonic-gate */ 28430Sstevel@tonic-gate static void 28440Sstevel@tonic-gate bofi_rep_rd8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr, 28450Sstevel@tonic-gate size_t repcount, uint_t flags) 28460Sstevel@tonic-gate { 28470Sstevel@tonic-gate struct bofi_shadow *hp; 28480Sstevel@tonic-gate int i; 28490Sstevel@tonic-gate uint8_t *addr; 28500Sstevel@tonic-gate 28510Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 28520Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint8_t) 28530Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 28540Sstevel@tonic-gate hp->save.acc.ahi_rep_get8(&hp->save.acc, host_addr, dev_addr, 28550Sstevel@tonic-gate repcount, flags); 28560Sstevel@tonic-gate return; 28570Sstevel@tonic-gate } 28580Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 28590Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 28600Sstevel@tonic-gate *(host_addr + i) = (uint8_t)do_pior_corrupt(hp, (caddr_t)addr, 28610Sstevel@tonic-gate do_bofi_rd8, i ? 0 : repcount, 1); 28620Sstevel@tonic-gate } 28630Sstevel@tonic-gate mutex_exit(&bofi_mutex); 28640Sstevel@tonic-gate } 28650Sstevel@tonic-gate 28660Sstevel@tonic-gate 28670Sstevel@tonic-gate /* 28680Sstevel@tonic-gate * our rep_getw() routine - use tryenter 28690Sstevel@tonic-gate */ 28700Sstevel@tonic-gate static void 28710Sstevel@tonic-gate bofi_rep_rd16(ddi_acc_impl_t *handle, uint16_t *host_addr, 28720Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 28730Sstevel@tonic-gate { 28740Sstevel@tonic-gate struct bofi_shadow *hp; 28750Sstevel@tonic-gate int i; 28760Sstevel@tonic-gate uint16_t *addr; 28770Sstevel@tonic-gate 28780Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 28790Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint16_t) 28800Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 28810Sstevel@tonic-gate hp->save.acc.ahi_rep_get16(&hp->save.acc, host_addr, dev_addr, 28820Sstevel@tonic-gate repcount, flags); 28830Sstevel@tonic-gate return; 28840Sstevel@tonic-gate } 28850Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 28860Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 28870Sstevel@tonic-gate *(host_addr + i) = (uint16_t)do_pior_corrupt(hp, (caddr_t)addr, 28880Sstevel@tonic-gate do_bofi_rd16, i ? 0 : repcount, 2); 28890Sstevel@tonic-gate } 28900Sstevel@tonic-gate mutex_exit(&bofi_mutex); 28910Sstevel@tonic-gate } 28920Sstevel@tonic-gate 28930Sstevel@tonic-gate 28940Sstevel@tonic-gate /* 28950Sstevel@tonic-gate * our rep_getl() routine - use tryenter 28960Sstevel@tonic-gate */ 28970Sstevel@tonic-gate static void 28980Sstevel@tonic-gate bofi_rep_rd32(ddi_acc_impl_t *handle, uint32_t *host_addr, 28990Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 29000Sstevel@tonic-gate { 29010Sstevel@tonic-gate struct bofi_shadow *hp; 29020Sstevel@tonic-gate int i; 29030Sstevel@tonic-gate uint32_t *addr; 29040Sstevel@tonic-gate 29050Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 29060Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint32_t) 29070Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 29080Sstevel@tonic-gate hp->save.acc.ahi_rep_get32(&hp->save.acc, host_addr, dev_addr, 29090Sstevel@tonic-gate repcount, flags); 29100Sstevel@tonic-gate return; 29110Sstevel@tonic-gate } 29120Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 29130Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 29140Sstevel@tonic-gate *(host_addr + i) = (uint32_t)do_pior_corrupt(hp, (caddr_t)addr, 29150Sstevel@tonic-gate do_bofi_rd32, i ? 0 : repcount, 4); 29160Sstevel@tonic-gate } 29170Sstevel@tonic-gate mutex_exit(&bofi_mutex); 29180Sstevel@tonic-gate } 29190Sstevel@tonic-gate 29200Sstevel@tonic-gate 29210Sstevel@tonic-gate /* 29220Sstevel@tonic-gate * our rep_getll() routine - use tryenter 29230Sstevel@tonic-gate */ 29240Sstevel@tonic-gate static void 29250Sstevel@tonic-gate bofi_rep_rd64(ddi_acc_impl_t *handle, uint64_t *host_addr, 29260Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 29270Sstevel@tonic-gate { 29280Sstevel@tonic-gate struct bofi_shadow *hp; 29290Sstevel@tonic-gate int i; 29300Sstevel@tonic-gate uint64_t *addr; 29310Sstevel@tonic-gate 29320Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 29330Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint64_t) 29340Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 29350Sstevel@tonic-gate hp->save.acc.ahi_rep_get64(&hp->save.acc, host_addr, dev_addr, 29360Sstevel@tonic-gate repcount, flags); 29370Sstevel@tonic-gate return; 29380Sstevel@tonic-gate } 29390Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 29400Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 29410Sstevel@tonic-gate *(host_addr + i) = (uint64_t)do_pior_corrupt(hp, (caddr_t)addr, 29420Sstevel@tonic-gate do_bofi_rd64, i ? 0 : repcount, 8); 29430Sstevel@tonic-gate } 29440Sstevel@tonic-gate mutex_exit(&bofi_mutex); 29450Sstevel@tonic-gate } 29460Sstevel@tonic-gate 29470Sstevel@tonic-gate #define BOFI_REP_WRITE_TESTS(type) \ 29480Sstevel@tonic-gate if (bofi_ddi_check) \ 29490Sstevel@tonic-gate dev_addr = (type *)((uintptr_t)dev_addr - 64 + hp->addr); \ 29500Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)dev_addr < hp->addr || \ 29510Sstevel@tonic-gate (caddr_t)(dev_addr + repcount) - hp->addr > hp->len)) { \ 29520Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 29530Sstevel@tonic-gate "ddi_rep_put() out of range addr %p not in %p/%llx\n", \ 29540Sstevel@tonic-gate (void *)dev_addr, (void *)hp->addr, hp->len); \ 29550Sstevel@tonic-gate if ((caddr_t)dev_addr < hp->addr || \ 29560Sstevel@tonic-gate (caddr_t)dev_addr - hp->addr >= hp->len) \ 29570Sstevel@tonic-gate return; \ 29580Sstevel@tonic-gate repcount = (type *)(hp->addr + hp->len) - dev_addr; \ 29590Sstevel@tonic-gate } 29600Sstevel@tonic-gate 29610Sstevel@tonic-gate /* 29620Sstevel@tonic-gate * our rep_putb() routine - use tryenter 29630Sstevel@tonic-gate */ 29640Sstevel@tonic-gate static void 29650Sstevel@tonic-gate bofi_rep_wr8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr, 29660Sstevel@tonic-gate size_t repcount, uint_t flags) 29670Sstevel@tonic-gate { 29680Sstevel@tonic-gate struct bofi_shadow *hp; 29690Sstevel@tonic-gate int i; 29700Sstevel@tonic-gate uint64_t llvalue; 29710Sstevel@tonic-gate uint8_t *addr; 29720Sstevel@tonic-gate 29730Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 29740Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint8_t) 29750Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 29760Sstevel@tonic-gate hp->save.acc.ahi_rep_put8(&hp->save.acc, host_addr, dev_addr, 29770Sstevel@tonic-gate repcount, flags); 29780Sstevel@tonic-gate return; 29790Sstevel@tonic-gate } 29800Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 29810Sstevel@tonic-gate llvalue = *(host_addr + i); 29820Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 29830Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 1, i ? 0 : 29840Sstevel@tonic-gate repcount)) 29850Sstevel@tonic-gate hp->save.acc.ahi_put8(&hp->save.acc, addr, 29860Sstevel@tonic-gate (uint8_t)llvalue); 29870Sstevel@tonic-gate } 29880Sstevel@tonic-gate mutex_exit(&bofi_mutex); 29890Sstevel@tonic-gate } 29900Sstevel@tonic-gate 29910Sstevel@tonic-gate 29920Sstevel@tonic-gate /* 29930Sstevel@tonic-gate * our rep_putw() routine - use tryenter 29940Sstevel@tonic-gate */ 29950Sstevel@tonic-gate static void 29960Sstevel@tonic-gate bofi_rep_wr16(ddi_acc_impl_t *handle, uint16_t *host_addr, 29970Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 29980Sstevel@tonic-gate { 29990Sstevel@tonic-gate struct bofi_shadow *hp; 30000Sstevel@tonic-gate int i; 30010Sstevel@tonic-gate uint64_t llvalue; 30020Sstevel@tonic-gate uint16_t *addr; 30030Sstevel@tonic-gate 30040Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 30050Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint16_t) 30060Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 30070Sstevel@tonic-gate hp->save.acc.ahi_rep_put16(&hp->save.acc, host_addr, dev_addr, 30080Sstevel@tonic-gate repcount, flags); 30090Sstevel@tonic-gate return; 30100Sstevel@tonic-gate } 30110Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 30120Sstevel@tonic-gate llvalue = *(host_addr + i); 30130Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 30140Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 2, i ? 0 : 30150Sstevel@tonic-gate repcount)) 30160Sstevel@tonic-gate hp->save.acc.ahi_put16(&hp->save.acc, addr, 30170Sstevel@tonic-gate (uint16_t)llvalue); 30180Sstevel@tonic-gate } 30190Sstevel@tonic-gate mutex_exit(&bofi_mutex); 30200Sstevel@tonic-gate } 30210Sstevel@tonic-gate 30220Sstevel@tonic-gate 30230Sstevel@tonic-gate /* 30240Sstevel@tonic-gate * our rep_putl() routine - use tryenter 30250Sstevel@tonic-gate */ 30260Sstevel@tonic-gate static void 30270Sstevel@tonic-gate bofi_rep_wr32(ddi_acc_impl_t *handle, uint32_t *host_addr, 30280Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 30290Sstevel@tonic-gate { 30300Sstevel@tonic-gate struct bofi_shadow *hp; 30310Sstevel@tonic-gate int i; 30320Sstevel@tonic-gate uint64_t llvalue; 30330Sstevel@tonic-gate uint32_t *addr; 30340Sstevel@tonic-gate 30350Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 30360Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint32_t) 30370Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 30380Sstevel@tonic-gate hp->save.acc.ahi_rep_put32(&hp->save.acc, host_addr, dev_addr, 30390Sstevel@tonic-gate repcount, flags); 30400Sstevel@tonic-gate return; 30410Sstevel@tonic-gate } 30420Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 30430Sstevel@tonic-gate llvalue = *(host_addr + i); 30440Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 30450Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 4, i ? 0 : 30460Sstevel@tonic-gate repcount)) 30470Sstevel@tonic-gate hp->save.acc.ahi_put32(&hp->save.acc, addr, 30480Sstevel@tonic-gate (uint32_t)llvalue); 30490Sstevel@tonic-gate } 30500Sstevel@tonic-gate mutex_exit(&bofi_mutex); 30510Sstevel@tonic-gate } 30520Sstevel@tonic-gate 30530Sstevel@tonic-gate 30540Sstevel@tonic-gate /* 30550Sstevel@tonic-gate * our rep_putll() routine - use tryenter 30560Sstevel@tonic-gate */ 30570Sstevel@tonic-gate static void 30580Sstevel@tonic-gate bofi_rep_wr64(ddi_acc_impl_t *handle, uint64_t *host_addr, 30590Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 30600Sstevel@tonic-gate { 30610Sstevel@tonic-gate struct bofi_shadow *hp; 30620Sstevel@tonic-gate int i; 30630Sstevel@tonic-gate uint64_t llvalue; 30640Sstevel@tonic-gate uint64_t *addr; 30650Sstevel@tonic-gate 30660Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 30670Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint64_t) 30680Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 30690Sstevel@tonic-gate hp->save.acc.ahi_rep_put64(&hp->save.acc, host_addr, dev_addr, 30700Sstevel@tonic-gate repcount, flags); 30710Sstevel@tonic-gate return; 30720Sstevel@tonic-gate } 30730Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 30740Sstevel@tonic-gate llvalue = *(host_addr + i); 30750Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 30760Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 8, i ? 0 : 30770Sstevel@tonic-gate repcount)) 30780Sstevel@tonic-gate hp->save.acc.ahi_put64(&hp->save.acc, addr, 30790Sstevel@tonic-gate (uint64_t)llvalue); 30800Sstevel@tonic-gate } 30810Sstevel@tonic-gate mutex_exit(&bofi_mutex); 30820Sstevel@tonic-gate } 30830Sstevel@tonic-gate 30840Sstevel@tonic-gate 30850Sstevel@tonic-gate /* 30860Sstevel@tonic-gate * our ddi_map routine 30870Sstevel@tonic-gate */ 30880Sstevel@tonic-gate static int 30890Sstevel@tonic-gate bofi_map(dev_info_t *dip, dev_info_t *rdip, 30900Sstevel@tonic-gate ddi_map_req_t *reqp, off_t offset, off_t len, caddr_t *vaddrp) 30910Sstevel@tonic-gate { 30920Sstevel@tonic-gate ddi_acc_impl_t *ap; 30930Sstevel@tonic-gate struct bofi_shadow *hp; 30940Sstevel@tonic-gate struct bofi_errent *ep; 30950Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 30960Sstevel@tonic-gate int retval; 30970Sstevel@tonic-gate struct bofi_shadow *dhashp; 30980Sstevel@tonic-gate struct bofi_shadow *hhashp; 30990Sstevel@tonic-gate 31000Sstevel@tonic-gate switch (reqp->map_op) { 31010Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: 31020Sstevel@tonic-gate /* 31030Sstevel@tonic-gate * for this case get nexus to do real work first 31040Sstevel@tonic-gate */ 31050Sstevel@tonic-gate retval = save_bus_ops.bus_map(dip, rdip, reqp, offset, len, 31060Sstevel@tonic-gate vaddrp); 31070Sstevel@tonic-gate if (retval != DDI_SUCCESS) 31080Sstevel@tonic-gate return (retval); 31090Sstevel@tonic-gate 31100Sstevel@tonic-gate ap = (ddi_acc_impl_t *)reqp->map_handlep; 31110Sstevel@tonic-gate if (ap == NULL) 31120Sstevel@tonic-gate return (DDI_SUCCESS); 31130Sstevel@tonic-gate /* 31140Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 31150Sstevel@tonic-gate */ 31160Sstevel@tonic-gate if (!driver_under_test(ap->ahi_common.ah_dip)) 31170Sstevel@tonic-gate return (DDI_SUCCESS); 31180Sstevel@tonic-gate 31190Sstevel@tonic-gate /* 31200Sstevel@tonic-gate * support for ddi_regs_map_setup() 31210Sstevel@tonic-gate * - allocate shadow handle structure and fill it in 31220Sstevel@tonic-gate */ 31230Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), KM_SLEEP); 31240Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(ap->ahi_common.ah_dip), 31250Sstevel@tonic-gate NAMESIZE); 31260Sstevel@tonic-gate hp->instance = ddi_get_instance(ap->ahi_common.ah_dip); 31270Sstevel@tonic-gate hp->dip = ap->ahi_common.ah_dip; 31280Sstevel@tonic-gate hp->addr = *vaddrp; 31290Sstevel@tonic-gate /* 31300Sstevel@tonic-gate * return spurious value to catch direct access to registers 31310Sstevel@tonic-gate */ 31320Sstevel@tonic-gate if (bofi_ddi_check) 31330Sstevel@tonic-gate *vaddrp = (caddr_t)64; 31340Sstevel@tonic-gate hp->rnumber = ((ddi_acc_hdl_t *)ap)->ah_rnumber; 31350Sstevel@tonic-gate hp->offset = offset; 31360Sstevel@tonic-gate if (len == 0) 31370Sstevel@tonic-gate hp->len = INT_MAX - offset; 31380Sstevel@tonic-gate else 31390Sstevel@tonic-gate hp->len = min(len, INT_MAX - offset); 31400Sstevel@tonic-gate hp->hdl.acc_handle = (ddi_acc_handle_t)ap; 31410Sstevel@tonic-gate hp->link = NULL; 31420Sstevel@tonic-gate hp->type = BOFI_ACC_HDL; 31430Sstevel@tonic-gate /* 31440Sstevel@tonic-gate * save existing function pointers and plug in our own 31450Sstevel@tonic-gate */ 31460Sstevel@tonic-gate hp->save.acc = *ap; 31470Sstevel@tonic-gate ap->ahi_get8 = bofi_rd8; 31480Sstevel@tonic-gate ap->ahi_get16 = bofi_rd16; 31490Sstevel@tonic-gate ap->ahi_get32 = bofi_rd32; 31500Sstevel@tonic-gate ap->ahi_get64 = bofi_rd64; 31510Sstevel@tonic-gate ap->ahi_put8 = bofi_wr8; 31520Sstevel@tonic-gate ap->ahi_put16 = bofi_wr16; 31530Sstevel@tonic-gate ap->ahi_put32 = bofi_wr32; 31540Sstevel@tonic-gate ap->ahi_put64 = bofi_wr64; 31550Sstevel@tonic-gate ap->ahi_rep_get8 = bofi_rep_rd8; 31560Sstevel@tonic-gate ap->ahi_rep_get16 = bofi_rep_rd16; 31570Sstevel@tonic-gate ap->ahi_rep_get32 = bofi_rep_rd32; 31580Sstevel@tonic-gate ap->ahi_rep_get64 = bofi_rep_rd64; 31590Sstevel@tonic-gate ap->ahi_rep_put8 = bofi_rep_wr8; 31600Sstevel@tonic-gate ap->ahi_rep_put16 = bofi_rep_wr16; 31610Sstevel@tonic-gate ap->ahi_rep_put32 = bofi_rep_wr32; 31620Sstevel@tonic-gate ap->ahi_rep_put64 = bofi_rep_wr64; 31630Sstevel@tonic-gate ap->ahi_fault_check = bofi_check_acc_hdl; 31640Sstevel@tonic-gate #if defined(__sparc) 31650Sstevel@tonic-gate #else 31660Sstevel@tonic-gate ap->ahi_acc_attr &= ~DDI_ACCATTR_DIRECT; 31670Sstevel@tonic-gate #endif 31680Sstevel@tonic-gate /* 31690Sstevel@tonic-gate * stick in a pointer to our shadow handle 31700Sstevel@tonic-gate */ 31710Sstevel@tonic-gate ap->ahi_common.ah_bus_private = hp; 31720Sstevel@tonic-gate /* 31730Sstevel@tonic-gate * add to dhash, hhash and inuse lists 31740Sstevel@tonic-gate */ 31750Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 31760Sstevel@tonic-gate mutex_enter(&bofi_mutex); 31770Sstevel@tonic-gate hp->next = shadow_list.next; 31780Sstevel@tonic-gate shadow_list.next->prev = hp; 31790Sstevel@tonic-gate hp->prev = &shadow_list; 31800Sstevel@tonic-gate shadow_list.next = hp; 31810Sstevel@tonic-gate hhashp = HDL_HHASH(ap); 31820Sstevel@tonic-gate hp->hnext = hhashp->hnext; 31830Sstevel@tonic-gate hhashp->hnext->hprev = hp; 31840Sstevel@tonic-gate hp->hprev = hhashp; 31850Sstevel@tonic-gate hhashp->hnext = hp; 31860Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 31870Sstevel@tonic-gate hp->dnext = dhashp->dnext; 31880Sstevel@tonic-gate dhashp->dnext->dprev = hp; 31890Sstevel@tonic-gate hp->dprev = dhashp; 31900Sstevel@tonic-gate dhashp->dnext = hp; 31910Sstevel@tonic-gate /* 31920Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 31930Sstevel@tonic-gate * acc_handle 31940Sstevel@tonic-gate */ 31950Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 31960Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 31970Sstevel@tonic-gate ddi_name_to_major(ep->name) && 31980Sstevel@tonic-gate hp->instance == ep->errdef.instance && 31990Sstevel@tonic-gate (ep->errdef.access_type & BOFI_PIO_RW) && 32000Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 32010Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 32020Sstevel@tonic-gate (ep->errdef.len == 0 || 32030Sstevel@tonic-gate offset < ep->errdef.offset + ep->errdef.len) && 32040Sstevel@tonic-gate offset + hp->len > ep->errdef.offset) { 32050Sstevel@tonic-gate lp = bofi_link_freelist; 32060Sstevel@tonic-gate if (lp != NULL) { 32070Sstevel@tonic-gate bofi_link_freelist = lp->link; 32080Sstevel@tonic-gate lp->errentp = ep; 32090Sstevel@tonic-gate lp->link = hp->link; 32100Sstevel@tonic-gate hp->link = lp; 32110Sstevel@tonic-gate } 32120Sstevel@tonic-gate } 32130Sstevel@tonic-gate } 32140Sstevel@tonic-gate mutex_exit(&bofi_mutex); 32150Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 32160Sstevel@tonic-gate return (DDI_SUCCESS); 32170Sstevel@tonic-gate case DDI_MO_UNMAP: 32180Sstevel@tonic-gate 32190Sstevel@tonic-gate ap = (ddi_acc_impl_t *)reqp->map_handlep; 32200Sstevel@tonic-gate if (ap == NULL) 32210Sstevel@tonic-gate break; 32220Sstevel@tonic-gate /* 32230Sstevel@tonic-gate * support for ddi_regs_map_free() 32240Sstevel@tonic-gate * - check we really have a shadow handle for this one 32250Sstevel@tonic-gate */ 32260Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 32270Sstevel@tonic-gate mutex_enter(&bofi_mutex); 32280Sstevel@tonic-gate hhashp = HDL_HHASH(ap); 32290Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 32300Sstevel@tonic-gate if (hp->hdl.acc_handle == (ddi_acc_handle_t)ap) 32310Sstevel@tonic-gate break; 32320Sstevel@tonic-gate if (hp == hhashp) { 32330Sstevel@tonic-gate mutex_exit(&bofi_mutex); 32340Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 32350Sstevel@tonic-gate break; 32360Sstevel@tonic-gate } 32370Sstevel@tonic-gate /* 32380Sstevel@tonic-gate * got a shadow handle - restore original pointers 32390Sstevel@tonic-gate */ 32400Sstevel@tonic-gate *ap = hp->save.acc; 32410Sstevel@tonic-gate *vaddrp = hp->addr; 32420Sstevel@tonic-gate /* 32430Sstevel@tonic-gate * remove from dhash, hhash and inuse lists 32440Sstevel@tonic-gate */ 32450Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 32460Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 32470Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 32480Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 32490Sstevel@tonic-gate hp->next->prev = hp->prev; 32500Sstevel@tonic-gate hp->prev->next = hp->next; 32510Sstevel@tonic-gate /* 32520Sstevel@tonic-gate * free any errdef link structures tagged onto the shadow handle 32530Sstevel@tonic-gate */ 32540Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 32550Sstevel@tonic-gate next_lp = lp->link; 32560Sstevel@tonic-gate lp->link = bofi_link_freelist; 32570Sstevel@tonic-gate bofi_link_freelist = lp; 32580Sstevel@tonic-gate lp = next_lp; 32590Sstevel@tonic-gate } 32600Sstevel@tonic-gate hp->link = NULL; 32610Sstevel@tonic-gate mutex_exit(&bofi_mutex); 32620Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 32630Sstevel@tonic-gate /* 32640Sstevel@tonic-gate * finally delete shadow handle 32650Sstevel@tonic-gate */ 32660Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 32670Sstevel@tonic-gate break; 32680Sstevel@tonic-gate default: 32690Sstevel@tonic-gate break; 32700Sstevel@tonic-gate } 32710Sstevel@tonic-gate return (save_bus_ops.bus_map(dip, rdip, reqp, offset, len, vaddrp)); 32720Sstevel@tonic-gate } 32730Sstevel@tonic-gate 32740Sstevel@tonic-gate 32750Sstevel@tonic-gate /* 32760Sstevel@tonic-gate * chain any pre-existing errdefs on to newly created dma handle 32770Sstevel@tonic-gate * if required call do_dma_corrupt() to corrupt data 32780Sstevel@tonic-gate */ 32790Sstevel@tonic-gate static void 32800Sstevel@tonic-gate chain_on_errdefs(struct bofi_shadow *hp) 32810Sstevel@tonic-gate { 32820Sstevel@tonic-gate struct bofi_errent *ep; 32830Sstevel@tonic-gate struct bofi_link *lp; 32840Sstevel@tonic-gate 32850Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 32860Sstevel@tonic-gate /* 32870Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this dma_handle 32880Sstevel@tonic-gate */ 32890Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 32900Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 32910Sstevel@tonic-gate ddi_name_to_major(ep->name) && 32920Sstevel@tonic-gate hp->instance == ep->errdef.instance && 32930Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 32940Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 32950Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_RW) && 32960Sstevel@tonic-gate (((uintptr_t)(hp->addr + ep->errdef.offset + 32970Sstevel@tonic-gate ep->errdef.len) & ~LLSZMASK) > 32980Sstevel@tonic-gate ((uintptr_t)((hp->addr + ep->errdef.offset) + 32990Sstevel@tonic-gate LLSZMASK) & ~LLSZMASK)))) { 33000Sstevel@tonic-gate /* 33010Sstevel@tonic-gate * got a match - link it on 33020Sstevel@tonic-gate */ 33030Sstevel@tonic-gate lp = bofi_link_freelist; 33040Sstevel@tonic-gate if (lp != NULL) { 33050Sstevel@tonic-gate bofi_link_freelist = lp->link; 33060Sstevel@tonic-gate lp->errentp = ep; 33070Sstevel@tonic-gate lp->link = hp->link; 33080Sstevel@tonic-gate hp->link = lp; 33090Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_W) && 33100Sstevel@tonic-gate (hp->flags & DDI_DMA_WRITE) && 33110Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 33120Sstevel@tonic-gate do_dma_corrupt(hp, ep, 33130Sstevel@tonic-gate DDI_DMA_SYNC_FORDEV, 33140Sstevel@tonic-gate 0, hp->len); 33150Sstevel@tonic-gate } 33160Sstevel@tonic-gate } 33170Sstevel@tonic-gate } 33180Sstevel@tonic-gate } 33190Sstevel@tonic-gate } 33200Sstevel@tonic-gate 33210Sstevel@tonic-gate 33220Sstevel@tonic-gate /* 33230Sstevel@tonic-gate * need to do copy byte-by-byte in case one of pages is little-endian 33240Sstevel@tonic-gate */ 33250Sstevel@tonic-gate static void 33260Sstevel@tonic-gate xbcopy(void *from, void *to, u_longlong_t len) 33270Sstevel@tonic-gate { 33280Sstevel@tonic-gate uchar_t *f = from; 33290Sstevel@tonic-gate uchar_t *t = to; 33300Sstevel@tonic-gate 33310Sstevel@tonic-gate while (len--) 33320Sstevel@tonic-gate *t++ = *f++; 33330Sstevel@tonic-gate } 33340Sstevel@tonic-gate 33350Sstevel@tonic-gate 33360Sstevel@tonic-gate /* 33370Sstevel@tonic-gate * our ddi_dma_map routine 33380Sstevel@tonic-gate */ 33390Sstevel@tonic-gate static int 33400Sstevel@tonic-gate bofi_dma_map(dev_info_t *dip, dev_info_t *rdip, 33410Sstevel@tonic-gate struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep) 33420Sstevel@tonic-gate { 33430Sstevel@tonic-gate struct bofi_shadow *hp, *xhp; 33440Sstevel@tonic-gate int maxrnumber = 0; 33450Sstevel@tonic-gate int retval = DDI_DMA_NORESOURCES; 33460Sstevel@tonic-gate auto struct ddi_dma_req dmareq; 33470Sstevel@tonic-gate int sleep; 33480Sstevel@tonic-gate struct bofi_shadow *dhashp; 33490Sstevel@tonic-gate struct bofi_shadow *hhashp; 33500Sstevel@tonic-gate ddi_dma_impl_t *mp; 33510Sstevel@tonic-gate unsigned long pagemask = ddi_ptob(rdip, 1) - 1; 33520Sstevel@tonic-gate 33530Sstevel@tonic-gate /* 33540Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 33550Sstevel@tonic-gate */ 33560Sstevel@tonic-gate if (handlep == NULL || !driver_under_test(rdip)) 33570Sstevel@tonic-gate return (save_bus_ops.bus_dma_map(dip, rdip, dmareqp, handlep)); 33580Sstevel@tonic-gate 33590Sstevel@tonic-gate sleep = (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 33600Sstevel@tonic-gate /* 33610Sstevel@tonic-gate * allocate shadow handle structure and fill it in 33620Sstevel@tonic-gate */ 33630Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), sleep); 33640Sstevel@tonic-gate if (hp == NULL) 33650Sstevel@tonic-gate goto error; 33660Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 33670Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 33680Sstevel@tonic-gate hp->dip = rdip; 33690Sstevel@tonic-gate hp->flags = dmareqp->dmar_flags; 33703971Sstephh if (dmareqp->dmar_object.dmao_type == DMA_OTYP_PAGES) { 33713971Sstephh hp->map_flags = B_PAGEIO; 33723971Sstephh hp->map_pp = dmareqp->dmar_object.dmao_obj.pp_obj.pp_pp; 33733971Sstephh } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_priv != NULL) { 33743971Sstephh hp->map_flags = B_SHADOW; 33753971Sstephh hp->map_pplist = dmareqp->dmar_object.dmao_obj.virt_obj.v_priv; 33763971Sstephh } else { 33773971Sstephh hp->map_flags = 0; 33783971Sstephh } 33790Sstevel@tonic-gate hp->link = NULL; 33800Sstevel@tonic-gate hp->type = BOFI_DMA_HDL; 33810Sstevel@tonic-gate /* 33820Sstevel@tonic-gate * get a kernel virtual mapping 33830Sstevel@tonic-gate */ 33840Sstevel@tonic-gate hp->addr = ddi_dmareq_mapin(dmareqp, &hp->mapaddr, &hp->len); 33850Sstevel@tonic-gate if (hp->addr == NULL) 33860Sstevel@tonic-gate goto error; 33870Sstevel@tonic-gate if (bofi_sync_check) { 33880Sstevel@tonic-gate /* 33890Sstevel@tonic-gate * Take a copy and pass pointers to this up to nexus instead. 33900Sstevel@tonic-gate * Data will be copied from the original on explicit 33910Sstevel@tonic-gate * and implicit ddi_dma_sync() 33920Sstevel@tonic-gate * 33930Sstevel@tonic-gate * - maintain page alignment because some devices assume it. 33940Sstevel@tonic-gate */ 33950Sstevel@tonic-gate hp->origaddr = hp->addr; 33960Sstevel@tonic-gate hp->allocaddr = ddi_umem_alloc( 33970Sstevel@tonic-gate ((uintptr_t)hp->addr & pagemask) + hp->len, sleep, 33980Sstevel@tonic-gate &hp->umem_cookie); 33990Sstevel@tonic-gate if (hp->allocaddr == NULL) 34000Sstevel@tonic-gate goto error; 34010Sstevel@tonic-gate hp->addr = hp->allocaddr + ((uintptr_t)hp->addr & pagemask); 34020Sstevel@tonic-gate if (dmareqp->dmar_flags & DDI_DMA_WRITE) 34030Sstevel@tonic-gate xbcopy(hp->origaddr, hp->addr, hp->len); 34040Sstevel@tonic-gate dmareq = *dmareqp; 34050Sstevel@tonic-gate dmareq.dmar_object.dmao_size = hp->len; 34060Sstevel@tonic-gate dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR; 34070Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_as = &kas; 34080Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_addr = hp->addr; 34090Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL; 34100Sstevel@tonic-gate dmareqp = &dmareq; 34110Sstevel@tonic-gate } 34120Sstevel@tonic-gate /* 34130Sstevel@tonic-gate * call nexus to do the real work 34140Sstevel@tonic-gate */ 34150Sstevel@tonic-gate retval = save_bus_ops.bus_dma_map(dip, rdip, dmareqp, handlep); 34160Sstevel@tonic-gate if (retval != DDI_SUCCESS) 34170Sstevel@tonic-gate goto error2; 34180Sstevel@tonic-gate /* 34190Sstevel@tonic-gate * now set dma_handle to point to real handle 34200Sstevel@tonic-gate */ 34210Sstevel@tonic-gate hp->hdl.dma_handle = *handlep; 34220Sstevel@tonic-gate /* 34230Sstevel@tonic-gate * unset DMP_NOSYNC 34240Sstevel@tonic-gate */ 34250Sstevel@tonic-gate mp = (ddi_dma_impl_t *)*handlep; 34260Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 34270Sstevel@tonic-gate mp->dmai_fault_check = bofi_check_dma_hdl; 34280Sstevel@tonic-gate /* 34290Sstevel@tonic-gate * bind and unbind are cached in devinfo - must overwrite them 34300Sstevel@tonic-gate * - note that our bind and unbind are quite happy dealing with 34310Sstevel@tonic-gate * any handles for this devinfo that were previously allocated 34320Sstevel@tonic-gate */ 34330Sstevel@tonic-gate if (save_bus_ops.bus_dma_bindhdl == DEVI(rdip)->devi_bus_dma_bindfunc) 34340Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_bindfunc = bofi_dma_bindhdl; 34350Sstevel@tonic-gate if (save_bus_ops.bus_dma_unbindhdl == 34360Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc) 34370Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc = bofi_dma_unbindhdl; 34380Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 34390Sstevel@tonic-gate mutex_enter(&bofi_mutex); 34400Sstevel@tonic-gate /* 34410Sstevel@tonic-gate * get an "rnumber" for this handle - really just seeking to 34420Sstevel@tonic-gate * get a unique number - generally only care for early allocated 34430Sstevel@tonic-gate * handles - so we get as far as INT_MAX, just stay there 34440Sstevel@tonic-gate */ 34450Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 34460Sstevel@tonic-gate for (xhp = dhashp->dnext; xhp != dhashp; xhp = xhp->dnext) 34470Sstevel@tonic-gate if (ddi_name_to_major(xhp->name) == 34480Sstevel@tonic-gate ddi_name_to_major(hp->name) && 34490Sstevel@tonic-gate xhp->instance == hp->instance && 34500Sstevel@tonic-gate xhp->type == BOFI_DMA_HDL) 34510Sstevel@tonic-gate if (xhp->rnumber >= maxrnumber) { 34520Sstevel@tonic-gate if (xhp->rnumber == INT_MAX) 34530Sstevel@tonic-gate maxrnumber = INT_MAX; 34540Sstevel@tonic-gate else 34550Sstevel@tonic-gate maxrnumber = xhp->rnumber + 1; 34560Sstevel@tonic-gate } 34570Sstevel@tonic-gate hp->rnumber = maxrnumber; 34580Sstevel@tonic-gate /* 34590Sstevel@tonic-gate * add to dhash, hhash and inuse lists 34600Sstevel@tonic-gate */ 34610Sstevel@tonic-gate hp->next = shadow_list.next; 34620Sstevel@tonic-gate shadow_list.next->prev = hp; 34630Sstevel@tonic-gate hp->prev = &shadow_list; 34640Sstevel@tonic-gate shadow_list.next = hp; 34650Sstevel@tonic-gate hhashp = HDL_HHASH(*handlep); 34660Sstevel@tonic-gate hp->hnext = hhashp->hnext; 34670Sstevel@tonic-gate hhashp->hnext->hprev = hp; 34680Sstevel@tonic-gate hp->hprev = hhashp; 34690Sstevel@tonic-gate hhashp->hnext = hp; 34700Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 34710Sstevel@tonic-gate hp->dnext = dhashp->dnext; 34720Sstevel@tonic-gate dhashp->dnext->dprev = hp; 34730Sstevel@tonic-gate hp->dprev = dhashp; 34740Sstevel@tonic-gate dhashp->dnext = hp; 34750Sstevel@tonic-gate /* 34760Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 34770Sstevel@tonic-gate * acc_handle and corrupt if required (as there is an implicit 34780Sstevel@tonic-gate * ddi_dma_sync() in this call) 34790Sstevel@tonic-gate */ 34800Sstevel@tonic-gate chain_on_errdefs(hp); 34810Sstevel@tonic-gate mutex_exit(&bofi_mutex); 34820Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 34830Sstevel@tonic-gate return (retval); 34840Sstevel@tonic-gate error: 34850Sstevel@tonic-gate if (dmareqp->dmar_fp != DDI_DMA_DONTWAIT) { 34860Sstevel@tonic-gate /* 34870Sstevel@tonic-gate * what to do here? Wait a bit and try again 34880Sstevel@tonic-gate */ 34890Sstevel@tonic-gate (void) timeout((void (*)())dmareqp->dmar_fp, 34900Sstevel@tonic-gate dmareqp->dmar_arg, 10); 34910Sstevel@tonic-gate } 34920Sstevel@tonic-gate error2: 34930Sstevel@tonic-gate if (hp) { 34943971Sstephh ddi_dmareq_mapout(hp->mapaddr, hp->len, hp->map_flags, 34953971Sstephh hp->map_pp, hp->map_pplist); 34960Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 34970Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 34980Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 34990Sstevel@tonic-gate } 35000Sstevel@tonic-gate return (retval); 35010Sstevel@tonic-gate } 35020Sstevel@tonic-gate 35030Sstevel@tonic-gate 35040Sstevel@tonic-gate /* 35050Sstevel@tonic-gate * our ddi_dma_allochdl routine 35060Sstevel@tonic-gate */ 35070Sstevel@tonic-gate static int 35080Sstevel@tonic-gate bofi_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp, 35090Sstevel@tonic-gate int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 35100Sstevel@tonic-gate { 35110Sstevel@tonic-gate int retval = DDI_DMA_NORESOURCES; 35120Sstevel@tonic-gate struct bofi_shadow *hp, *xhp; 35130Sstevel@tonic-gate int maxrnumber = 0; 35140Sstevel@tonic-gate struct bofi_shadow *dhashp; 35150Sstevel@tonic-gate struct bofi_shadow *hhashp; 35160Sstevel@tonic-gate ddi_dma_impl_t *mp; 35170Sstevel@tonic-gate 35180Sstevel@tonic-gate /* 35190Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 35200Sstevel@tonic-gate */ 35210Sstevel@tonic-gate if (!driver_under_test(rdip)) 35220Sstevel@tonic-gate return (save_bus_ops.bus_dma_allochdl(dip, rdip, attrp, 35230Sstevel@tonic-gate waitfp, arg, handlep)); 35240Sstevel@tonic-gate 35250Sstevel@tonic-gate /* 35260Sstevel@tonic-gate * allocate shadow handle structure and fill it in 35270Sstevel@tonic-gate */ 35280Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), 35290Sstevel@tonic-gate ((waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP)); 35300Sstevel@tonic-gate if (hp == NULL) { 35310Sstevel@tonic-gate /* 35320Sstevel@tonic-gate * what to do here? Wait a bit and try again 35330Sstevel@tonic-gate */ 35340Sstevel@tonic-gate if (waitfp != DDI_DMA_DONTWAIT) 35350Sstevel@tonic-gate (void) timeout((void (*)())waitfp, arg, 10); 35360Sstevel@tonic-gate return (retval); 35370Sstevel@tonic-gate } 35380Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 35390Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 35400Sstevel@tonic-gate hp->dip = rdip; 35410Sstevel@tonic-gate hp->link = NULL; 35420Sstevel@tonic-gate hp->type = BOFI_NULL; 35430Sstevel@tonic-gate /* 35440Sstevel@tonic-gate * call nexus to do the real work 35450Sstevel@tonic-gate */ 35460Sstevel@tonic-gate retval = save_bus_ops.bus_dma_allochdl(dip, rdip, attrp, waitfp, arg, 35470Sstevel@tonic-gate handlep); 35480Sstevel@tonic-gate if (retval != DDI_SUCCESS) { 35490Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 35500Sstevel@tonic-gate return (retval); 35510Sstevel@tonic-gate } 35520Sstevel@tonic-gate /* 35530Sstevel@tonic-gate * now point set dma_handle to point to real handle 35540Sstevel@tonic-gate */ 35550Sstevel@tonic-gate hp->hdl.dma_handle = *handlep; 35560Sstevel@tonic-gate mp = (ddi_dma_impl_t *)*handlep; 35570Sstevel@tonic-gate mp->dmai_fault_check = bofi_check_dma_hdl; 35580Sstevel@tonic-gate /* 35590Sstevel@tonic-gate * bind and unbind are cached in devinfo - must overwrite them 35600Sstevel@tonic-gate * - note that our bind and unbind are quite happy dealing with 35610Sstevel@tonic-gate * any handles for this devinfo that were previously allocated 35620Sstevel@tonic-gate */ 35630Sstevel@tonic-gate if (save_bus_ops.bus_dma_bindhdl == DEVI(rdip)->devi_bus_dma_bindfunc) 35640Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_bindfunc = bofi_dma_bindhdl; 35650Sstevel@tonic-gate if (save_bus_ops.bus_dma_unbindhdl == 35660Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc) 35670Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc = bofi_dma_unbindhdl; 35680Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 35690Sstevel@tonic-gate mutex_enter(&bofi_mutex); 35700Sstevel@tonic-gate /* 35710Sstevel@tonic-gate * get an "rnumber" for this handle - really just seeking to 35720Sstevel@tonic-gate * get a unique number - generally only care for early allocated 35730Sstevel@tonic-gate * handles - so we get as far as INT_MAX, just stay there 35740Sstevel@tonic-gate */ 35750Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 35760Sstevel@tonic-gate for (xhp = dhashp->dnext; xhp != dhashp; xhp = xhp->dnext) 35770Sstevel@tonic-gate if (ddi_name_to_major(xhp->name) == 35780Sstevel@tonic-gate ddi_name_to_major(hp->name) && 35790Sstevel@tonic-gate xhp->instance == hp->instance && 35800Sstevel@tonic-gate (xhp->type == BOFI_DMA_HDL || 35810Sstevel@tonic-gate xhp->type == BOFI_NULL)) 35820Sstevel@tonic-gate if (xhp->rnumber >= maxrnumber) { 35830Sstevel@tonic-gate if (xhp->rnumber == INT_MAX) 35840Sstevel@tonic-gate maxrnumber = INT_MAX; 35850Sstevel@tonic-gate else 35860Sstevel@tonic-gate maxrnumber = xhp->rnumber + 1; 35870Sstevel@tonic-gate } 35880Sstevel@tonic-gate hp->rnumber = maxrnumber; 35890Sstevel@tonic-gate /* 35900Sstevel@tonic-gate * add to dhash, hhash and inuse lists 35910Sstevel@tonic-gate */ 35920Sstevel@tonic-gate hp->next = shadow_list.next; 35930Sstevel@tonic-gate shadow_list.next->prev = hp; 35940Sstevel@tonic-gate hp->prev = &shadow_list; 35950Sstevel@tonic-gate shadow_list.next = hp; 35960Sstevel@tonic-gate hhashp = HDL_HHASH(*handlep); 35970Sstevel@tonic-gate hp->hnext = hhashp->hnext; 35980Sstevel@tonic-gate hhashp->hnext->hprev = hp; 35990Sstevel@tonic-gate hp->hprev = hhashp; 36000Sstevel@tonic-gate hhashp->hnext = hp; 36010Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 36020Sstevel@tonic-gate hp->dnext = dhashp->dnext; 36030Sstevel@tonic-gate dhashp->dnext->dprev = hp; 36040Sstevel@tonic-gate hp->dprev = dhashp; 36050Sstevel@tonic-gate dhashp->dnext = hp; 36060Sstevel@tonic-gate mutex_exit(&bofi_mutex); 36070Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 36080Sstevel@tonic-gate return (retval); 36090Sstevel@tonic-gate } 36100Sstevel@tonic-gate 36110Sstevel@tonic-gate 36120Sstevel@tonic-gate /* 36130Sstevel@tonic-gate * our ddi_dma_freehdl routine 36140Sstevel@tonic-gate */ 36150Sstevel@tonic-gate static int 36160Sstevel@tonic-gate bofi_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 36170Sstevel@tonic-gate { 36180Sstevel@tonic-gate int retval; 36190Sstevel@tonic-gate struct bofi_shadow *hp; 36200Sstevel@tonic-gate struct bofi_shadow *hhashp; 36210Sstevel@tonic-gate 36220Sstevel@tonic-gate /* 36230Sstevel@tonic-gate * find shadow for this handle 36240Sstevel@tonic-gate */ 36250Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 36260Sstevel@tonic-gate mutex_enter(&bofi_mutex); 36270Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 36280Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 36290Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 36300Sstevel@tonic-gate break; 36310Sstevel@tonic-gate mutex_exit(&bofi_mutex); 36320Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 36330Sstevel@tonic-gate /* 36340Sstevel@tonic-gate * call nexus to do the real work 36350Sstevel@tonic-gate */ 36360Sstevel@tonic-gate retval = save_bus_ops.bus_dma_freehdl(dip, rdip, handle); 36370Sstevel@tonic-gate if (retval != DDI_SUCCESS) { 36380Sstevel@tonic-gate return (retval); 36390Sstevel@tonic-gate } 36400Sstevel@tonic-gate /* 36410Sstevel@tonic-gate * did we really have a shadow for this handle 36420Sstevel@tonic-gate */ 36430Sstevel@tonic-gate if (hp == hhashp) 36440Sstevel@tonic-gate return (retval); 36450Sstevel@tonic-gate /* 36460Sstevel@tonic-gate * yes we have - see if it's still bound 36470Sstevel@tonic-gate */ 36480Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 36490Sstevel@tonic-gate mutex_enter(&bofi_mutex); 36500Sstevel@tonic-gate if (hp->type != BOFI_NULL) 36510Sstevel@tonic-gate panic("driver freeing bound dma_handle"); 36520Sstevel@tonic-gate /* 36530Sstevel@tonic-gate * remove from dhash, hhash and inuse lists 36540Sstevel@tonic-gate */ 36550Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 36560Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 36570Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 36580Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 36590Sstevel@tonic-gate hp->next->prev = hp->prev; 36600Sstevel@tonic-gate hp->prev->next = hp->next; 36610Sstevel@tonic-gate mutex_exit(&bofi_mutex); 36620Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 36630Sstevel@tonic-gate 36640Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 36650Sstevel@tonic-gate return (retval); 36660Sstevel@tonic-gate } 36670Sstevel@tonic-gate 36680Sstevel@tonic-gate 36690Sstevel@tonic-gate /* 36700Sstevel@tonic-gate * our ddi_dma_bindhdl routine 36710Sstevel@tonic-gate */ 36720Sstevel@tonic-gate static int 36730Sstevel@tonic-gate bofi_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 36740Sstevel@tonic-gate ddi_dma_handle_t handle, struct ddi_dma_req *dmareqp, 36750Sstevel@tonic-gate ddi_dma_cookie_t *cookiep, uint_t *ccountp) 36760Sstevel@tonic-gate { 36770Sstevel@tonic-gate int retval = DDI_DMA_NORESOURCES; 36780Sstevel@tonic-gate auto struct ddi_dma_req dmareq; 36790Sstevel@tonic-gate struct bofi_shadow *hp; 36800Sstevel@tonic-gate struct bofi_shadow *hhashp; 36810Sstevel@tonic-gate ddi_dma_impl_t *mp; 36820Sstevel@tonic-gate unsigned long pagemask = ddi_ptob(rdip, 1) - 1; 36830Sstevel@tonic-gate 36840Sstevel@tonic-gate /* 36850Sstevel@tonic-gate * check we really have a shadow for this handle 36860Sstevel@tonic-gate */ 36870Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 36880Sstevel@tonic-gate mutex_enter(&bofi_mutex); 36890Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 36900Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 36910Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 36920Sstevel@tonic-gate break; 36930Sstevel@tonic-gate mutex_exit(&bofi_mutex); 36940Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 36950Sstevel@tonic-gate if (hp == hhashp) { 36960Sstevel@tonic-gate /* 36970Sstevel@tonic-gate * no we don't - just call nexus to do the real work 36980Sstevel@tonic-gate */ 36990Sstevel@tonic-gate return save_bus_ops.bus_dma_bindhdl(dip, rdip, handle, dmareqp, 37000Sstevel@tonic-gate cookiep, ccountp); 37010Sstevel@tonic-gate } 37020Sstevel@tonic-gate /* 37030Sstevel@tonic-gate * yes we have - see if it's already bound 37040Sstevel@tonic-gate */ 37050Sstevel@tonic-gate if (hp->type != BOFI_NULL) 37060Sstevel@tonic-gate return (DDI_DMA_INUSE); 37070Sstevel@tonic-gate 37080Sstevel@tonic-gate hp->flags = dmareqp->dmar_flags; 37093971Sstephh if (dmareqp->dmar_object.dmao_type == DMA_OTYP_PAGES) { 37103971Sstephh hp->map_flags = B_PAGEIO; 37113971Sstephh hp->map_pp = dmareqp->dmar_object.dmao_obj.pp_obj.pp_pp; 37123971Sstephh } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_priv != NULL) { 37133971Sstephh hp->map_flags = B_SHADOW; 37143971Sstephh hp->map_pplist = dmareqp->dmar_object.dmao_obj.virt_obj.v_priv; 37153971Sstephh } else { 37163971Sstephh hp->map_flags = 0; 37173971Sstephh } 37180Sstevel@tonic-gate /* 37190Sstevel@tonic-gate * get a kernel virtual mapping 37200Sstevel@tonic-gate */ 37210Sstevel@tonic-gate hp->addr = ddi_dmareq_mapin(dmareqp, &hp->mapaddr, &hp->len); 37220Sstevel@tonic-gate if (hp->addr == NULL) 37230Sstevel@tonic-gate goto error; 37240Sstevel@tonic-gate if (bofi_sync_check) { 37250Sstevel@tonic-gate /* 37260Sstevel@tonic-gate * Take a copy and pass pointers to this up to nexus instead. 37270Sstevel@tonic-gate * Data will be copied from the original on explicit 37280Sstevel@tonic-gate * and implicit ddi_dma_sync() 37290Sstevel@tonic-gate * 37300Sstevel@tonic-gate * - maintain page alignment because some devices assume it. 37310Sstevel@tonic-gate */ 37320Sstevel@tonic-gate hp->origaddr = hp->addr; 37330Sstevel@tonic-gate hp->allocaddr = ddi_umem_alloc( 37340Sstevel@tonic-gate ((uintptr_t)hp->addr & pagemask) + hp->len, 37350Sstevel@tonic-gate (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP, 37360Sstevel@tonic-gate &hp->umem_cookie); 37370Sstevel@tonic-gate if (hp->allocaddr == NULL) 37380Sstevel@tonic-gate goto error; 37390Sstevel@tonic-gate hp->addr = hp->allocaddr + ((uintptr_t)hp->addr & pagemask); 37400Sstevel@tonic-gate if (dmareqp->dmar_flags & DDI_DMA_WRITE) 37410Sstevel@tonic-gate xbcopy(hp->origaddr, hp->addr, hp->len); 37420Sstevel@tonic-gate dmareq = *dmareqp; 37430Sstevel@tonic-gate dmareq.dmar_object.dmao_size = hp->len; 37440Sstevel@tonic-gate dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR; 37450Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_as = &kas; 37460Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_addr = hp->addr; 37470Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL; 37480Sstevel@tonic-gate dmareqp = &dmareq; 37490Sstevel@tonic-gate } 37500Sstevel@tonic-gate /* 37510Sstevel@tonic-gate * call nexus to do the real work 37520Sstevel@tonic-gate */ 37530Sstevel@tonic-gate retval = save_bus_ops.bus_dma_bindhdl(dip, rdip, handle, dmareqp, 37540Sstevel@tonic-gate cookiep, ccountp); 37550Sstevel@tonic-gate if (retval != DDI_SUCCESS) 37560Sstevel@tonic-gate goto error2; 37570Sstevel@tonic-gate /* 37580Sstevel@tonic-gate * unset DMP_NOSYNC 37590Sstevel@tonic-gate */ 37600Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 37610Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 37620Sstevel@tonic-gate /* 37630Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 37640Sstevel@tonic-gate * acc_handle and corrupt if required (as there is an implicit 37650Sstevel@tonic-gate * ddi_dma_sync() in this call) 37660Sstevel@tonic-gate */ 37670Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 37680Sstevel@tonic-gate mutex_enter(&bofi_mutex); 37690Sstevel@tonic-gate hp->type = BOFI_DMA_HDL; 37700Sstevel@tonic-gate chain_on_errdefs(hp); 37710Sstevel@tonic-gate mutex_exit(&bofi_mutex); 37720Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 37730Sstevel@tonic-gate return (retval); 37740Sstevel@tonic-gate 37750Sstevel@tonic-gate error: 37760Sstevel@tonic-gate if (dmareqp->dmar_fp != DDI_DMA_DONTWAIT) { 37770Sstevel@tonic-gate /* 37780Sstevel@tonic-gate * what to do here? Wait a bit and try again 37790Sstevel@tonic-gate */ 37800Sstevel@tonic-gate (void) timeout((void (*)())dmareqp->dmar_fp, 37810Sstevel@tonic-gate dmareqp->dmar_arg, 10); 37820Sstevel@tonic-gate } 37830Sstevel@tonic-gate error2: 37840Sstevel@tonic-gate if (hp) { 37853971Sstephh ddi_dmareq_mapout(hp->mapaddr, hp->len, hp->map_flags, 37863971Sstephh hp->map_pp, hp->map_pplist); 37870Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 37880Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 37890Sstevel@tonic-gate hp->mapaddr = NULL; 37900Sstevel@tonic-gate hp->allocaddr = NULL; 37910Sstevel@tonic-gate hp->origaddr = NULL; 37920Sstevel@tonic-gate } 37930Sstevel@tonic-gate return (retval); 37940Sstevel@tonic-gate } 37950Sstevel@tonic-gate 37960Sstevel@tonic-gate 37970Sstevel@tonic-gate /* 37980Sstevel@tonic-gate * our ddi_dma_unbindhdl routine 37990Sstevel@tonic-gate */ 38000Sstevel@tonic-gate static int 38010Sstevel@tonic-gate bofi_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 38020Sstevel@tonic-gate { 38030Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 38040Sstevel@tonic-gate struct bofi_errent *ep; 38050Sstevel@tonic-gate int retval; 38060Sstevel@tonic-gate struct bofi_shadow *hp; 38070Sstevel@tonic-gate struct bofi_shadow *hhashp; 38080Sstevel@tonic-gate 38090Sstevel@tonic-gate /* 38100Sstevel@tonic-gate * call nexus to do the real work 38110Sstevel@tonic-gate */ 38120Sstevel@tonic-gate retval = save_bus_ops.bus_dma_unbindhdl(dip, rdip, handle); 38130Sstevel@tonic-gate if (retval != DDI_SUCCESS) 38140Sstevel@tonic-gate return (retval); 38150Sstevel@tonic-gate /* 38160Sstevel@tonic-gate * check we really have a shadow for this handle 38170Sstevel@tonic-gate */ 38180Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 38190Sstevel@tonic-gate mutex_enter(&bofi_mutex); 38200Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 38210Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 38220Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 38230Sstevel@tonic-gate break; 38240Sstevel@tonic-gate if (hp == hhashp) { 38250Sstevel@tonic-gate mutex_exit(&bofi_mutex); 38260Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 38270Sstevel@tonic-gate return (retval); 38280Sstevel@tonic-gate } 38290Sstevel@tonic-gate /* 38300Sstevel@tonic-gate * yes we have - see if it's already unbound 38310Sstevel@tonic-gate */ 38320Sstevel@tonic-gate if (hp->type == BOFI_NULL) 38330Sstevel@tonic-gate panic("driver unbinding unbound dma_handle"); 38340Sstevel@tonic-gate /* 38350Sstevel@tonic-gate * free any errdef link structures tagged on to this 38360Sstevel@tonic-gate * shadow handle 38370Sstevel@tonic-gate */ 38380Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 38390Sstevel@tonic-gate next_lp = lp->link; 38400Sstevel@tonic-gate /* 38410Sstevel@tonic-gate * there is an implicit sync_for_cpu on free - 38420Sstevel@tonic-gate * may need to corrupt 38430Sstevel@tonic-gate */ 38440Sstevel@tonic-gate ep = lp->errentp; 38450Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_R) && 38460Sstevel@tonic-gate (hp->flags & DDI_DMA_READ) && 38470Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 38480Sstevel@tonic-gate do_dma_corrupt(hp, ep, DDI_DMA_SYNC_FORCPU, 0, hp->len); 38490Sstevel@tonic-gate } 38500Sstevel@tonic-gate lp->link = bofi_link_freelist; 38510Sstevel@tonic-gate bofi_link_freelist = lp; 38520Sstevel@tonic-gate lp = next_lp; 38530Sstevel@tonic-gate } 38540Sstevel@tonic-gate hp->link = NULL; 38550Sstevel@tonic-gate hp->type = BOFI_NULL; 38560Sstevel@tonic-gate mutex_exit(&bofi_mutex); 38570Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 38580Sstevel@tonic-gate 38590Sstevel@tonic-gate if (bofi_sync_check && (hp->flags & DDI_DMA_READ)) 38600Sstevel@tonic-gate /* 38610Sstevel@tonic-gate * implicit sync_for_cpu - copy data back 38620Sstevel@tonic-gate */ 38630Sstevel@tonic-gate if (hp->allocaddr) 38640Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 38653971Sstephh ddi_dmareq_mapout(hp->mapaddr, hp->len, hp->map_flags, 38663971Sstephh hp->map_pp, hp->map_pplist); 38670Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 38680Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 38690Sstevel@tonic-gate hp->mapaddr = NULL; 38700Sstevel@tonic-gate hp->allocaddr = NULL; 38710Sstevel@tonic-gate hp->origaddr = NULL; 38720Sstevel@tonic-gate return (retval); 38730Sstevel@tonic-gate } 38740Sstevel@tonic-gate 38750Sstevel@tonic-gate 38760Sstevel@tonic-gate /* 38770Sstevel@tonic-gate * our ddi_dma_sync routine 38780Sstevel@tonic-gate */ 38790Sstevel@tonic-gate static int 38800Sstevel@tonic-gate bofi_dma_flush(dev_info_t *dip, dev_info_t *rdip, 38810Sstevel@tonic-gate ddi_dma_handle_t handle, off_t off, size_t len, uint_t flags) 38820Sstevel@tonic-gate { 38830Sstevel@tonic-gate struct bofi_link *lp; 38840Sstevel@tonic-gate struct bofi_errent *ep; 38850Sstevel@tonic-gate struct bofi_shadow *hp; 38860Sstevel@tonic-gate struct bofi_shadow *hhashp; 38870Sstevel@tonic-gate int retval; 38880Sstevel@tonic-gate 38890Sstevel@tonic-gate if (flags == DDI_DMA_SYNC_FORCPU || flags == DDI_DMA_SYNC_FORKERNEL) { 38900Sstevel@tonic-gate /* 38910Sstevel@tonic-gate * in this case get nexus driver to do sync first 38920Sstevel@tonic-gate */ 38930Sstevel@tonic-gate retval = save_bus_ops.bus_dma_flush(dip, rdip, handle, off, 38940Sstevel@tonic-gate len, flags); 38950Sstevel@tonic-gate if (retval != DDI_SUCCESS) 38960Sstevel@tonic-gate return (retval); 38970Sstevel@tonic-gate } 38980Sstevel@tonic-gate /* 38990Sstevel@tonic-gate * check we really have a shadow for this handle 39000Sstevel@tonic-gate */ 39010Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 39020Sstevel@tonic-gate mutex_enter(&bofi_mutex); 39030Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 39040Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 39050Sstevel@tonic-gate if (hp->hdl.dma_handle == handle && 39060Sstevel@tonic-gate hp->type == BOFI_DMA_HDL) 39070Sstevel@tonic-gate break; 39080Sstevel@tonic-gate mutex_exit(&bofi_mutex); 39090Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 39100Sstevel@tonic-gate if (hp != hhashp) { 39110Sstevel@tonic-gate /* 39120Sstevel@tonic-gate * yes - do we need to copy data from original 39130Sstevel@tonic-gate */ 39140Sstevel@tonic-gate if (bofi_sync_check && flags == DDI_DMA_SYNC_FORDEV) 39150Sstevel@tonic-gate if (hp->allocaddr) 39160Sstevel@tonic-gate xbcopy(hp->origaddr+off, hp->addr+off, 39170Sstevel@tonic-gate len ? len : (hp->len - off)); 39180Sstevel@tonic-gate /* 39190Sstevel@tonic-gate * yes - check if we need to corrupt the data 39200Sstevel@tonic-gate */ 39210Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 39220Sstevel@tonic-gate mutex_enter(&bofi_mutex); 39230Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 39240Sstevel@tonic-gate ep = lp->errentp; 39250Sstevel@tonic-gate if ((((ep->errdef.access_type & BOFI_DMA_R) && 39260Sstevel@tonic-gate (flags == DDI_DMA_SYNC_FORCPU || 39270Sstevel@tonic-gate flags == DDI_DMA_SYNC_FORKERNEL)) || 39280Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_W) && 39290Sstevel@tonic-gate (flags == DDI_DMA_SYNC_FORDEV))) && 39300Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 39310Sstevel@tonic-gate do_dma_corrupt(hp, ep, flags, off, 39320Sstevel@tonic-gate len ? len : (hp->len - off)); 39330Sstevel@tonic-gate } 39340Sstevel@tonic-gate } 39350Sstevel@tonic-gate mutex_exit(&bofi_mutex); 39360Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 39370Sstevel@tonic-gate /* 39380Sstevel@tonic-gate * do we need to copy data to original 39390Sstevel@tonic-gate */ 39400Sstevel@tonic-gate if (bofi_sync_check && (flags == DDI_DMA_SYNC_FORCPU || 39410Sstevel@tonic-gate flags == DDI_DMA_SYNC_FORKERNEL)) 39420Sstevel@tonic-gate if (hp->allocaddr) 39430Sstevel@tonic-gate xbcopy(hp->addr+off, hp->origaddr+off, 39440Sstevel@tonic-gate len ? len : (hp->len - off)); 39450Sstevel@tonic-gate } 39460Sstevel@tonic-gate if (flags == DDI_DMA_SYNC_FORDEV) 39470Sstevel@tonic-gate /* 39480Sstevel@tonic-gate * in this case get nexus driver to do sync last 39490Sstevel@tonic-gate */ 39500Sstevel@tonic-gate retval = save_bus_ops.bus_dma_flush(dip, rdip, handle, off, 39510Sstevel@tonic-gate len, flags); 39520Sstevel@tonic-gate return (retval); 39530Sstevel@tonic-gate } 39540Sstevel@tonic-gate 39550Sstevel@tonic-gate 39560Sstevel@tonic-gate /* 39570Sstevel@tonic-gate * our dma_win routine 39580Sstevel@tonic-gate */ 39590Sstevel@tonic-gate static int 39600Sstevel@tonic-gate bofi_dma_win(dev_info_t *dip, dev_info_t *rdip, 39610Sstevel@tonic-gate ddi_dma_handle_t handle, uint_t win, off_t *offp, 39620Sstevel@tonic-gate size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp) 39630Sstevel@tonic-gate { 39640Sstevel@tonic-gate struct bofi_shadow *hp; 39650Sstevel@tonic-gate struct bofi_shadow *hhashp; 39660Sstevel@tonic-gate int retval; 39670Sstevel@tonic-gate ddi_dma_impl_t *mp; 39680Sstevel@tonic-gate 39690Sstevel@tonic-gate /* 39700Sstevel@tonic-gate * call nexus to do the real work 39710Sstevel@tonic-gate */ 39720Sstevel@tonic-gate retval = save_bus_ops.bus_dma_win(dip, rdip, handle, win, offp, lenp, 39730Sstevel@tonic-gate cookiep, ccountp); 39740Sstevel@tonic-gate if (retval != DDI_SUCCESS) 39750Sstevel@tonic-gate return (retval); 39760Sstevel@tonic-gate /* 39770Sstevel@tonic-gate * check we really have a shadow for this handle 39780Sstevel@tonic-gate */ 39790Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 39800Sstevel@tonic-gate mutex_enter(&bofi_mutex); 39810Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 39820Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 39830Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 39840Sstevel@tonic-gate break; 39850Sstevel@tonic-gate if (hp != hhashp) { 39860Sstevel@tonic-gate /* 39870Sstevel@tonic-gate * yes - make sure DMP_NOSYNC is unset 39880Sstevel@tonic-gate */ 39890Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 39900Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 39910Sstevel@tonic-gate } 39920Sstevel@tonic-gate mutex_exit(&bofi_mutex); 39930Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 39940Sstevel@tonic-gate return (retval); 39950Sstevel@tonic-gate } 39960Sstevel@tonic-gate 39970Sstevel@tonic-gate 39980Sstevel@tonic-gate /* 39990Sstevel@tonic-gate * our dma_ctl routine 40000Sstevel@tonic-gate */ 40010Sstevel@tonic-gate static int 40020Sstevel@tonic-gate bofi_dma_ctl(dev_info_t *dip, dev_info_t *rdip, 40030Sstevel@tonic-gate ddi_dma_handle_t handle, enum ddi_dma_ctlops request, 40040Sstevel@tonic-gate off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags) 40050Sstevel@tonic-gate { 40060Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 40070Sstevel@tonic-gate struct bofi_errent *ep; 40080Sstevel@tonic-gate struct bofi_shadow *hp; 40090Sstevel@tonic-gate struct bofi_shadow *hhashp; 40100Sstevel@tonic-gate int retval; 40110Sstevel@tonic-gate int i; 40120Sstevel@tonic-gate struct bofi_shadow *dummyhp; 40130Sstevel@tonic-gate ddi_dma_impl_t *mp; 40140Sstevel@tonic-gate 40150Sstevel@tonic-gate /* 40160Sstevel@tonic-gate * get nexus to do real work 40170Sstevel@tonic-gate */ 40180Sstevel@tonic-gate retval = save_bus_ops.bus_dma_ctl(dip, rdip, handle, request, offp, 40190Sstevel@tonic-gate lenp, objp, flags); 40200Sstevel@tonic-gate if (retval != DDI_SUCCESS) 40210Sstevel@tonic-gate return (retval); 40220Sstevel@tonic-gate /* 40230Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 40240Sstevel@tonic-gate */ 40250Sstevel@tonic-gate if (!driver_under_test(rdip)) 40260Sstevel@tonic-gate return (DDI_SUCCESS); 40270Sstevel@tonic-gate 40280Sstevel@tonic-gate #if defined(__sparc) 40290Sstevel@tonic-gate /* 40300Sstevel@tonic-gate * check if this is a dvma_reserve - that one's like a 40310Sstevel@tonic-gate * dma_allochdl and needs to be handled separately 40320Sstevel@tonic-gate */ 40330Sstevel@tonic-gate if (request == DDI_DMA_RESERVE) { 40340Sstevel@tonic-gate bofi_dvma_reserve(rdip, *(ddi_dma_handle_t *)objp); 40350Sstevel@tonic-gate return (DDI_SUCCESS); 40360Sstevel@tonic-gate } 40370Sstevel@tonic-gate #endif 40380Sstevel@tonic-gate /* 40390Sstevel@tonic-gate * check we really have a shadow for this handle 40400Sstevel@tonic-gate */ 40410Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 40420Sstevel@tonic-gate mutex_enter(&bofi_mutex); 40430Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 40440Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 40450Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 40460Sstevel@tonic-gate break; 40470Sstevel@tonic-gate if (hp == hhashp) { 40480Sstevel@tonic-gate mutex_exit(&bofi_mutex); 40490Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 40500Sstevel@tonic-gate return (retval); 40510Sstevel@tonic-gate } 40520Sstevel@tonic-gate /* 40530Sstevel@tonic-gate * yes we have - see what kind of command this is 40540Sstevel@tonic-gate */ 40550Sstevel@tonic-gate switch (request) { 40560Sstevel@tonic-gate case DDI_DMA_RELEASE: 40570Sstevel@tonic-gate /* 40580Sstevel@tonic-gate * dvma release - release dummy handle and all the index handles 40590Sstevel@tonic-gate */ 40600Sstevel@tonic-gate dummyhp = hp; 40610Sstevel@tonic-gate dummyhp->hnext->hprev = dummyhp->hprev; 40620Sstevel@tonic-gate dummyhp->hprev->hnext = dummyhp->hnext; 40630Sstevel@tonic-gate mutex_exit(&bofi_mutex); 40640Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 40650Sstevel@tonic-gate for (i = 0; i < dummyhp->len; i++) { 40660Sstevel@tonic-gate hp = dummyhp->hparrayp[i]; 40670Sstevel@tonic-gate /* 40680Sstevel@tonic-gate * chek none of the index handles were still loaded 40690Sstevel@tonic-gate */ 40700Sstevel@tonic-gate if (hp->type != BOFI_NULL) 40710Sstevel@tonic-gate panic("driver releasing loaded dvma"); 40720Sstevel@tonic-gate /* 40730Sstevel@tonic-gate * remove from dhash and inuse lists 40740Sstevel@tonic-gate */ 40750Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 40760Sstevel@tonic-gate mutex_enter(&bofi_mutex); 40770Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 40780Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 40790Sstevel@tonic-gate hp->next->prev = hp->prev; 40800Sstevel@tonic-gate hp->prev->next = hp->next; 40810Sstevel@tonic-gate mutex_exit(&bofi_mutex); 40820Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 40830Sstevel@tonic-gate 40840Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 40850Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 40860Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 40870Sstevel@tonic-gate } 40880Sstevel@tonic-gate kmem_free(dummyhp->hparrayp, dummyhp->len * 40890Sstevel@tonic-gate sizeof (struct bofi_shadow *)); 40900Sstevel@tonic-gate kmem_free(dummyhp, sizeof (struct bofi_shadow)); 40910Sstevel@tonic-gate return (retval); 40920Sstevel@tonic-gate case DDI_DMA_FREE: 40930Sstevel@tonic-gate /* 40940Sstevel@tonic-gate * ddi_dma_free case - remove from dhash, hhash and inuse lists 40950Sstevel@tonic-gate */ 40960Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 40970Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 40980Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 40990Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 41000Sstevel@tonic-gate hp->next->prev = hp->prev; 41010Sstevel@tonic-gate hp->prev->next = hp->next; 41020Sstevel@tonic-gate /* 41030Sstevel@tonic-gate * free any errdef link structures tagged on to this 41040Sstevel@tonic-gate * shadow handle 41050Sstevel@tonic-gate */ 41060Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 41070Sstevel@tonic-gate next_lp = lp->link; 41080Sstevel@tonic-gate /* 41090Sstevel@tonic-gate * there is an implicit sync_for_cpu on free - 41100Sstevel@tonic-gate * may need to corrupt 41110Sstevel@tonic-gate */ 41120Sstevel@tonic-gate ep = lp->errentp; 41130Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_R) && 41140Sstevel@tonic-gate (hp->flags & DDI_DMA_READ) && 41150Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 41160Sstevel@tonic-gate do_dma_corrupt(hp, ep, DDI_DMA_SYNC_FORCPU, 41170Sstevel@tonic-gate 0, hp->len); 41180Sstevel@tonic-gate } 41190Sstevel@tonic-gate lp->link = bofi_link_freelist; 41200Sstevel@tonic-gate bofi_link_freelist = lp; 41210Sstevel@tonic-gate lp = next_lp; 41220Sstevel@tonic-gate } 41230Sstevel@tonic-gate hp->link = NULL; 41240Sstevel@tonic-gate mutex_exit(&bofi_mutex); 41250Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 41260Sstevel@tonic-gate 41270Sstevel@tonic-gate if (bofi_sync_check && (hp->flags & DDI_DMA_READ)) 41280Sstevel@tonic-gate if (hp->allocaddr) 41290Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 41303971Sstephh ddi_dmareq_mapout(hp->mapaddr, hp->len, hp->map_flags, 41313971Sstephh hp->map_pp, hp->map_pplist); 41320Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 41330Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 41340Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 41350Sstevel@tonic-gate return (retval); 41360Sstevel@tonic-gate case DDI_DMA_MOVWIN: 41370Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 41380Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 41390Sstevel@tonic-gate break; 41400Sstevel@tonic-gate case DDI_DMA_NEXTWIN: 41410Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 41420Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 41430Sstevel@tonic-gate break; 41440Sstevel@tonic-gate default: 41450Sstevel@tonic-gate break; 41460Sstevel@tonic-gate } 41470Sstevel@tonic-gate mutex_exit(&bofi_mutex); 41480Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 41490Sstevel@tonic-gate return (retval); 41500Sstevel@tonic-gate } 41510Sstevel@tonic-gate 41520Sstevel@tonic-gate #if defined(__sparc) 41530Sstevel@tonic-gate /* 41540Sstevel@tonic-gate * dvma reserve case from bofi_dma_ctl() 41550Sstevel@tonic-gate */ 41560Sstevel@tonic-gate static void 41570Sstevel@tonic-gate bofi_dvma_reserve(dev_info_t *rdip, ddi_dma_handle_t handle) 41580Sstevel@tonic-gate { 41590Sstevel@tonic-gate struct bofi_shadow *hp; 41600Sstevel@tonic-gate struct bofi_shadow *dummyhp; 41610Sstevel@tonic-gate struct bofi_shadow *dhashp; 41620Sstevel@tonic-gate struct bofi_shadow *hhashp; 41630Sstevel@tonic-gate ddi_dma_impl_t *mp; 41640Sstevel@tonic-gate struct fast_dvma *nexus_private; 41650Sstevel@tonic-gate int i, count; 41660Sstevel@tonic-gate 41670Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 41680Sstevel@tonic-gate count = mp->dmai_ndvmapages; 41690Sstevel@tonic-gate /* 41700Sstevel@tonic-gate * allocate dummy shadow handle structure 41710Sstevel@tonic-gate */ 41720Sstevel@tonic-gate dummyhp = kmem_zalloc(sizeof (*dummyhp), KM_SLEEP); 41730Sstevel@tonic-gate if (mp->dmai_rflags & DMP_BYPASSNEXUS) { 41740Sstevel@tonic-gate /* 41750Sstevel@tonic-gate * overlay our routines over the nexus's dvma routines 41760Sstevel@tonic-gate */ 41770Sstevel@tonic-gate nexus_private = (struct fast_dvma *)mp->dmai_nexus_private; 41780Sstevel@tonic-gate dummyhp->save.dvma_ops = *(nexus_private->ops); 41790Sstevel@tonic-gate nexus_private->ops = &bofi_dvma_ops; 41800Sstevel@tonic-gate } 41810Sstevel@tonic-gate /* 41820Sstevel@tonic-gate * now fill in the dummy handle. This just gets put on hhash queue 41830Sstevel@tonic-gate * so our dvma routines can find and index off to the handle they 41840Sstevel@tonic-gate * really want. 41850Sstevel@tonic-gate */ 41860Sstevel@tonic-gate (void) strncpy(dummyhp->name, ddi_get_name(rdip), NAMESIZE); 41870Sstevel@tonic-gate dummyhp->instance = ddi_get_instance(rdip); 41880Sstevel@tonic-gate dummyhp->rnumber = -1; 41890Sstevel@tonic-gate dummyhp->dip = rdip; 41900Sstevel@tonic-gate dummyhp->len = count; 41910Sstevel@tonic-gate dummyhp->hdl.dma_handle = handle; 41920Sstevel@tonic-gate dummyhp->link = NULL; 41930Sstevel@tonic-gate dummyhp->type = BOFI_NULL; 41940Sstevel@tonic-gate /* 41950Sstevel@tonic-gate * allocate space for real handles 41960Sstevel@tonic-gate */ 41970Sstevel@tonic-gate dummyhp->hparrayp = kmem_alloc(count * 41980Sstevel@tonic-gate sizeof (struct bofi_shadow *), KM_SLEEP); 41990Sstevel@tonic-gate for (i = 0; i < count; i++) { 42000Sstevel@tonic-gate /* 42010Sstevel@tonic-gate * allocate shadow handle structures and fill them in 42020Sstevel@tonic-gate */ 42030Sstevel@tonic-gate hp = kmem_zalloc(sizeof (*hp), KM_SLEEP); 42040Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 42050Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 42060Sstevel@tonic-gate hp->rnumber = -1; 42070Sstevel@tonic-gate hp->dip = rdip; 42080Sstevel@tonic-gate hp->hdl.dma_handle = 0; 42090Sstevel@tonic-gate hp->link = NULL; 42100Sstevel@tonic-gate hp->type = BOFI_NULL; 42110Sstevel@tonic-gate if (bofi_sync_check) { 42120Sstevel@tonic-gate unsigned long pagemask = ddi_ptob(rdip, 1) - 1; 42130Sstevel@tonic-gate /* 42140Sstevel@tonic-gate * Take a copy and set this to be hp->addr 42150Sstevel@tonic-gate * Data will be copied to and from the original on 42160Sstevel@tonic-gate * explicit and implicit ddi_dma_sync() 42170Sstevel@tonic-gate * 42180Sstevel@tonic-gate * - maintain page alignment because some devices 42190Sstevel@tonic-gate * assume it. 42200Sstevel@tonic-gate */ 42210Sstevel@tonic-gate hp->allocaddr = ddi_umem_alloc( 4222968Smike_s ((int)(uintptr_t)hp->addr & pagemask) 42235204Sstephh + pagemask + 1, 42240Sstevel@tonic-gate KM_SLEEP, &hp->umem_cookie); 4225968Smike_s hp->addr = hp->allocaddr + 4226968Smike_s ((int)(uintptr_t)hp->addr & pagemask); 42270Sstevel@tonic-gate } 42280Sstevel@tonic-gate /* 42290Sstevel@tonic-gate * add to dhash and inuse lists. 42300Sstevel@tonic-gate * these don't go on hhash queue. 42310Sstevel@tonic-gate */ 42320Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 42330Sstevel@tonic-gate mutex_enter(&bofi_mutex); 42340Sstevel@tonic-gate hp->next = shadow_list.next; 42350Sstevel@tonic-gate shadow_list.next->prev = hp; 42360Sstevel@tonic-gate hp->prev = &shadow_list; 42370Sstevel@tonic-gate shadow_list.next = hp; 42380Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 42390Sstevel@tonic-gate hp->dnext = dhashp->dnext; 42400Sstevel@tonic-gate dhashp->dnext->dprev = hp; 42410Sstevel@tonic-gate hp->dprev = dhashp; 42420Sstevel@tonic-gate dhashp->dnext = hp; 42430Sstevel@tonic-gate dummyhp->hparrayp[i] = hp; 42440Sstevel@tonic-gate mutex_exit(&bofi_mutex); 42450Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 42460Sstevel@tonic-gate } 42470Sstevel@tonic-gate /* 42480Sstevel@tonic-gate * add dummy handle to hhash list only 42490Sstevel@tonic-gate */ 42500Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 42510Sstevel@tonic-gate mutex_enter(&bofi_mutex); 42520Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 42530Sstevel@tonic-gate dummyhp->hnext = hhashp->hnext; 42540Sstevel@tonic-gate hhashp->hnext->hprev = dummyhp; 42550Sstevel@tonic-gate dummyhp->hprev = hhashp; 42560Sstevel@tonic-gate hhashp->hnext = dummyhp; 42570Sstevel@tonic-gate mutex_exit(&bofi_mutex); 42580Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 42590Sstevel@tonic-gate } 42600Sstevel@tonic-gate 42610Sstevel@tonic-gate /* 42620Sstevel@tonic-gate * our dvma_kaddr_load() 42630Sstevel@tonic-gate */ 42640Sstevel@tonic-gate static void 42650Sstevel@tonic-gate bofi_dvma_kaddr_load(ddi_dma_handle_t h, caddr_t a, uint_t len, uint_t index, 42660Sstevel@tonic-gate ddi_dma_cookie_t *cp) 42670Sstevel@tonic-gate { 42680Sstevel@tonic-gate struct bofi_shadow *dummyhp; 42690Sstevel@tonic-gate struct bofi_shadow *hp; 42700Sstevel@tonic-gate struct bofi_shadow *hhashp; 42710Sstevel@tonic-gate struct bofi_errent *ep; 42720Sstevel@tonic-gate struct bofi_link *lp; 42730Sstevel@tonic-gate 42740Sstevel@tonic-gate /* 42750Sstevel@tonic-gate * check we really have a dummy shadow for this handle 42760Sstevel@tonic-gate */ 42770Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 42780Sstevel@tonic-gate mutex_enter(&bofi_mutex); 42790Sstevel@tonic-gate hhashp = HDL_HHASH(h); 42800Sstevel@tonic-gate for (dummyhp = hhashp->hnext; dummyhp != hhashp; 42810Sstevel@tonic-gate dummyhp = dummyhp->hnext) 42820Sstevel@tonic-gate if (dummyhp->hdl.dma_handle == h) 42830Sstevel@tonic-gate break; 42840Sstevel@tonic-gate mutex_exit(&bofi_mutex); 42850Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 42860Sstevel@tonic-gate if (dummyhp == hhashp) { 42870Sstevel@tonic-gate /* 42880Sstevel@tonic-gate * no dummy shadow - panic 42890Sstevel@tonic-gate */ 42900Sstevel@tonic-gate panic("driver dvma_kaddr_load with no reserve"); 42910Sstevel@tonic-gate } 42920Sstevel@tonic-gate 42930Sstevel@tonic-gate /* 42940Sstevel@tonic-gate * find real hp 42950Sstevel@tonic-gate */ 42960Sstevel@tonic-gate hp = dummyhp->hparrayp[index]; 42970Sstevel@tonic-gate /* 42980Sstevel@tonic-gate * check its not already loaded 42990Sstevel@tonic-gate */ 43000Sstevel@tonic-gate if (hp->type != BOFI_NULL) 43010Sstevel@tonic-gate panic("driver loading loaded dvma"); 43020Sstevel@tonic-gate /* 43030Sstevel@tonic-gate * if were doing copying, just need to change origaddr and get 43040Sstevel@tonic-gate * nexus to map hp->addr again 43050Sstevel@tonic-gate * if not, set hp->addr to new address. 43060Sstevel@tonic-gate * - note these are always kernel virtual addresses - no need to map 43070Sstevel@tonic-gate */ 43080Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) { 43090Sstevel@tonic-gate hp->origaddr = a; 43100Sstevel@tonic-gate a = hp->addr; 43110Sstevel@tonic-gate } else 43120Sstevel@tonic-gate hp->addr = a; 43130Sstevel@tonic-gate hp->len = len; 43140Sstevel@tonic-gate /* 43150Sstevel@tonic-gate * get nexus to do the real work 43160Sstevel@tonic-gate */ 43170Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_kaddr_load(h, a, len, index, cp); 43180Sstevel@tonic-gate /* 43190Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this dma_handle 43200Sstevel@tonic-gate * no need to corrupt - there's no implicit dma_sync on this one 43210Sstevel@tonic-gate */ 43220Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 43230Sstevel@tonic-gate mutex_enter(&bofi_mutex); 43240Sstevel@tonic-gate hp->type = BOFI_DMA_HDL; 43250Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 43260Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 43270Sstevel@tonic-gate ddi_name_to_major(ep->name) && 43280Sstevel@tonic-gate hp->instance == ep->errdef.instance && 43290Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 43300Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 43310Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_RW) && 43320Sstevel@tonic-gate (((uintptr_t)(hp->addr + ep->errdef.offset + 43330Sstevel@tonic-gate ep->errdef.len) & ~LLSZMASK) > 43340Sstevel@tonic-gate ((uintptr_t)((hp->addr + ep->errdef.offset) + 43350Sstevel@tonic-gate LLSZMASK) & ~LLSZMASK)))) { 43360Sstevel@tonic-gate lp = bofi_link_freelist; 43370Sstevel@tonic-gate if (lp != NULL) { 43380Sstevel@tonic-gate bofi_link_freelist = lp->link; 43390Sstevel@tonic-gate lp->errentp = ep; 43400Sstevel@tonic-gate lp->link = hp->link; 43410Sstevel@tonic-gate hp->link = lp; 43420Sstevel@tonic-gate } 43430Sstevel@tonic-gate } 43440Sstevel@tonic-gate } 43450Sstevel@tonic-gate mutex_exit(&bofi_mutex); 43460Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 43470Sstevel@tonic-gate } 43480Sstevel@tonic-gate 43490Sstevel@tonic-gate /* 43500Sstevel@tonic-gate * our dvma_unload() 43510Sstevel@tonic-gate */ 43520Sstevel@tonic-gate static void 43530Sstevel@tonic-gate bofi_dvma_unload(ddi_dma_handle_t h, uint_t index, uint_t view) 43540Sstevel@tonic-gate { 43550Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 43560Sstevel@tonic-gate struct bofi_errent *ep; 43570Sstevel@tonic-gate struct bofi_shadow *dummyhp; 43580Sstevel@tonic-gate struct bofi_shadow *hp; 43590Sstevel@tonic-gate struct bofi_shadow *hhashp; 43600Sstevel@tonic-gate 43610Sstevel@tonic-gate /* 43620Sstevel@tonic-gate * check we really have a dummy shadow for this handle 43630Sstevel@tonic-gate */ 43640Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 43650Sstevel@tonic-gate mutex_enter(&bofi_mutex); 43660Sstevel@tonic-gate hhashp = HDL_HHASH(h); 43670Sstevel@tonic-gate for (dummyhp = hhashp->hnext; dummyhp != hhashp; 43680Sstevel@tonic-gate dummyhp = dummyhp->hnext) 43690Sstevel@tonic-gate if (dummyhp->hdl.dma_handle == h) 43700Sstevel@tonic-gate break; 43710Sstevel@tonic-gate mutex_exit(&bofi_mutex); 43720Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 43730Sstevel@tonic-gate if (dummyhp == hhashp) { 43740Sstevel@tonic-gate /* 43750Sstevel@tonic-gate * no dummy shadow - panic 43760Sstevel@tonic-gate */ 43770Sstevel@tonic-gate panic("driver dvma_unload with no reserve"); 43780Sstevel@tonic-gate } 43790Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_unload(h, index, view); 43800Sstevel@tonic-gate /* 43810Sstevel@tonic-gate * find real hp 43820Sstevel@tonic-gate */ 43830Sstevel@tonic-gate hp = dummyhp->hparrayp[index]; 43840Sstevel@tonic-gate /* 43850Sstevel@tonic-gate * check its not already unloaded 43860Sstevel@tonic-gate */ 43870Sstevel@tonic-gate if (hp->type == BOFI_NULL) 43880Sstevel@tonic-gate panic("driver unloading unloaded dvma"); 43890Sstevel@tonic-gate /* 43900Sstevel@tonic-gate * free any errdef link structures tagged on to this 43910Sstevel@tonic-gate * shadow handle - do corruption if necessary 43920Sstevel@tonic-gate */ 43930Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 43940Sstevel@tonic-gate mutex_enter(&bofi_mutex); 43950Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 43960Sstevel@tonic-gate next_lp = lp->link; 43970Sstevel@tonic-gate ep = lp->errentp; 43980Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_R) && 43990Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || 44000Sstevel@tonic-gate view == DDI_DMA_SYNC_FORKERNEL) && 44010Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 44020Sstevel@tonic-gate do_dma_corrupt(hp, ep, view, 0, hp->len); 44030Sstevel@tonic-gate } 44040Sstevel@tonic-gate lp->link = bofi_link_freelist; 44050Sstevel@tonic-gate bofi_link_freelist = lp; 44060Sstevel@tonic-gate lp = next_lp; 44070Sstevel@tonic-gate } 44080Sstevel@tonic-gate hp->link = NULL; 44090Sstevel@tonic-gate hp->type = BOFI_NULL; 44100Sstevel@tonic-gate mutex_exit(&bofi_mutex); 44110Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 44120Sstevel@tonic-gate /* 44130Sstevel@tonic-gate * if there is an explicit sync_for_cpu, then do copy to original 44140Sstevel@tonic-gate */ 44150Sstevel@tonic-gate if (bofi_sync_check && 44160Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL)) 44170Sstevel@tonic-gate if (hp->allocaddr) 44180Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 44190Sstevel@tonic-gate } 44200Sstevel@tonic-gate 44210Sstevel@tonic-gate /* 44220Sstevel@tonic-gate * our dvma_unload() 44230Sstevel@tonic-gate */ 44240Sstevel@tonic-gate static void 44250Sstevel@tonic-gate bofi_dvma_sync(ddi_dma_handle_t h, uint_t index, uint_t view) 44260Sstevel@tonic-gate { 44270Sstevel@tonic-gate struct bofi_link *lp; 44280Sstevel@tonic-gate struct bofi_errent *ep; 44290Sstevel@tonic-gate struct bofi_shadow *hp; 44300Sstevel@tonic-gate struct bofi_shadow *dummyhp; 44310Sstevel@tonic-gate struct bofi_shadow *hhashp; 44320Sstevel@tonic-gate 44330Sstevel@tonic-gate /* 44340Sstevel@tonic-gate * check we really have a dummy shadow for this handle 44350Sstevel@tonic-gate */ 44360Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 44370Sstevel@tonic-gate mutex_enter(&bofi_mutex); 44380Sstevel@tonic-gate hhashp = HDL_HHASH(h); 44390Sstevel@tonic-gate for (dummyhp = hhashp->hnext; dummyhp != hhashp; 44400Sstevel@tonic-gate dummyhp = dummyhp->hnext) 44410Sstevel@tonic-gate if (dummyhp->hdl.dma_handle == h) 44420Sstevel@tonic-gate break; 44430Sstevel@tonic-gate mutex_exit(&bofi_mutex); 44440Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 44450Sstevel@tonic-gate if (dummyhp == hhashp) { 44460Sstevel@tonic-gate /* 44470Sstevel@tonic-gate * no dummy shadow - panic 44480Sstevel@tonic-gate */ 44490Sstevel@tonic-gate panic("driver dvma_sync with no reserve"); 44500Sstevel@tonic-gate } 44510Sstevel@tonic-gate /* 44520Sstevel@tonic-gate * find real hp 44530Sstevel@tonic-gate */ 44540Sstevel@tonic-gate hp = dummyhp->hparrayp[index]; 44550Sstevel@tonic-gate /* 44560Sstevel@tonic-gate * check its already loaded 44570Sstevel@tonic-gate */ 44580Sstevel@tonic-gate if (hp->type == BOFI_NULL) 44590Sstevel@tonic-gate panic("driver syncing unloaded dvma"); 44600Sstevel@tonic-gate if (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL) 44610Sstevel@tonic-gate /* 44620Sstevel@tonic-gate * in this case do sync first 44630Sstevel@tonic-gate */ 44640Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_sync(h, index, view); 44650Sstevel@tonic-gate /* 44660Sstevel@tonic-gate * if there is an explicit sync_for_dev, then do copy from original 44670Sstevel@tonic-gate */ 44680Sstevel@tonic-gate if (bofi_sync_check && view == DDI_DMA_SYNC_FORDEV) { 44690Sstevel@tonic-gate if (hp->allocaddr) 44700Sstevel@tonic-gate xbcopy(hp->origaddr, hp->addr, hp->len); 44710Sstevel@tonic-gate } 44720Sstevel@tonic-gate /* 44730Sstevel@tonic-gate * do corruption if necessary 44740Sstevel@tonic-gate */ 44750Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 44760Sstevel@tonic-gate mutex_enter(&bofi_mutex); 44770Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 44780Sstevel@tonic-gate ep = lp->errentp; 44790Sstevel@tonic-gate if ((((ep->errdef.access_type & BOFI_DMA_R) && 44800Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || 44810Sstevel@tonic-gate view == DDI_DMA_SYNC_FORKERNEL)) || 44820Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_W) && 44830Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORDEV))) && 44840Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 44850Sstevel@tonic-gate do_dma_corrupt(hp, ep, view, 0, hp->len); 44860Sstevel@tonic-gate } 44870Sstevel@tonic-gate } 44880Sstevel@tonic-gate mutex_exit(&bofi_mutex); 44890Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 44900Sstevel@tonic-gate /* 44910Sstevel@tonic-gate * if there is an explicit sync_for_cpu, then do copy to original 44920Sstevel@tonic-gate */ 44930Sstevel@tonic-gate if (bofi_sync_check && 44940Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL)) { 44950Sstevel@tonic-gate if (hp->allocaddr) 44960Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 44970Sstevel@tonic-gate } 44980Sstevel@tonic-gate if (view == DDI_DMA_SYNC_FORDEV) 44990Sstevel@tonic-gate /* 45000Sstevel@tonic-gate * in this case do sync last 45010Sstevel@tonic-gate */ 45020Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_sync(h, index, view); 45030Sstevel@tonic-gate } 45040Sstevel@tonic-gate #endif 45050Sstevel@tonic-gate 45060Sstevel@tonic-gate /* 45070Sstevel@tonic-gate * bofi intercept routine - gets called instead of users interrupt routine 45080Sstevel@tonic-gate */ 45090Sstevel@tonic-gate static uint_t 45100Sstevel@tonic-gate bofi_intercept_intr(caddr_t xp) 45110Sstevel@tonic-gate { 45120Sstevel@tonic-gate struct bofi_errent *ep; 45130Sstevel@tonic-gate struct bofi_link *lp; 45140Sstevel@tonic-gate struct bofi_shadow *hp; 45150Sstevel@tonic-gate int intr_count = 1; 45160Sstevel@tonic-gate int i; 45170Sstevel@tonic-gate uint_t retval = DDI_INTR_UNCLAIMED; 45180Sstevel@tonic-gate uint_t result; 45190Sstevel@tonic-gate int unclaimed_counter = 0; 45200Sstevel@tonic-gate int jabber_detected = 0; 45210Sstevel@tonic-gate 45220Sstevel@tonic-gate hp = (struct bofi_shadow *)xp; 45230Sstevel@tonic-gate /* 45240Sstevel@tonic-gate * check if nothing to do 45250Sstevel@tonic-gate */ 45260Sstevel@tonic-gate if (hp->link == NULL) 45270Sstevel@tonic-gate return (hp->save.intr.int_handler 45280Sstevel@tonic-gate (hp->save.intr.int_handler_arg1, NULL)); 45290Sstevel@tonic-gate mutex_enter(&bofi_mutex); 45300Sstevel@tonic-gate /* 45310Sstevel@tonic-gate * look for any errdefs 45320Sstevel@tonic-gate */ 45330Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 45340Sstevel@tonic-gate ep = lp->errentp; 45350Sstevel@tonic-gate if (ep->state & BOFI_DEV_ACTIVE) { 45360Sstevel@tonic-gate /* 45370Sstevel@tonic-gate * got one 45380Sstevel@tonic-gate */ 45390Sstevel@tonic-gate if ((ep->errdef.access_count || 45400Sstevel@tonic-gate ep->errdef.fail_count) && 45410Sstevel@tonic-gate (ep->errdef.access_type & BOFI_LOG)) 45420Sstevel@tonic-gate log_acc_event(ep, BOFI_INTR, 0, 0, 1, 0); 45430Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 45440Sstevel@tonic-gate ep->errdef.access_count--; 45450Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 45460Sstevel@tonic-gate ep->errdef.fail_count--; 45470Sstevel@tonic-gate ep->errdef.access_count = 0; 45480Sstevel@tonic-gate /* 45490Sstevel@tonic-gate * OK do "corruption" 45500Sstevel@tonic-gate */ 45510Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 45520Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 45530Sstevel@tonic-gate switch (ep->errdef.optype) { 45540Sstevel@tonic-gate case BOFI_DELAY_INTR: 45550Sstevel@tonic-gate if (!hp->hilevel) { 45560Sstevel@tonic-gate drv_usecwait 45570Sstevel@tonic-gate (ep->errdef.operand); 45580Sstevel@tonic-gate } 45590Sstevel@tonic-gate break; 45600Sstevel@tonic-gate case BOFI_LOSE_INTR: 45610Sstevel@tonic-gate intr_count = 0; 45620Sstevel@tonic-gate break; 45630Sstevel@tonic-gate case BOFI_EXTRA_INTR: 45640Sstevel@tonic-gate intr_count += ep->errdef.operand; 45650Sstevel@tonic-gate break; 45660Sstevel@tonic-gate default: 45670Sstevel@tonic-gate break; 45680Sstevel@tonic-gate } 45690Sstevel@tonic-gate } 45700Sstevel@tonic-gate } 45710Sstevel@tonic-gate } 45720Sstevel@tonic-gate mutex_exit(&bofi_mutex); 45730Sstevel@tonic-gate /* 45740Sstevel@tonic-gate * send extra or fewer interrupts as requested 45750Sstevel@tonic-gate */ 45760Sstevel@tonic-gate for (i = 0; i < intr_count; i++) { 45770Sstevel@tonic-gate result = hp->save.intr.int_handler 45780Sstevel@tonic-gate (hp->save.intr.int_handler_arg1, NULL); 45790Sstevel@tonic-gate if (result == DDI_INTR_CLAIMED) 45800Sstevel@tonic-gate unclaimed_counter >>= 1; 45810Sstevel@tonic-gate else if (++unclaimed_counter >= 20) 45820Sstevel@tonic-gate jabber_detected = 1; 45830Sstevel@tonic-gate if (i == 0) 45840Sstevel@tonic-gate retval = result; 45850Sstevel@tonic-gate } 45860Sstevel@tonic-gate /* 45870Sstevel@tonic-gate * if more than 1000 spurious interrupts requested and 45880Sstevel@tonic-gate * jabber not detected - give warning 45890Sstevel@tonic-gate */ 45900Sstevel@tonic-gate if (intr_count > 1000 && !jabber_detected) 45910Sstevel@tonic-gate panic("undetected interrupt jabber: %s%d", 45920Sstevel@tonic-gate hp->name, hp->instance); 45930Sstevel@tonic-gate /* 45940Sstevel@tonic-gate * return first response - or "unclaimed" if none 45950Sstevel@tonic-gate */ 45960Sstevel@tonic-gate return (retval); 45970Sstevel@tonic-gate } 45980Sstevel@tonic-gate 45990Sstevel@tonic-gate 46000Sstevel@tonic-gate /* 46010Sstevel@tonic-gate * our ddi_check_acc_hdl 46020Sstevel@tonic-gate */ 46030Sstevel@tonic-gate /* ARGSUSED */ 46040Sstevel@tonic-gate static int 46050Sstevel@tonic-gate bofi_check_acc_hdl(ddi_acc_impl_t *handle) 46060Sstevel@tonic-gate { 46070Sstevel@tonic-gate struct bofi_shadow *hp; 46080Sstevel@tonic-gate struct bofi_link *lp; 46090Sstevel@tonic-gate uint_t result = 0; 46100Sstevel@tonic-gate 46110Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 46120Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 46130Sstevel@tonic-gate return (0); 46140Sstevel@tonic-gate } 46150Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 46160Sstevel@tonic-gate /* 46170Sstevel@tonic-gate * OR in error state from all associated 46180Sstevel@tonic-gate * errdef structures 46190Sstevel@tonic-gate */ 46200Sstevel@tonic-gate if (lp->errentp->errdef.access_count == 0 && 46210Sstevel@tonic-gate (lp->errentp->state & BOFI_DEV_ACTIVE)) { 46220Sstevel@tonic-gate result = (lp->errentp->errdef.acc_chk & 1); 46230Sstevel@tonic-gate } 46240Sstevel@tonic-gate } 46250Sstevel@tonic-gate mutex_exit(&bofi_mutex); 46260Sstevel@tonic-gate return (result); 46270Sstevel@tonic-gate } 46280Sstevel@tonic-gate 46290Sstevel@tonic-gate /* 46300Sstevel@tonic-gate * our ddi_check_dma_hdl 46310Sstevel@tonic-gate */ 46320Sstevel@tonic-gate /* ARGSUSED */ 46330Sstevel@tonic-gate static int 46340Sstevel@tonic-gate bofi_check_dma_hdl(ddi_dma_impl_t *handle) 46350Sstevel@tonic-gate { 46360Sstevel@tonic-gate struct bofi_shadow *hp; 46370Sstevel@tonic-gate struct bofi_link *lp; 46380Sstevel@tonic-gate struct bofi_shadow *hhashp; 46390Sstevel@tonic-gate uint_t result = 0; 46400Sstevel@tonic-gate 46410Sstevel@tonic-gate if (!mutex_tryenter(&bofi_mutex)) { 46420Sstevel@tonic-gate return (0); 46430Sstevel@tonic-gate } 46440Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 46450Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 46460Sstevel@tonic-gate if (hp->hdl.dma_handle == (ddi_dma_handle_t)handle) 46470Sstevel@tonic-gate break; 46480Sstevel@tonic-gate if (hp == hhashp) { 46490Sstevel@tonic-gate mutex_exit(&bofi_mutex); 46500Sstevel@tonic-gate return (0); 46510Sstevel@tonic-gate } 46520Sstevel@tonic-gate if (!hp->link) { 46530Sstevel@tonic-gate mutex_exit(&bofi_mutex); 46540Sstevel@tonic-gate return (0); 46550Sstevel@tonic-gate } 46560Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 46570Sstevel@tonic-gate /* 46580Sstevel@tonic-gate * OR in error state from all associated 46590Sstevel@tonic-gate * errdef structures 46600Sstevel@tonic-gate */ 46610Sstevel@tonic-gate if (lp->errentp->errdef.access_count == 0 && 46620Sstevel@tonic-gate (lp->errentp->state & BOFI_DEV_ACTIVE)) { 46630Sstevel@tonic-gate result = ((lp->errentp->errdef.acc_chk & 2) ? 1 : 0); 46640Sstevel@tonic-gate } 46650Sstevel@tonic-gate } 46660Sstevel@tonic-gate mutex_exit(&bofi_mutex); 46670Sstevel@tonic-gate return (result); 46680Sstevel@tonic-gate } 46690Sstevel@tonic-gate 46700Sstevel@tonic-gate 46710Sstevel@tonic-gate /* ARGSUSED */ 46720Sstevel@tonic-gate static int 46730Sstevel@tonic-gate bofi_post_event(dev_info_t *dip, dev_info_t *rdip, 46740Sstevel@tonic-gate ddi_eventcookie_t eventhdl, void *impl_data) 46750Sstevel@tonic-gate { 46760Sstevel@tonic-gate ddi_eventcookie_t ec; 46770Sstevel@tonic-gate struct ddi_fault_event_data *arg; 46780Sstevel@tonic-gate struct bofi_errent *ep; 46790Sstevel@tonic-gate struct bofi_shadow *hp; 46800Sstevel@tonic-gate struct bofi_shadow *dhashp; 46810Sstevel@tonic-gate struct bofi_link *lp; 46820Sstevel@tonic-gate 46830Sstevel@tonic-gate ASSERT(eventhdl); 46840Sstevel@tonic-gate if (ddi_get_eventcookie(dip, DDI_DEVI_FAULT_EVENT, &ec) != DDI_SUCCESS) 46850Sstevel@tonic-gate return (DDI_FAILURE); 46860Sstevel@tonic-gate 46870Sstevel@tonic-gate if (ec != eventhdl) 46880Sstevel@tonic-gate return (save_bus_ops.bus_post_event(dip, rdip, eventhdl, 46890Sstevel@tonic-gate impl_data)); 46900Sstevel@tonic-gate 46910Sstevel@tonic-gate arg = (struct ddi_fault_event_data *)impl_data; 46920Sstevel@tonic-gate mutex_enter(&bofi_mutex); 46930Sstevel@tonic-gate /* 46940Sstevel@tonic-gate * find shadow handles with appropriate dev_infos 46950Sstevel@tonic-gate * and set error reported on all associated errdef structures 46960Sstevel@tonic-gate */ 46970Sstevel@tonic-gate dhashp = HDL_DHASH(arg->f_dip); 46980Sstevel@tonic-gate for (hp = dhashp->dnext; hp != dhashp; hp = hp->dnext) { 46990Sstevel@tonic-gate if (hp->dip == arg->f_dip) { 47000Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 47010Sstevel@tonic-gate ep = lp->errentp; 47020Sstevel@tonic-gate ep->errstate.errmsg_count++; 47030Sstevel@tonic-gate if ((ep->errstate.msg_time == NULL || 47040Sstevel@tonic-gate ep->errstate.severity > arg->f_impact) && 47050Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 47060Sstevel@tonic-gate ep->errstate.msg_time = bofi_gettime(); 47070Sstevel@tonic-gate ep->errstate.severity = arg->f_impact; 47080Sstevel@tonic-gate (void) strncpy(ep->errstate.buffer, 47090Sstevel@tonic-gate arg->f_message, ERRMSGSIZE); 47100Sstevel@tonic-gate ddi_trigger_softintr(ep->softintr_id); 47110Sstevel@tonic-gate } 47120Sstevel@tonic-gate } 47130Sstevel@tonic-gate } 47140Sstevel@tonic-gate } 47150Sstevel@tonic-gate mutex_exit(&bofi_mutex); 47160Sstevel@tonic-gate return (save_bus_ops.bus_post_event(dip, rdip, eventhdl, impl_data)); 47170Sstevel@tonic-gate } 47180Sstevel@tonic-gate 47191865Sdilpreet /*ARGSUSED*/ 47201865Sdilpreet static int 47211865Sdilpreet bofi_fm_ereport_callback(sysevent_t *ev, void *cookie) 47221865Sdilpreet { 47231865Sdilpreet char *class = ""; 47241865Sdilpreet char *path = ""; 47251865Sdilpreet char *ptr; 47261865Sdilpreet nvlist_t *nvlist; 47271865Sdilpreet nvlist_t *detector; 47281865Sdilpreet ddi_fault_impact_t impact; 47291865Sdilpreet struct bofi_errent *ep; 47301865Sdilpreet struct bofi_shadow *hp; 47311865Sdilpreet struct bofi_link *lp; 47321865Sdilpreet char service_class[FM_MAX_CLASS]; 47331865Sdilpreet char hppath[MAXPATHLEN]; 47341865Sdilpreet int service_ereport = 0; 47351865Sdilpreet 47361865Sdilpreet (void) sysevent_get_attr_list(ev, &nvlist); 47371865Sdilpreet (void) nvlist_lookup_string(nvlist, FM_CLASS, &class); 47381865Sdilpreet if (nvlist_lookup_nvlist(nvlist, FM_EREPORT_DETECTOR, &detector) == 0) 47391865Sdilpreet (void) nvlist_lookup_string(detector, FM_FMRI_DEV_PATH, &path); 47401865Sdilpreet 47411865Sdilpreet (void) snprintf(service_class, FM_MAX_CLASS, "%s.%s.%s.", 47421865Sdilpreet FM_EREPORT_CLASS, DDI_IO_CLASS, DDI_FM_SERVICE_IMPACT); 47431865Sdilpreet if (strncmp(class, service_class, strlen(service_class) - 1) == 0) 47441865Sdilpreet service_ereport = 1; 47451865Sdilpreet 47461865Sdilpreet mutex_enter(&bofi_mutex); 47471865Sdilpreet /* 47481865Sdilpreet * find shadow handles with appropriate dev_infos 47491865Sdilpreet * and set error reported on all associated errdef structures 47501865Sdilpreet */ 47511865Sdilpreet for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) { 47521865Sdilpreet (void) ddi_pathname(hp->dip, hppath); 47531865Sdilpreet if (strcmp(path, hppath) != 0) 47541865Sdilpreet continue; 47551865Sdilpreet for (lp = hp->link; lp != NULL; lp = lp->link) { 47561865Sdilpreet ep = lp->errentp; 47571865Sdilpreet ep->errstate.errmsg_count++; 47581865Sdilpreet if (!(ep->state & BOFI_DEV_ACTIVE)) 47591865Sdilpreet continue; 47601865Sdilpreet if (ep->errstate.msg_time != NULL) 47611865Sdilpreet continue; 47621865Sdilpreet if (service_ereport) { 47631865Sdilpreet ptr = class + strlen(service_class); 47641865Sdilpreet if (strcmp(ptr, DDI_FM_SERVICE_LOST) == 0) 47651865Sdilpreet impact = DDI_SERVICE_LOST; 47661865Sdilpreet else if (strcmp(ptr, 47671865Sdilpreet DDI_FM_SERVICE_DEGRADED) == 0) 47681865Sdilpreet impact = DDI_SERVICE_DEGRADED; 47691865Sdilpreet else if (strcmp(ptr, 47701865Sdilpreet DDI_FM_SERVICE_RESTORED) == 0) 47711865Sdilpreet impact = DDI_SERVICE_RESTORED; 47721865Sdilpreet else 47731865Sdilpreet impact = DDI_SERVICE_UNAFFECTED; 47741865Sdilpreet if (ep->errstate.severity > impact) 47751865Sdilpreet ep->errstate.severity = impact; 47761865Sdilpreet } else if (ep->errstate.buffer[0] == '\0') { 47771865Sdilpreet (void) strncpy(ep->errstate.buffer, class, 47781865Sdilpreet ERRMSGSIZE); 47791865Sdilpreet } 47801865Sdilpreet if (ep->errstate.buffer[0] != '\0' && 47811865Sdilpreet ep->errstate.severity < DDI_SERVICE_RESTORED) { 47821865Sdilpreet ep->errstate.msg_time = bofi_gettime(); 47831865Sdilpreet ddi_trigger_softintr(ep->softintr_id); 47841865Sdilpreet } 47851865Sdilpreet } 47861865Sdilpreet } 47871865Sdilpreet nvlist_free(nvlist); 47881865Sdilpreet mutex_exit(&bofi_mutex); 47891865Sdilpreet return (0); 47901865Sdilpreet } 47911865Sdilpreet 47920Sstevel@tonic-gate /* 47930Sstevel@tonic-gate * our intr_ops routine 47940Sstevel@tonic-gate */ 47950Sstevel@tonic-gate static int 47960Sstevel@tonic-gate bofi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 47970Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 47980Sstevel@tonic-gate { 47990Sstevel@tonic-gate int retval; 48000Sstevel@tonic-gate struct bofi_shadow *hp; 48010Sstevel@tonic-gate struct bofi_shadow *dhashp; 48020Sstevel@tonic-gate struct bofi_shadow *hhashp; 48030Sstevel@tonic-gate struct bofi_errent *ep; 48040Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 48050Sstevel@tonic-gate 48060Sstevel@tonic-gate switch (intr_op) { 48070Sstevel@tonic-gate case DDI_INTROP_ADDISR: 48080Sstevel@tonic-gate /* 48090Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 48100Sstevel@tonic-gate */ 48110Sstevel@tonic-gate if (!driver_under_test(rdip)) 48120Sstevel@tonic-gate return (save_bus_ops.bus_intr_op(dip, rdip, 48130Sstevel@tonic-gate intr_op, hdlp, result)); 48140Sstevel@tonic-gate /* 48150Sstevel@tonic-gate * allocate shadow handle structure and fill in 48160Sstevel@tonic-gate */ 48170Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), KM_SLEEP); 48180Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 48190Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 48200Sstevel@tonic-gate hp->save.intr.int_handler = hdlp->ih_cb_func; 48210Sstevel@tonic-gate hp->save.intr.int_handler_arg1 = hdlp->ih_cb_arg1; 48220Sstevel@tonic-gate hdlp->ih_cb_func = (ddi_intr_handler_t *)bofi_intercept_intr; 48230Sstevel@tonic-gate hdlp->ih_cb_arg1 = (caddr_t)hp; 48240Sstevel@tonic-gate hp->bofi_inum = hdlp->ih_inum; 48250Sstevel@tonic-gate hp->dip = rdip; 48260Sstevel@tonic-gate hp->link = NULL; 48270Sstevel@tonic-gate hp->type = BOFI_INT_HDL; 48280Sstevel@tonic-gate /* 48290Sstevel@tonic-gate * save whether hilevel or not 48300Sstevel@tonic-gate */ 48310Sstevel@tonic-gate 48320Sstevel@tonic-gate if (hdlp->ih_pri >= ddi_intr_get_hilevel_pri()) 48330Sstevel@tonic-gate hp->hilevel = 1; 48340Sstevel@tonic-gate else 48350Sstevel@tonic-gate hp->hilevel = 0; 48360Sstevel@tonic-gate 48370Sstevel@tonic-gate /* 48380Sstevel@tonic-gate * call nexus to do real work, but specifying our handler, and 48390Sstevel@tonic-gate * our shadow handle as argument 48400Sstevel@tonic-gate */ 48410Sstevel@tonic-gate retval = save_bus_ops.bus_intr_op(dip, rdip, 48420Sstevel@tonic-gate intr_op, hdlp, result); 48430Sstevel@tonic-gate if (retval != DDI_SUCCESS) { 48440Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 48450Sstevel@tonic-gate return (retval); 48460Sstevel@tonic-gate } 48470Sstevel@tonic-gate /* 48480Sstevel@tonic-gate * add to dhash, hhash and inuse lists 48490Sstevel@tonic-gate */ 48500Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 48510Sstevel@tonic-gate mutex_enter(&bofi_mutex); 48520Sstevel@tonic-gate hp->next = shadow_list.next; 48530Sstevel@tonic-gate shadow_list.next->prev = hp; 48540Sstevel@tonic-gate hp->prev = &shadow_list; 48550Sstevel@tonic-gate shadow_list.next = hp; 48560Sstevel@tonic-gate hhashp = HDL_HHASH(hdlp->ih_inum); 48570Sstevel@tonic-gate hp->hnext = hhashp->hnext; 48580Sstevel@tonic-gate hhashp->hnext->hprev = hp; 48590Sstevel@tonic-gate hp->hprev = hhashp; 48600Sstevel@tonic-gate hhashp->hnext = hp; 48610Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 48620Sstevel@tonic-gate hp->dnext = dhashp->dnext; 48630Sstevel@tonic-gate dhashp->dnext->dprev = hp; 48640Sstevel@tonic-gate hp->dprev = dhashp; 48650Sstevel@tonic-gate dhashp->dnext = hp; 48660Sstevel@tonic-gate /* 48670Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 48680Sstevel@tonic-gate * acc_handle 48690Sstevel@tonic-gate */ 48700Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 48710Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 48720Sstevel@tonic-gate ddi_name_to_major(ep->name) && 48730Sstevel@tonic-gate hp->instance == ep->errdef.instance && 48740Sstevel@tonic-gate (ep->errdef.access_type & BOFI_INTR)) { 48750Sstevel@tonic-gate lp = bofi_link_freelist; 48760Sstevel@tonic-gate if (lp != NULL) { 48770Sstevel@tonic-gate bofi_link_freelist = lp->link; 48780Sstevel@tonic-gate lp->errentp = ep; 48790Sstevel@tonic-gate lp->link = hp->link; 48800Sstevel@tonic-gate hp->link = lp; 48810Sstevel@tonic-gate } 48820Sstevel@tonic-gate } 48830Sstevel@tonic-gate } 48840Sstevel@tonic-gate mutex_exit(&bofi_mutex); 48850Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 48860Sstevel@tonic-gate return (retval); 48870Sstevel@tonic-gate case DDI_INTROP_REMISR: 48880Sstevel@tonic-gate /* 48890Sstevel@tonic-gate * call nexus routine first 48900Sstevel@tonic-gate */ 48910Sstevel@tonic-gate retval = save_bus_ops.bus_intr_op(dip, rdip, 48920Sstevel@tonic-gate intr_op, hdlp, result); 48930Sstevel@tonic-gate /* 48940Sstevel@tonic-gate * find shadow handle 48950Sstevel@tonic-gate */ 48960Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 48970Sstevel@tonic-gate mutex_enter(&bofi_mutex); 48980Sstevel@tonic-gate hhashp = HDL_HHASH(hdlp->ih_inum); 48990Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) { 49000Sstevel@tonic-gate if (hp->dip == rdip && 49010Sstevel@tonic-gate hp->type == BOFI_INT_HDL && 49020Sstevel@tonic-gate hp->bofi_inum == hdlp->ih_inum) { 49030Sstevel@tonic-gate break; 49040Sstevel@tonic-gate } 49050Sstevel@tonic-gate } 49060Sstevel@tonic-gate if (hp == hhashp) { 49070Sstevel@tonic-gate mutex_exit(&bofi_mutex); 49080Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 49090Sstevel@tonic-gate return (retval); 49100Sstevel@tonic-gate } 49110Sstevel@tonic-gate /* 49120Sstevel@tonic-gate * found one - remove from dhash, hhash and inuse lists 49130Sstevel@tonic-gate */ 49140Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 49150Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 49160Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 49170Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 49180Sstevel@tonic-gate hp->next->prev = hp->prev; 49190Sstevel@tonic-gate hp->prev->next = hp->next; 49200Sstevel@tonic-gate /* 49210Sstevel@tonic-gate * free any errdef link structures 49220Sstevel@tonic-gate * tagged on to this shadow handle 49230Sstevel@tonic-gate */ 49240Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 49250Sstevel@tonic-gate next_lp = lp->link; 49260Sstevel@tonic-gate lp->link = bofi_link_freelist; 49270Sstevel@tonic-gate bofi_link_freelist = lp; 49280Sstevel@tonic-gate lp = next_lp; 49290Sstevel@tonic-gate } 49300Sstevel@tonic-gate hp->link = NULL; 49310Sstevel@tonic-gate mutex_exit(&bofi_mutex); 49320Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 49330Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 49340Sstevel@tonic-gate return (retval); 49350Sstevel@tonic-gate default: 49360Sstevel@tonic-gate return (save_bus_ops.bus_intr_op(dip, rdip, 49370Sstevel@tonic-gate intr_op, hdlp, result)); 49380Sstevel@tonic-gate } 49390Sstevel@tonic-gate } 4940