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