1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/sysmacros.h> 31*0Sstevel@tonic-gate #include <sys/buf.h> 32*0Sstevel@tonic-gate #include <sys/errno.h> 33*0Sstevel@tonic-gate #include <sys/modctl.h> 34*0Sstevel@tonic-gate #include <sys/conf.h> 35*0Sstevel@tonic-gate #include <sys/stat.h> 36*0Sstevel@tonic-gate #include <sys/kmem.h> 37*0Sstevel@tonic-gate #include <sys/proc.h> 38*0Sstevel@tonic-gate #include <sys/cpuvar.h> 39*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 40*0Sstevel@tonic-gate #include <sys/ddi.h> 41*0Sstevel@tonic-gate #include <sys/sunddi.h> 42*0Sstevel@tonic-gate #include <sys/sunndi.h> 43*0Sstevel@tonic-gate #include <sys/debug.h> 44*0Sstevel@tonic-gate #include <sys/bofi.h> 45*0Sstevel@tonic-gate #include <sys/dvma.h> 46*0Sstevel@tonic-gate #include <sys/bofi_impl.h> 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate /* 49*0Sstevel@tonic-gate * Testing the resilience of a hardened device driver requires a suitably wide 50*0Sstevel@tonic-gate * range of different types of "typical" hardware faults to be injected, 51*0Sstevel@tonic-gate * preferably in a controlled and repeatable fashion. This is not in general 52*0Sstevel@tonic-gate * possible via hardware, so the "fault injection test harness" is provided. 53*0Sstevel@tonic-gate * This works by intercepting calls from the driver to various DDI routines, 54*0Sstevel@tonic-gate * and then corrupting the result of those DDI routine calls as if the 55*0Sstevel@tonic-gate * hardware had caused the corruption. 56*0Sstevel@tonic-gate * 57*0Sstevel@tonic-gate * Conceptually, the bofi driver consists of two parts: 58*0Sstevel@tonic-gate * 59*0Sstevel@tonic-gate * A driver interface that supports a number of ioctls which allow error 60*0Sstevel@tonic-gate * definitions ("errdefs") to be defined and subsequently managed. The 61*0Sstevel@tonic-gate * driver is a clone driver, so each open will create a separate 62*0Sstevel@tonic-gate * invocation. Any errdefs created by using ioctls to that invocation 63*0Sstevel@tonic-gate * will automatically be deleted when that invocation is closed. 64*0Sstevel@tonic-gate * 65*0Sstevel@tonic-gate * Intercept routines: When the bofi driver is attached, it edits the 66*0Sstevel@tonic-gate * bus_ops structure of the bus nexus specified by the "bofi-nexus" 67*0Sstevel@tonic-gate * field in the "bofi.conf" file, thus allowing the 68*0Sstevel@tonic-gate * bofi driver to intercept various ddi functions. These intercept 69*0Sstevel@tonic-gate * routines primarily carry out fault injections based on the errdefs 70*0Sstevel@tonic-gate * created for that device. 71*0Sstevel@tonic-gate * 72*0Sstevel@tonic-gate * Faults can be injected into: 73*0Sstevel@tonic-gate * 74*0Sstevel@tonic-gate * DMA (corrupting data for DMA to/from memory areas defined by 75*0Sstevel@tonic-gate * ddi_dma_setup(), ddi_dma_bind_handle(), etc) 76*0Sstevel@tonic-gate * 77*0Sstevel@tonic-gate * Physical IO (corrupting data sent/received via ddi_get8(), ddi_put8(), 78*0Sstevel@tonic-gate * etc), 79*0Sstevel@tonic-gate * 80*0Sstevel@tonic-gate * Interrupts (generating spurious interrupts, losing interrupts, 81*0Sstevel@tonic-gate * delaying interrupts). 82*0Sstevel@tonic-gate * 83*0Sstevel@tonic-gate * By default, ddi routines called from all drivers will be intercepted 84*0Sstevel@tonic-gate * and faults potentially injected. However, the "bofi-to-test" field in 85*0Sstevel@tonic-gate * the "bofi.conf" file can be set to a space-separated list of drivers to 86*0Sstevel@tonic-gate * test (or by preceding each driver name in the list with an "!", a list 87*0Sstevel@tonic-gate * of drivers not to test). 88*0Sstevel@tonic-gate * 89*0Sstevel@tonic-gate * In addition to fault injection, the bofi driver does a number of static 90*0Sstevel@tonic-gate * checks which are controlled by properties in the "bofi.conf" file. 91*0Sstevel@tonic-gate * 92*0Sstevel@tonic-gate * "bofi-ddi-check" - if set will validate that there are no PIO access 93*0Sstevel@tonic-gate * other than those using the DDI routines (ddi_get8(), ddi_put8(), etc). 94*0Sstevel@tonic-gate * 95*0Sstevel@tonic-gate * "bofi-range-check" - if set to values 1 (warning) or 2 (panic), will 96*0Sstevel@tonic-gate * validate that calls to ddi_get8(), ddi_put8(), etc are not made 97*0Sstevel@tonic-gate * specifying addresses outside the range of the access_handle. 98*0Sstevel@tonic-gate * 99*0Sstevel@tonic-gate * "bofi-sync-check" - if set will validate that calls to ddi_dma_sync() 100*0Sstevel@tonic-gate * are being made correctly. 101*0Sstevel@tonic-gate */ 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate extern void *bp_mapin_common(struct buf *, int); 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate static int bofi_ddi_check; 106*0Sstevel@tonic-gate static int bofi_sync_check; 107*0Sstevel@tonic-gate static int bofi_range_check; 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate static struct bofi_link bofi_link_array[BOFI_NLINKS], *bofi_link_freelist; 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate #define LLSZMASK (sizeof (uint64_t)-1) 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate #define HDL_HASH_TBL_SIZE 64 114*0Sstevel@tonic-gate static struct bofi_shadow hhash_table[HDL_HASH_TBL_SIZE]; 115*0Sstevel@tonic-gate static struct bofi_shadow dhash_table[HDL_HASH_TBL_SIZE]; 116*0Sstevel@tonic-gate #define HDL_DHASH(x) \ 117*0Sstevel@tonic-gate (&dhash_table[((uintptr_t)(x) >> 3) & (HDL_HASH_TBL_SIZE-1)]) 118*0Sstevel@tonic-gate #define HDL_HHASH(x) \ 119*0Sstevel@tonic-gate (&hhash_table[((uintptr_t)(x) >> 5) & (HDL_HASH_TBL_SIZE-1)]) 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate static struct bofi_shadow shadow_list; 122*0Sstevel@tonic-gate static struct bofi_errent *errent_listp; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate static char driver_list[NAMESIZE]; 125*0Sstevel@tonic-gate static int driver_list_size; 126*0Sstevel@tonic-gate static int driver_list_neg; 127*0Sstevel@tonic-gate static char nexus_name[NAMESIZE]; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate static int initialized = 0; 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate #define NCLONES 256 132*0Sstevel@tonic-gate static int clone_tab[NCLONES]; 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate static dev_info_t *our_dip; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate static kmutex_t bofi_mutex; 137*0Sstevel@tonic-gate static kmutex_t clone_tab_mutex; 138*0Sstevel@tonic-gate static kmutex_t bofi_low_mutex; 139*0Sstevel@tonic-gate static ddi_iblock_cookie_t bofi_low_cookie; 140*0Sstevel@tonic-gate static uint_t bofi_signal(caddr_t arg); 141*0Sstevel@tonic-gate static int bofi_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 142*0Sstevel@tonic-gate static int bofi_attach(dev_info_t *, ddi_attach_cmd_t); 143*0Sstevel@tonic-gate static int bofi_detach(dev_info_t *, ddi_detach_cmd_t); 144*0Sstevel@tonic-gate static int bofi_open(dev_t *, int, int, cred_t *); 145*0Sstevel@tonic-gate static int bofi_close(dev_t, int, int, cred_t *); 146*0Sstevel@tonic-gate static int bofi_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 147*0Sstevel@tonic-gate static int bofi_errdef_alloc(struct bofi_errdef *, char *, 148*0Sstevel@tonic-gate struct bofi_errent *); 149*0Sstevel@tonic-gate static int bofi_errdef_free(struct bofi_errent *); 150*0Sstevel@tonic-gate static void bofi_start(struct bofi_errctl *, char *); 151*0Sstevel@tonic-gate static void bofi_stop(struct bofi_errctl *, char *); 152*0Sstevel@tonic-gate static void bofi_broadcast(struct bofi_errctl *, char *); 153*0Sstevel@tonic-gate static void bofi_clear_acc_chk(struct bofi_errctl *, char *); 154*0Sstevel@tonic-gate static void bofi_clear_errors(struct bofi_errctl *, char *); 155*0Sstevel@tonic-gate static void bofi_clear_errdefs(struct bofi_errctl *, char *); 156*0Sstevel@tonic-gate static int bofi_errdef_check(struct bofi_errstate *, 157*0Sstevel@tonic-gate struct acc_log_elem **); 158*0Sstevel@tonic-gate static int bofi_errdef_check_w(struct bofi_errstate *, 159*0Sstevel@tonic-gate struct acc_log_elem **); 160*0Sstevel@tonic-gate static int bofi_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 161*0Sstevel@tonic-gate off_t, off_t, caddr_t *); 162*0Sstevel@tonic-gate static int bofi_dma_map(dev_info_t *, dev_info_t *, 163*0Sstevel@tonic-gate struct ddi_dma_req *, ddi_dma_handle_t *); 164*0Sstevel@tonic-gate static int bofi_dma_allochdl(dev_info_t *, dev_info_t *, 165*0Sstevel@tonic-gate ddi_dma_attr_t *, int (*)(caddr_t), caddr_t, 166*0Sstevel@tonic-gate ddi_dma_handle_t *); 167*0Sstevel@tonic-gate static int bofi_dma_freehdl(dev_info_t *, dev_info_t *, 168*0Sstevel@tonic-gate ddi_dma_handle_t); 169*0Sstevel@tonic-gate static int bofi_dma_bindhdl(dev_info_t *, dev_info_t *, 170*0Sstevel@tonic-gate ddi_dma_handle_t, struct ddi_dma_req *, ddi_dma_cookie_t *, 171*0Sstevel@tonic-gate uint_t *); 172*0Sstevel@tonic-gate static int bofi_dma_unbindhdl(dev_info_t *, dev_info_t *, 173*0Sstevel@tonic-gate ddi_dma_handle_t); 174*0Sstevel@tonic-gate static int bofi_dma_flush(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 175*0Sstevel@tonic-gate off_t, size_t, uint_t); 176*0Sstevel@tonic-gate static int bofi_dma_ctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 177*0Sstevel@tonic-gate enum ddi_dma_ctlops, off_t *, size_t *, caddr_t *, uint_t); 178*0Sstevel@tonic-gate static int bofi_dma_win(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 179*0Sstevel@tonic-gate uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *); 180*0Sstevel@tonic-gate static int bofi_intr_ops(dev_info_t *dip, dev_info_t *rdip, 181*0Sstevel@tonic-gate ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, 182*0Sstevel@tonic-gate void *result); 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate #if defined(__sparc) 185*0Sstevel@tonic-gate static void bofi_dvma_kaddr_load(ddi_dma_handle_t, caddr_t, uint_t, 186*0Sstevel@tonic-gate uint_t, ddi_dma_cookie_t *); 187*0Sstevel@tonic-gate static void bofi_dvma_unload(ddi_dma_handle_t, uint_t, uint_t); 188*0Sstevel@tonic-gate static void bofi_dvma_sync(ddi_dma_handle_t, uint_t, uint_t); 189*0Sstevel@tonic-gate static void bofi_dvma_reserve(dev_info_t *, ddi_dma_handle_t); 190*0Sstevel@tonic-gate #endif 191*0Sstevel@tonic-gate static int driver_under_test(dev_info_t *); 192*0Sstevel@tonic-gate static int bofi_check_acc_hdl(ddi_acc_impl_t *); 193*0Sstevel@tonic-gate static int bofi_check_dma_hdl(ddi_dma_impl_t *); 194*0Sstevel@tonic-gate static int bofi_post_event(dev_info_t *dip, dev_info_t *rdip, 195*0Sstevel@tonic-gate ddi_eventcookie_t eventhdl, void *impl_data); 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate static struct bus_ops bofi_bus_ops = { 198*0Sstevel@tonic-gate BUSO_REV, 199*0Sstevel@tonic-gate bofi_map, 200*0Sstevel@tonic-gate NULL, 201*0Sstevel@tonic-gate NULL, 202*0Sstevel@tonic-gate NULL, 203*0Sstevel@tonic-gate i_ddi_map_fault, 204*0Sstevel@tonic-gate bofi_dma_map, 205*0Sstevel@tonic-gate bofi_dma_allochdl, 206*0Sstevel@tonic-gate bofi_dma_freehdl, 207*0Sstevel@tonic-gate bofi_dma_bindhdl, 208*0Sstevel@tonic-gate bofi_dma_unbindhdl, 209*0Sstevel@tonic-gate bofi_dma_flush, 210*0Sstevel@tonic-gate bofi_dma_win, 211*0Sstevel@tonic-gate bofi_dma_ctl, 212*0Sstevel@tonic-gate NULL, 213*0Sstevel@tonic-gate ddi_bus_prop_op, 214*0Sstevel@tonic-gate ndi_busop_get_eventcookie, 215*0Sstevel@tonic-gate ndi_busop_add_eventcall, 216*0Sstevel@tonic-gate ndi_busop_remove_eventcall, 217*0Sstevel@tonic-gate bofi_post_event, 218*0Sstevel@tonic-gate NULL, 219*0Sstevel@tonic-gate 0, 220*0Sstevel@tonic-gate 0, 221*0Sstevel@tonic-gate 0, 222*0Sstevel@tonic-gate 0, 223*0Sstevel@tonic-gate 0, 224*0Sstevel@tonic-gate 0, 225*0Sstevel@tonic-gate 0, 226*0Sstevel@tonic-gate bofi_intr_ops 227*0Sstevel@tonic-gate }; 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate static struct cb_ops bofi_cb_ops = { 230*0Sstevel@tonic-gate bofi_open, 231*0Sstevel@tonic-gate bofi_close, 232*0Sstevel@tonic-gate nodev, 233*0Sstevel@tonic-gate nodev, 234*0Sstevel@tonic-gate nodev, /* dump */ 235*0Sstevel@tonic-gate nodev, 236*0Sstevel@tonic-gate nodev, 237*0Sstevel@tonic-gate bofi_ioctl, 238*0Sstevel@tonic-gate nodev, /* devmap */ 239*0Sstevel@tonic-gate nodev, 240*0Sstevel@tonic-gate nodev, /* segmap */ 241*0Sstevel@tonic-gate nochpoll, 242*0Sstevel@tonic-gate nodev, 243*0Sstevel@tonic-gate NULL, /* for STREAMS drivers */ 244*0Sstevel@tonic-gate D_NEW | D_MP /* driver compatibility flag */ 245*0Sstevel@tonic-gate }; 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate static struct dev_ops bofi_ops = { 248*0Sstevel@tonic-gate DEVO_REV, /* driver build version */ 249*0Sstevel@tonic-gate 0, /* device reference count */ 250*0Sstevel@tonic-gate bofi_getinfo, 251*0Sstevel@tonic-gate nulldev, 252*0Sstevel@tonic-gate nulldev, /* probe */ 253*0Sstevel@tonic-gate bofi_attach, 254*0Sstevel@tonic-gate bofi_detach, 255*0Sstevel@tonic-gate nulldev, /* reset */ 256*0Sstevel@tonic-gate &bofi_cb_ops, 257*0Sstevel@tonic-gate (struct bus_ops *)NULL, 258*0Sstevel@tonic-gate nulldev /* power */ 259*0Sstevel@tonic-gate }; 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate /* module configuration stuff */ 262*0Sstevel@tonic-gate static void *statep; 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate static struct modldrv modldrv = { 265*0Sstevel@tonic-gate &mod_driverops, 266*0Sstevel@tonic-gate "bofi driver %I%", 267*0Sstevel@tonic-gate &bofi_ops 268*0Sstevel@tonic-gate }; 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 271*0Sstevel@tonic-gate MODREV_1, 272*0Sstevel@tonic-gate &modldrv, 273*0Sstevel@tonic-gate 0 274*0Sstevel@tonic-gate }; 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate static struct bus_ops save_bus_ops; 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate #if defined(__sparc) 279*0Sstevel@tonic-gate static struct dvma_ops bofi_dvma_ops = { 280*0Sstevel@tonic-gate DVMAO_REV, 281*0Sstevel@tonic-gate bofi_dvma_kaddr_load, 282*0Sstevel@tonic-gate bofi_dvma_unload, 283*0Sstevel@tonic-gate bofi_dvma_sync 284*0Sstevel@tonic-gate }; 285*0Sstevel@tonic-gate #endif 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /* 288*0Sstevel@tonic-gate * support routine - map user page into kernel virtual 289*0Sstevel@tonic-gate */ 290*0Sstevel@tonic-gate static caddr_t 291*0Sstevel@tonic-gate dmareq_mapin(offset_t len, caddr_t addr, struct as *as, int flag) 292*0Sstevel@tonic-gate { 293*0Sstevel@tonic-gate struct buf buf; 294*0Sstevel@tonic-gate struct proc proc; 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate /* 297*0Sstevel@tonic-gate * mock up a buf structure so we can call bp_mapin_common() 298*0Sstevel@tonic-gate */ 299*0Sstevel@tonic-gate buf.b_flags = B_PHYS; 300*0Sstevel@tonic-gate buf.b_un.b_addr = (caddr_t)addr; 301*0Sstevel@tonic-gate buf.b_bcount = (size_t)len; 302*0Sstevel@tonic-gate proc.p_as = as; 303*0Sstevel@tonic-gate buf.b_proc = &proc; 304*0Sstevel@tonic-gate return (bp_mapin_common(&buf, flag)); 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate /* 309*0Sstevel@tonic-gate * support routine - map page chain into kernel virtual 310*0Sstevel@tonic-gate */ 311*0Sstevel@tonic-gate static caddr_t 312*0Sstevel@tonic-gate dmareq_pp_mapin(offset_t len, uint_t offset, page_t *pp, int flag) 313*0Sstevel@tonic-gate { 314*0Sstevel@tonic-gate struct buf buf; 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate /* 317*0Sstevel@tonic-gate * mock up a buf structure so we can call bp_mapin_common() 318*0Sstevel@tonic-gate */ 319*0Sstevel@tonic-gate buf.b_flags = B_PAGEIO; 320*0Sstevel@tonic-gate buf.b_un.b_addr = (caddr_t)(uintptr_t)offset; 321*0Sstevel@tonic-gate buf.b_bcount = (size_t)len; 322*0Sstevel@tonic-gate buf.b_pages = pp; 323*0Sstevel@tonic-gate return (bp_mapin_common(&buf, flag)); 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate /* 328*0Sstevel@tonic-gate * support routine - map page array into kernel virtual 329*0Sstevel@tonic-gate */ 330*0Sstevel@tonic-gate static caddr_t 331*0Sstevel@tonic-gate dmareq_pplist_mapin(uint_t len, caddr_t addr, page_t **pplist, struct as *as, 332*0Sstevel@tonic-gate int flag) 333*0Sstevel@tonic-gate { 334*0Sstevel@tonic-gate struct buf buf; 335*0Sstevel@tonic-gate struct proc proc; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate /* 338*0Sstevel@tonic-gate * mock up a buf structure so we can call bp_mapin_common() 339*0Sstevel@tonic-gate */ 340*0Sstevel@tonic-gate buf.b_flags = B_PHYS|B_SHADOW; 341*0Sstevel@tonic-gate buf.b_un.b_addr = addr; 342*0Sstevel@tonic-gate buf.b_bcount = len; 343*0Sstevel@tonic-gate buf.b_shadow = pplist; 344*0Sstevel@tonic-gate proc.p_as = as; 345*0Sstevel@tonic-gate buf.b_proc = &proc; 346*0Sstevel@tonic-gate return (bp_mapin_common(&buf, flag)); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate /* 351*0Sstevel@tonic-gate * support routine - map dmareq into kernel virtual if not already 352*0Sstevel@tonic-gate * fills in *lenp with length 353*0Sstevel@tonic-gate * *mapaddr will be new kernel virtual address - or null if no mapping needed 354*0Sstevel@tonic-gate */ 355*0Sstevel@tonic-gate static caddr_t 356*0Sstevel@tonic-gate ddi_dmareq_mapin(struct ddi_dma_req *dmareqp, caddr_t *mapaddrp, 357*0Sstevel@tonic-gate offset_t *lenp) 358*0Sstevel@tonic-gate { 359*0Sstevel@tonic-gate int sleep = (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? VM_SLEEP: VM_NOSLEEP; 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate *lenp = dmareqp->dmar_object.dmao_size; 362*0Sstevel@tonic-gate if (dmareqp->dmar_object.dmao_type == DMA_OTYP_PAGES) { 363*0Sstevel@tonic-gate *mapaddrp = dmareq_pp_mapin(dmareqp->dmar_object.dmao_size, 364*0Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.pp_obj.pp_offset, 365*0Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.pp_obj.pp_pp, sleep); 366*0Sstevel@tonic-gate return (*mapaddrp); 367*0Sstevel@tonic-gate } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_priv != NULL) { 368*0Sstevel@tonic-gate *mapaddrp = dmareq_pplist_mapin(dmareqp->dmar_object.dmao_size, 369*0Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_addr, 370*0Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_priv, 371*0Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_as, sleep); 372*0Sstevel@tonic-gate return (*mapaddrp); 373*0Sstevel@tonic-gate } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_as == &kas) { 374*0Sstevel@tonic-gate *mapaddrp = NULL; 375*0Sstevel@tonic-gate return (dmareqp->dmar_object.dmao_obj.virt_obj.v_addr); 376*0Sstevel@tonic-gate } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_as == NULL) { 377*0Sstevel@tonic-gate *mapaddrp = NULL; 378*0Sstevel@tonic-gate return (dmareqp->dmar_object.dmao_obj.virt_obj.v_addr); 379*0Sstevel@tonic-gate } else { 380*0Sstevel@tonic-gate *mapaddrp = dmareq_mapin(dmareqp->dmar_object.dmao_size, 381*0Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_addr, 382*0Sstevel@tonic-gate dmareqp->dmar_object.dmao_obj.virt_obj.v_as, sleep); 383*0Sstevel@tonic-gate return (*mapaddrp); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate /* 389*0Sstevel@tonic-gate * support routine - free off kernel virtual mapping as allocated by 390*0Sstevel@tonic-gate * ddi_dmareq_mapin() 391*0Sstevel@tonic-gate */ 392*0Sstevel@tonic-gate static void 393*0Sstevel@tonic-gate ddi_dmareq_mapout(caddr_t addr, offset_t len) 394*0Sstevel@tonic-gate { 395*0Sstevel@tonic-gate struct buf buf; 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate if (addr == NULL) 398*0Sstevel@tonic-gate return; 399*0Sstevel@tonic-gate /* 400*0Sstevel@tonic-gate * mock up a buf structure 401*0Sstevel@tonic-gate */ 402*0Sstevel@tonic-gate buf.b_flags = B_REMAPPED; 403*0Sstevel@tonic-gate buf.b_un.b_addr = addr; 404*0Sstevel@tonic-gate buf.b_bcount = (size_t)len; 405*0Sstevel@tonic-gate bp_mapout(&buf); 406*0Sstevel@tonic-gate } 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate static time_t 409*0Sstevel@tonic-gate bofi_gettime() 410*0Sstevel@tonic-gate { 411*0Sstevel@tonic-gate timestruc_t ts; 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate gethrestime(&ts); 414*0Sstevel@tonic-gate return (ts.tv_sec); 415*0Sstevel@tonic-gate } 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate /* 418*0Sstevel@tonic-gate * reset the bus_ops structure of the specified nexus to point to 419*0Sstevel@tonic-gate * the original values in the save_bus_ops structure. 420*0Sstevel@tonic-gate * 421*0Sstevel@tonic-gate * Note that both this routine and modify_bus_ops() rely on the current 422*0Sstevel@tonic-gate * behavior of the framework in that nexus drivers are not unloadable 423*0Sstevel@tonic-gate * 424*0Sstevel@tonic-gate */ 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate static int 427*0Sstevel@tonic-gate reset_bus_ops(char *name, struct bus_ops *bop) 428*0Sstevel@tonic-gate { 429*0Sstevel@tonic-gate struct modctl *modp; 430*0Sstevel@tonic-gate struct modldrv *mp; 431*0Sstevel@tonic-gate struct bus_ops *bp; 432*0Sstevel@tonic-gate struct dev_ops *ops; 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate mutex_enter(&mod_lock); 435*0Sstevel@tonic-gate /* 436*0Sstevel@tonic-gate * find specified module 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate modp = &modules; 439*0Sstevel@tonic-gate do { 440*0Sstevel@tonic-gate if (strcmp(name, modp->mod_modname) == 0) { 441*0Sstevel@tonic-gate if (!modp->mod_linkage) { 442*0Sstevel@tonic-gate mutex_exit(&mod_lock); 443*0Sstevel@tonic-gate return (0); 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate mp = modp->mod_linkage->ml_linkage[0]; 446*0Sstevel@tonic-gate if (!mp || !mp->drv_dev_ops) { 447*0Sstevel@tonic-gate mutex_exit(&mod_lock); 448*0Sstevel@tonic-gate return (0); 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate ops = mp->drv_dev_ops; 451*0Sstevel@tonic-gate bp = ops->devo_bus_ops; 452*0Sstevel@tonic-gate if (!bp) { 453*0Sstevel@tonic-gate mutex_exit(&mod_lock); 454*0Sstevel@tonic-gate return (0); 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate if (ops->devo_refcnt > 0) { 457*0Sstevel@tonic-gate /* 458*0Sstevel@tonic-gate * As long as devices are active with modified 459*0Sstevel@tonic-gate * bus ops bofi must not go away. There may be 460*0Sstevel@tonic-gate * drivers with modified access or dma handles. 461*0Sstevel@tonic-gate */ 462*0Sstevel@tonic-gate mutex_exit(&mod_lock); 463*0Sstevel@tonic-gate return (0); 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate cmn_err(CE_NOTE, "bofi reset bus_ops for %s", 466*0Sstevel@tonic-gate mp->drv_linkinfo); 467*0Sstevel@tonic-gate bp->bus_intr_op = bop->bus_intr_op; 468*0Sstevel@tonic-gate bp->bus_post_event = bop->bus_post_event; 469*0Sstevel@tonic-gate bp->bus_map = bop->bus_map; 470*0Sstevel@tonic-gate bp->bus_dma_map = bop->bus_dma_map; 471*0Sstevel@tonic-gate bp->bus_dma_allochdl = bop->bus_dma_allochdl; 472*0Sstevel@tonic-gate bp->bus_dma_freehdl = bop->bus_dma_freehdl; 473*0Sstevel@tonic-gate bp->bus_dma_bindhdl = bop->bus_dma_bindhdl; 474*0Sstevel@tonic-gate bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl; 475*0Sstevel@tonic-gate bp->bus_dma_flush = bop->bus_dma_flush; 476*0Sstevel@tonic-gate bp->bus_dma_win = bop->bus_dma_win; 477*0Sstevel@tonic-gate bp->bus_dma_ctl = bop->bus_dma_ctl; 478*0Sstevel@tonic-gate mutex_exit(&mod_lock); 479*0Sstevel@tonic-gate return (1); 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules); 482*0Sstevel@tonic-gate mutex_exit(&mod_lock); 483*0Sstevel@tonic-gate return (0); 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate /* 487*0Sstevel@tonic-gate * modify the bus_ops structure of the specified nexus to point to bofi 488*0Sstevel@tonic-gate * routines, saving the original values in the save_bus_ops structure 489*0Sstevel@tonic-gate */ 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate static int 492*0Sstevel@tonic-gate modify_bus_ops(char *name, struct bus_ops *bop) 493*0Sstevel@tonic-gate { 494*0Sstevel@tonic-gate struct modctl *modp; 495*0Sstevel@tonic-gate struct modldrv *mp; 496*0Sstevel@tonic-gate struct bus_ops *bp; 497*0Sstevel@tonic-gate struct dev_ops *ops; 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate if (ddi_name_to_major(name) == -1) 500*0Sstevel@tonic-gate return (0); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate mutex_enter(&mod_lock); 503*0Sstevel@tonic-gate /* 504*0Sstevel@tonic-gate * find specified module 505*0Sstevel@tonic-gate */ 506*0Sstevel@tonic-gate modp = &modules; 507*0Sstevel@tonic-gate do { 508*0Sstevel@tonic-gate if (strcmp(name, modp->mod_modname) == 0) { 509*0Sstevel@tonic-gate if (!modp->mod_linkage) { 510*0Sstevel@tonic-gate mutex_exit(&mod_lock); 511*0Sstevel@tonic-gate return (0); 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate mp = modp->mod_linkage->ml_linkage[0]; 514*0Sstevel@tonic-gate if (!mp || !mp->drv_dev_ops) { 515*0Sstevel@tonic-gate mutex_exit(&mod_lock); 516*0Sstevel@tonic-gate return (0); 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate ops = mp->drv_dev_ops; 519*0Sstevel@tonic-gate bp = ops->devo_bus_ops; 520*0Sstevel@tonic-gate if (!bp) { 521*0Sstevel@tonic-gate mutex_exit(&mod_lock); 522*0Sstevel@tonic-gate return (0); 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate if (ops->devo_refcnt == 0) { 525*0Sstevel@tonic-gate /* 526*0Sstevel@tonic-gate * If there is no device active for this 527*0Sstevel@tonic-gate * module then there is nothing to do for bofi. 528*0Sstevel@tonic-gate */ 529*0Sstevel@tonic-gate mutex_exit(&mod_lock); 530*0Sstevel@tonic-gate return (0); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate cmn_err(CE_NOTE, "bofi modify bus_ops for %s", 533*0Sstevel@tonic-gate mp->drv_linkinfo); 534*0Sstevel@tonic-gate save_bus_ops = *bp; 535*0Sstevel@tonic-gate bp->bus_intr_op = bop->bus_intr_op; 536*0Sstevel@tonic-gate bp->bus_post_event = bop->bus_post_event; 537*0Sstevel@tonic-gate bp->bus_map = bop->bus_map; 538*0Sstevel@tonic-gate bp->bus_dma_map = bop->bus_dma_map; 539*0Sstevel@tonic-gate bp->bus_dma_allochdl = bop->bus_dma_allochdl; 540*0Sstevel@tonic-gate bp->bus_dma_freehdl = bop->bus_dma_freehdl; 541*0Sstevel@tonic-gate bp->bus_dma_bindhdl = bop->bus_dma_bindhdl; 542*0Sstevel@tonic-gate bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl; 543*0Sstevel@tonic-gate bp->bus_dma_flush = bop->bus_dma_flush; 544*0Sstevel@tonic-gate bp->bus_dma_win = bop->bus_dma_win; 545*0Sstevel@tonic-gate bp->bus_dma_ctl = bop->bus_dma_ctl; 546*0Sstevel@tonic-gate mutex_exit(&mod_lock); 547*0Sstevel@tonic-gate return (1); 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules); 550*0Sstevel@tonic-gate mutex_exit(&mod_lock); 551*0Sstevel@tonic-gate return (0); 552*0Sstevel@tonic-gate } 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate int 556*0Sstevel@tonic-gate _init(void) 557*0Sstevel@tonic-gate { 558*0Sstevel@tonic-gate int e; 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate e = ddi_soft_state_init(&statep, sizeof (struct bofi_errent), 1); 561*0Sstevel@tonic-gate if (e != 0) 562*0Sstevel@tonic-gate return (e); 563*0Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) 564*0Sstevel@tonic-gate ddi_soft_state_fini(&statep); 565*0Sstevel@tonic-gate return (e); 566*0Sstevel@tonic-gate } 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate int 570*0Sstevel@tonic-gate _fini(void) 571*0Sstevel@tonic-gate { 572*0Sstevel@tonic-gate int e; 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) != 0) 575*0Sstevel@tonic-gate return (e); 576*0Sstevel@tonic-gate ddi_soft_state_fini(&statep); 577*0Sstevel@tonic-gate return (e); 578*0Sstevel@tonic-gate } 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate int 582*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 583*0Sstevel@tonic-gate { 584*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate static int 589*0Sstevel@tonic-gate bofi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 590*0Sstevel@tonic-gate { 591*0Sstevel@tonic-gate char *name; 592*0Sstevel@tonic-gate char buf[80]; 593*0Sstevel@tonic-gate int i; 594*0Sstevel@tonic-gate int s, ss; 595*0Sstevel@tonic-gate int size = NAMESIZE; 596*0Sstevel@tonic-gate int new_string; 597*0Sstevel@tonic-gate char *ptr; 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate if (cmd != DDI_ATTACH) 600*0Sstevel@tonic-gate return (DDI_FAILURE); 601*0Sstevel@tonic-gate /* 602*0Sstevel@tonic-gate * only one instance - but we clone using the open routine 603*0Sstevel@tonic-gate */ 604*0Sstevel@tonic-gate if (ddi_get_instance(dip) > 0) 605*0Sstevel@tonic-gate return (DDI_FAILURE); 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate if (!initialized) { 608*0Sstevel@tonic-gate if ((name = ddi_get_name(dip)) == NULL) 609*0Sstevel@tonic-gate return (DDI_FAILURE); 610*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s,ctl", name); 611*0Sstevel@tonic-gate if (ddi_create_minor_node(dip, buf, S_IFCHR, 0, 612*0Sstevel@tonic-gate DDI_PSEUDO, NULL) == DDI_FAILURE) 613*0Sstevel@tonic-gate return (DDI_FAILURE); 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_MED, 616*0Sstevel@tonic-gate &bofi_low_cookie) != DDI_SUCCESS) { 617*0Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 618*0Sstevel@tonic-gate return (DDI_FAILURE); /* fail attach */ 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate /* 621*0Sstevel@tonic-gate * get nexus name (from conf file) 622*0Sstevel@tonic-gate */ 623*0Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0, 624*0Sstevel@tonic-gate "bofi-nexus", nexus_name, &size) != DDI_PROP_SUCCESS) { 625*0Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 626*0Sstevel@tonic-gate return (DDI_FAILURE); 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate /* 629*0Sstevel@tonic-gate * get whether to do dma map kmem private checking 630*0Sstevel@tonic-gate */ 631*0Sstevel@tonic-gate if ((bofi_range_check = ddi_prop_lookup_string(DDI_DEV_T_ANY, 632*0Sstevel@tonic-gate dip, 0, "bofi-range-check", &ptr)) != DDI_PROP_SUCCESS) 633*0Sstevel@tonic-gate bofi_range_check = 0; 634*0Sstevel@tonic-gate else if (strcmp(ptr, "panic") == 0) 635*0Sstevel@tonic-gate bofi_range_check = 2; 636*0Sstevel@tonic-gate else if (strcmp(ptr, "warn") == 0) 637*0Sstevel@tonic-gate bofi_range_check = 1; 638*0Sstevel@tonic-gate else 639*0Sstevel@tonic-gate bofi_range_check = 0; 640*0Sstevel@tonic-gate ddi_prop_free(ptr); 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate /* 643*0Sstevel@tonic-gate * get whether to prevent direct access to register 644*0Sstevel@tonic-gate */ 645*0Sstevel@tonic-gate if ((bofi_ddi_check = ddi_prop_lookup_string(DDI_DEV_T_ANY, 646*0Sstevel@tonic-gate dip, 0, "bofi-ddi-check", &ptr)) != DDI_PROP_SUCCESS) 647*0Sstevel@tonic-gate bofi_ddi_check = 0; 648*0Sstevel@tonic-gate else if (strcmp(ptr, "on") == 0) 649*0Sstevel@tonic-gate bofi_ddi_check = 1; 650*0Sstevel@tonic-gate else 651*0Sstevel@tonic-gate bofi_ddi_check = 0; 652*0Sstevel@tonic-gate ddi_prop_free(ptr); 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate /* 655*0Sstevel@tonic-gate * get whether to do copy on ddi_dma_sync 656*0Sstevel@tonic-gate */ 657*0Sstevel@tonic-gate if ((bofi_sync_check = ddi_prop_lookup_string(DDI_DEV_T_ANY, 658*0Sstevel@tonic-gate dip, 0, "bofi-sync-check", &ptr)) != DDI_PROP_SUCCESS) 659*0Sstevel@tonic-gate bofi_sync_check = 0; 660*0Sstevel@tonic-gate else if (strcmp(ptr, "on") == 0) 661*0Sstevel@tonic-gate bofi_sync_check = 1; 662*0Sstevel@tonic-gate else 663*0Sstevel@tonic-gate bofi_sync_check = 0; 664*0Sstevel@tonic-gate ddi_prop_free(ptr); 665*0Sstevel@tonic-gate 666*0Sstevel@tonic-gate /* 667*0Sstevel@tonic-gate * get driver-under-test names (from conf file) 668*0Sstevel@tonic-gate */ 669*0Sstevel@tonic-gate size = NAMESIZE; 670*0Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0, 671*0Sstevel@tonic-gate "bofi-to-test", driver_list, &size) != DDI_PROP_SUCCESS) 672*0Sstevel@tonic-gate driver_list[0] = 0; 673*0Sstevel@tonic-gate /* 674*0Sstevel@tonic-gate * and convert into a sequence of strings 675*0Sstevel@tonic-gate */ 676*0Sstevel@tonic-gate driver_list_neg = 1; 677*0Sstevel@tonic-gate new_string = 1; 678*0Sstevel@tonic-gate driver_list_size = strlen(driver_list); 679*0Sstevel@tonic-gate for (i = 0; i < driver_list_size; i++) { 680*0Sstevel@tonic-gate if (driver_list[i] == ' ') { 681*0Sstevel@tonic-gate driver_list[i] = '\0'; 682*0Sstevel@tonic-gate new_string = 1; 683*0Sstevel@tonic-gate } else if (new_string) { 684*0Sstevel@tonic-gate if (driver_list[i] != '!') 685*0Sstevel@tonic-gate driver_list_neg = 0; 686*0Sstevel@tonic-gate new_string = 0; 687*0Sstevel@tonic-gate } 688*0Sstevel@tonic-gate } 689*0Sstevel@tonic-gate /* 690*0Sstevel@tonic-gate * initialize mutex, lists 691*0Sstevel@tonic-gate */ 692*0Sstevel@tonic-gate mutex_init(&clone_tab_mutex, NULL, MUTEX_DRIVER, 693*0Sstevel@tonic-gate NULL); 694*0Sstevel@tonic-gate /* 695*0Sstevel@tonic-gate * fake up iblock cookie - need to protect outselves 696*0Sstevel@tonic-gate * against drivers that use hilevel interrupts 697*0Sstevel@tonic-gate */ 698*0Sstevel@tonic-gate ss = spl8(); 699*0Sstevel@tonic-gate s = spl8(); 700*0Sstevel@tonic-gate splx(ss); 701*0Sstevel@tonic-gate mutex_init(&bofi_mutex, NULL, MUTEX_SPIN, (void *)(uintptr_t)s); 702*0Sstevel@tonic-gate mutex_init(&bofi_low_mutex, NULL, MUTEX_DRIVER, 703*0Sstevel@tonic-gate (void *)bofi_low_cookie); 704*0Sstevel@tonic-gate shadow_list.next = &shadow_list; 705*0Sstevel@tonic-gate shadow_list.prev = &shadow_list; 706*0Sstevel@tonic-gate for (i = 0; i < HDL_HASH_TBL_SIZE; i++) { 707*0Sstevel@tonic-gate hhash_table[i].hnext = &hhash_table[i]; 708*0Sstevel@tonic-gate hhash_table[i].hprev = &hhash_table[i]; 709*0Sstevel@tonic-gate dhash_table[i].dnext = &dhash_table[i]; 710*0Sstevel@tonic-gate dhash_table[i].dprev = &dhash_table[i]; 711*0Sstevel@tonic-gate } 712*0Sstevel@tonic-gate for (i = 1; i < BOFI_NLINKS; i++) 713*0Sstevel@tonic-gate bofi_link_array[i].link = &bofi_link_array[i-1]; 714*0Sstevel@tonic-gate bofi_link_freelist = &bofi_link_array[BOFI_NLINKS - 1]; 715*0Sstevel@tonic-gate /* 716*0Sstevel@tonic-gate * overlay bus_ops structure 717*0Sstevel@tonic-gate */ 718*0Sstevel@tonic-gate if (modify_bus_ops(nexus_name, &bofi_bus_ops) == 0) { 719*0Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 720*0Sstevel@tonic-gate mutex_destroy(&clone_tab_mutex); 721*0Sstevel@tonic-gate mutex_destroy(&bofi_mutex); 722*0Sstevel@tonic-gate mutex_destroy(&bofi_low_mutex); 723*0Sstevel@tonic-gate return (DDI_FAILURE); 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate /* 726*0Sstevel@tonic-gate * save dip for getinfo 727*0Sstevel@tonic-gate */ 728*0Sstevel@tonic-gate our_dip = dip; 729*0Sstevel@tonic-gate ddi_report_dev(dip); 730*0Sstevel@tonic-gate initialized = 1; 731*0Sstevel@tonic-gate } 732*0Sstevel@tonic-gate return (DDI_SUCCESS); 733*0Sstevel@tonic-gate } 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate static int 737*0Sstevel@tonic-gate bofi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 738*0Sstevel@tonic-gate { 739*0Sstevel@tonic-gate char *name; 740*0Sstevel@tonic-gate char buf[80]; 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate if (cmd != DDI_DETACH) 743*0Sstevel@tonic-gate return (DDI_FAILURE); 744*0Sstevel@tonic-gate if (ddi_get_instance(dip) > 0) 745*0Sstevel@tonic-gate return (DDI_FAILURE); 746*0Sstevel@tonic-gate if ((name = ddi_get_name(dip)) == NULL) 747*0Sstevel@tonic-gate return (DDI_FAILURE); 748*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s,ctl", name); 749*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 750*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 751*0Sstevel@tonic-gate /* 752*0Sstevel@tonic-gate * make sure test bofi is no longer in use 753*0Sstevel@tonic-gate */ 754*0Sstevel@tonic-gate if (shadow_list.next != &shadow_list || errent_listp != NULL) { 755*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 756*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 757*0Sstevel@tonic-gate return (DDI_FAILURE); 758*0Sstevel@tonic-gate } 759*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 760*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate /* 763*0Sstevel@tonic-gate * restore bus_ops structure 764*0Sstevel@tonic-gate */ 765*0Sstevel@tonic-gate if (reset_bus_ops(nexus_name, &save_bus_ops) == 0) 766*0Sstevel@tonic-gate return (DDI_FAILURE); 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate mutex_destroy(&clone_tab_mutex); 769*0Sstevel@tonic-gate mutex_destroy(&bofi_mutex); 770*0Sstevel@tonic-gate mutex_destroy(&bofi_low_mutex); 771*0Sstevel@tonic-gate ddi_remove_minor_node(dip, buf); 772*0Sstevel@tonic-gate our_dip = NULL; 773*0Sstevel@tonic-gate initialized = 0; 774*0Sstevel@tonic-gate return (DDI_SUCCESS); 775*0Sstevel@tonic-gate } 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate /* ARGSUSED */ 779*0Sstevel@tonic-gate static int 780*0Sstevel@tonic-gate bofi_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 781*0Sstevel@tonic-gate { 782*0Sstevel@tonic-gate dev_t dev = (dev_t)arg; 783*0Sstevel@tonic-gate int minor = (int)getminor(dev); 784*0Sstevel@tonic-gate int retval; 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate switch (cmd) { 787*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 788*0Sstevel@tonic-gate if (minor != 0 || our_dip == NULL) { 789*0Sstevel@tonic-gate *result = (void *)NULL; 790*0Sstevel@tonic-gate retval = DDI_FAILURE; 791*0Sstevel@tonic-gate } else { 792*0Sstevel@tonic-gate *result = (void *)our_dip; 793*0Sstevel@tonic-gate retval = DDI_SUCCESS; 794*0Sstevel@tonic-gate } 795*0Sstevel@tonic-gate break; 796*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 797*0Sstevel@tonic-gate *result = (void *)0; 798*0Sstevel@tonic-gate retval = DDI_SUCCESS; 799*0Sstevel@tonic-gate break; 800*0Sstevel@tonic-gate default: 801*0Sstevel@tonic-gate retval = DDI_FAILURE; 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate return (retval); 804*0Sstevel@tonic-gate } 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate 807*0Sstevel@tonic-gate /* ARGSUSED */ 808*0Sstevel@tonic-gate static int 809*0Sstevel@tonic-gate bofi_open(dev_t *devp, int flag, int otyp, cred_t *credp) 810*0Sstevel@tonic-gate { 811*0Sstevel@tonic-gate int minor = (int)getminor(*devp); 812*0Sstevel@tonic-gate struct bofi_errent *softc; 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate /* 815*0Sstevel@tonic-gate * only allow open on minor=0 - the clone device 816*0Sstevel@tonic-gate */ 817*0Sstevel@tonic-gate if (minor != 0) 818*0Sstevel@tonic-gate return (ENXIO); 819*0Sstevel@tonic-gate /* 820*0Sstevel@tonic-gate * fail if not attached 821*0Sstevel@tonic-gate */ 822*0Sstevel@tonic-gate if (!initialized) 823*0Sstevel@tonic-gate return (ENXIO); 824*0Sstevel@tonic-gate /* 825*0Sstevel@tonic-gate * find a free slot and grab it 826*0Sstevel@tonic-gate */ 827*0Sstevel@tonic-gate mutex_enter(&clone_tab_mutex); 828*0Sstevel@tonic-gate for (minor = 1; minor < NCLONES; minor++) { 829*0Sstevel@tonic-gate if (clone_tab[minor] == 0) { 830*0Sstevel@tonic-gate clone_tab[minor] = 1; 831*0Sstevel@tonic-gate break; 832*0Sstevel@tonic-gate } 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate mutex_exit(&clone_tab_mutex); 835*0Sstevel@tonic-gate if (minor == NCLONES) 836*0Sstevel@tonic-gate return (EAGAIN); 837*0Sstevel@tonic-gate /* 838*0Sstevel@tonic-gate * soft state structure for this clone is used to maintain a list 839*0Sstevel@tonic-gate * of allocated errdefs so they can be freed on close 840*0Sstevel@tonic-gate */ 841*0Sstevel@tonic-gate if (ddi_soft_state_zalloc(statep, minor) != DDI_SUCCESS) { 842*0Sstevel@tonic-gate mutex_enter(&clone_tab_mutex); 843*0Sstevel@tonic-gate clone_tab[minor] = 0; 844*0Sstevel@tonic-gate mutex_exit(&clone_tab_mutex); 845*0Sstevel@tonic-gate return (EAGAIN); 846*0Sstevel@tonic-gate } 847*0Sstevel@tonic-gate softc = ddi_get_soft_state(statep, minor); 848*0Sstevel@tonic-gate softc->cnext = softc; 849*0Sstevel@tonic-gate softc->cprev = softc; 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), minor); 852*0Sstevel@tonic-gate return (0); 853*0Sstevel@tonic-gate } 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate /* ARGSUSED */ 857*0Sstevel@tonic-gate static int 858*0Sstevel@tonic-gate bofi_close(dev_t dev, int flag, int otyp, cred_t *credp) 859*0Sstevel@tonic-gate { 860*0Sstevel@tonic-gate int minor = (int)getminor(dev); 861*0Sstevel@tonic-gate struct bofi_errent *softc; 862*0Sstevel@tonic-gate struct bofi_errent *ep, *next_ep; 863*0Sstevel@tonic-gate 864*0Sstevel@tonic-gate softc = ddi_get_soft_state(statep, minor); 865*0Sstevel@tonic-gate if (softc == NULL) 866*0Sstevel@tonic-gate return (ENXIO); 867*0Sstevel@tonic-gate /* 868*0Sstevel@tonic-gate * find list of errdefs and free them off 869*0Sstevel@tonic-gate */ 870*0Sstevel@tonic-gate for (ep = softc->cnext; ep != softc; ) { 871*0Sstevel@tonic-gate next_ep = ep->cnext; 872*0Sstevel@tonic-gate (void) bofi_errdef_free(ep); 873*0Sstevel@tonic-gate ep = next_ep; 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate /* 876*0Sstevel@tonic-gate * free clone tab slot 877*0Sstevel@tonic-gate */ 878*0Sstevel@tonic-gate mutex_enter(&clone_tab_mutex); 879*0Sstevel@tonic-gate clone_tab[minor] = 0; 880*0Sstevel@tonic-gate mutex_exit(&clone_tab_mutex); 881*0Sstevel@tonic-gate 882*0Sstevel@tonic-gate ddi_soft_state_free(statep, minor); 883*0Sstevel@tonic-gate return (0); 884*0Sstevel@tonic-gate } 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate /* ARGSUSED */ 888*0Sstevel@tonic-gate static int 889*0Sstevel@tonic-gate bofi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 890*0Sstevel@tonic-gate int *rvalp) 891*0Sstevel@tonic-gate { 892*0Sstevel@tonic-gate struct bofi_errent *softc; 893*0Sstevel@tonic-gate int minor = (int)getminor(dev); 894*0Sstevel@tonic-gate struct bofi_errdef errdef; 895*0Sstevel@tonic-gate struct bofi_errctl errctl; 896*0Sstevel@tonic-gate struct bofi_errstate errstate; 897*0Sstevel@tonic-gate void *ed_handle; 898*0Sstevel@tonic-gate struct bofi_get_handles get_handles; 899*0Sstevel@tonic-gate struct bofi_get_hdl_info hdl_info; 900*0Sstevel@tonic-gate struct handle_info *hdlip; 901*0Sstevel@tonic-gate struct handle_info *hib; 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate char *buffer; 904*0Sstevel@tonic-gate char *bufptr; 905*0Sstevel@tonic-gate char *endbuf; 906*0Sstevel@tonic-gate int req_count, count, err; 907*0Sstevel@tonic-gate char *namep; 908*0Sstevel@tonic-gate struct bofi_shadow *hp; 909*0Sstevel@tonic-gate int retval; 910*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 911*0Sstevel@tonic-gate int i; 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate switch (cmd) { 914*0Sstevel@tonic-gate case BOFI_ADD_DEF: 915*0Sstevel@tonic-gate /* 916*0Sstevel@tonic-gate * add a new error definition 917*0Sstevel@tonic-gate */ 918*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 919*0Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 920*0Sstevel@tonic-gate case DDI_MODEL_ILP32: 921*0Sstevel@tonic-gate { 922*0Sstevel@tonic-gate /* 923*0Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 924*0Sstevel@tonic-gate * 64 bit ioctl 925*0Sstevel@tonic-gate */ 926*0Sstevel@tonic-gate struct bofi_errdef32 errdef_32; 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errdef_32, 929*0Sstevel@tonic-gate sizeof (struct bofi_errdef32), mode)) { 930*0Sstevel@tonic-gate return (EFAULT); 931*0Sstevel@tonic-gate } 932*0Sstevel@tonic-gate errdef.namesize = errdef_32.namesize; 933*0Sstevel@tonic-gate (void) strncpy(errdef.name, errdef_32.name, NAMESIZE); 934*0Sstevel@tonic-gate errdef.instance = errdef_32.instance; 935*0Sstevel@tonic-gate errdef.rnumber = errdef_32.rnumber; 936*0Sstevel@tonic-gate errdef.offset = errdef_32.offset; 937*0Sstevel@tonic-gate errdef.len = errdef_32.len; 938*0Sstevel@tonic-gate errdef.access_type = errdef_32.access_type; 939*0Sstevel@tonic-gate errdef.access_count = errdef_32.access_count; 940*0Sstevel@tonic-gate errdef.fail_count = errdef_32.fail_count; 941*0Sstevel@tonic-gate errdef.acc_chk = errdef_32.acc_chk; 942*0Sstevel@tonic-gate errdef.optype = errdef_32.optype; 943*0Sstevel@tonic-gate errdef.operand = errdef_32.operand; 944*0Sstevel@tonic-gate errdef.log.logsize = errdef_32.log.logsize; 945*0Sstevel@tonic-gate errdef.log.entries = errdef_32.log.entries; 946*0Sstevel@tonic-gate errdef.log.flags = errdef_32.log.flags; 947*0Sstevel@tonic-gate errdef.log.wrapcnt = errdef_32.log.wrapcnt; 948*0Sstevel@tonic-gate errdef.log.start_time = errdef_32.log.start_time; 949*0Sstevel@tonic-gate errdef.log.stop_time = errdef_32.log.stop_time; 950*0Sstevel@tonic-gate errdef.log.logbase = 951*0Sstevel@tonic-gate (caddr_t)(uintptr_t)errdef_32.log.logbase; 952*0Sstevel@tonic-gate errdef.errdef_handle = errdef_32.errdef_handle; 953*0Sstevel@tonic-gate break; 954*0Sstevel@tonic-gate } 955*0Sstevel@tonic-gate case DDI_MODEL_NONE: 956*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errdef, 957*0Sstevel@tonic-gate sizeof (struct bofi_errdef), mode)) 958*0Sstevel@tonic-gate return (EFAULT); 959*0Sstevel@tonic-gate break; 960*0Sstevel@tonic-gate } 961*0Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 962*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errdef, 963*0Sstevel@tonic-gate sizeof (struct bofi_errdef), mode) != 0) 964*0Sstevel@tonic-gate return (EFAULT); 965*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 966*0Sstevel@tonic-gate /* 967*0Sstevel@tonic-gate * do some validation 968*0Sstevel@tonic-gate */ 969*0Sstevel@tonic-gate if (errdef.fail_count == 0) 970*0Sstevel@tonic-gate errdef.optype = 0; 971*0Sstevel@tonic-gate if (errdef.optype != 0) { 972*0Sstevel@tonic-gate if (errdef.access_type & BOFI_INTR && 973*0Sstevel@tonic-gate errdef.optype != BOFI_DELAY_INTR && 974*0Sstevel@tonic-gate errdef.optype != BOFI_LOSE_INTR && 975*0Sstevel@tonic-gate errdef.optype != BOFI_EXTRA_INTR) 976*0Sstevel@tonic-gate return (EINVAL); 977*0Sstevel@tonic-gate if ((errdef.access_type & (BOFI_DMA_RW|BOFI_PIO_R)) && 978*0Sstevel@tonic-gate errdef.optype == BOFI_NO_TRANSFER) 979*0Sstevel@tonic-gate return (EINVAL); 980*0Sstevel@tonic-gate if ((errdef.access_type & (BOFI_PIO_RW)) && 981*0Sstevel@tonic-gate errdef.optype != BOFI_EQUAL && 982*0Sstevel@tonic-gate errdef.optype != BOFI_OR && 983*0Sstevel@tonic-gate errdef.optype != BOFI_XOR && 984*0Sstevel@tonic-gate errdef.optype != BOFI_AND && 985*0Sstevel@tonic-gate errdef.optype != BOFI_NO_TRANSFER) 986*0Sstevel@tonic-gate return (EINVAL); 987*0Sstevel@tonic-gate } 988*0Sstevel@tonic-gate /* 989*0Sstevel@tonic-gate * find softstate for this clone, so we can tag 990*0Sstevel@tonic-gate * new errdef on to it 991*0Sstevel@tonic-gate */ 992*0Sstevel@tonic-gate softc = ddi_get_soft_state(statep, minor); 993*0Sstevel@tonic-gate if (softc == NULL) 994*0Sstevel@tonic-gate return (ENXIO); 995*0Sstevel@tonic-gate /* 996*0Sstevel@tonic-gate * read in name 997*0Sstevel@tonic-gate */ 998*0Sstevel@tonic-gate if (errdef.namesize > NAMESIZE) 999*0Sstevel@tonic-gate return (EINVAL); 1000*0Sstevel@tonic-gate namep = kmem_zalloc(errdef.namesize+1, KM_SLEEP); 1001*0Sstevel@tonic-gate (void) strncpy(namep, errdef.name, errdef.namesize); 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate if (bofi_errdef_alloc(&errdef, namep, softc) != DDI_SUCCESS) { 1004*0Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 1005*0Sstevel@tonic-gate (uintptr_t)errdef.errdef_handle); 1006*0Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 1007*0Sstevel@tonic-gate return (EINVAL); 1008*0Sstevel@tonic-gate } 1009*0Sstevel@tonic-gate /* 1010*0Sstevel@tonic-gate * copy out errdef again, including filled in errdef_handle 1011*0Sstevel@tonic-gate */ 1012*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1013*0Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 1014*0Sstevel@tonic-gate case DDI_MODEL_ILP32: 1015*0Sstevel@tonic-gate { 1016*0Sstevel@tonic-gate /* 1017*0Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 1018*0Sstevel@tonic-gate * 64 bit ioctl 1019*0Sstevel@tonic-gate */ 1020*0Sstevel@tonic-gate struct bofi_errdef32 errdef_32; 1021*0Sstevel@tonic-gate 1022*0Sstevel@tonic-gate errdef_32.namesize = errdef.namesize; 1023*0Sstevel@tonic-gate (void) strncpy(errdef_32.name, errdef.name, NAMESIZE); 1024*0Sstevel@tonic-gate errdef_32.instance = errdef.instance; 1025*0Sstevel@tonic-gate errdef_32.rnumber = errdef.rnumber; 1026*0Sstevel@tonic-gate errdef_32.offset = errdef.offset; 1027*0Sstevel@tonic-gate errdef_32.len = errdef.len; 1028*0Sstevel@tonic-gate errdef_32.access_type = errdef.access_type; 1029*0Sstevel@tonic-gate errdef_32.access_count = errdef.access_count; 1030*0Sstevel@tonic-gate errdef_32.fail_count = errdef.fail_count; 1031*0Sstevel@tonic-gate errdef_32.acc_chk = errdef.acc_chk; 1032*0Sstevel@tonic-gate errdef_32.optype = errdef.optype; 1033*0Sstevel@tonic-gate errdef_32.operand = errdef.operand; 1034*0Sstevel@tonic-gate errdef_32.log.logsize = errdef.log.logsize; 1035*0Sstevel@tonic-gate errdef_32.log.entries = errdef.log.entries; 1036*0Sstevel@tonic-gate errdef_32.log.flags = errdef.log.flags; 1037*0Sstevel@tonic-gate errdef_32.log.wrapcnt = errdef.log.wrapcnt; 1038*0Sstevel@tonic-gate errdef_32.log.start_time = errdef.log.start_time; 1039*0Sstevel@tonic-gate errdef_32.log.stop_time = errdef.log.stop_time; 1040*0Sstevel@tonic-gate errdef_32.log.logbase = 1041*0Sstevel@tonic-gate (caddr32_t)(uintptr_t)errdef.log.logbase; 1042*0Sstevel@tonic-gate errdef_32.errdef_handle = errdef.errdef_handle; 1043*0Sstevel@tonic-gate if (ddi_copyout(&errdef_32, (void *)arg, 1044*0Sstevel@tonic-gate sizeof (struct bofi_errdef32), mode) != 0) { 1045*0Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 1046*0Sstevel@tonic-gate errdef.errdef_handle); 1047*0Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 1048*0Sstevel@tonic-gate return (EFAULT); 1049*0Sstevel@tonic-gate } 1050*0Sstevel@tonic-gate break; 1051*0Sstevel@tonic-gate } 1052*0Sstevel@tonic-gate case DDI_MODEL_NONE: 1053*0Sstevel@tonic-gate if (ddi_copyout(&errdef, (void *)arg, 1054*0Sstevel@tonic-gate sizeof (struct bofi_errdef), mode) != 0) { 1055*0Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 1056*0Sstevel@tonic-gate errdef.errdef_handle); 1057*0Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 1058*0Sstevel@tonic-gate return (EFAULT); 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate break; 1061*0Sstevel@tonic-gate } 1062*0Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 1063*0Sstevel@tonic-gate if (ddi_copyout(&errdef, (void *)arg, 1064*0Sstevel@tonic-gate sizeof (struct bofi_errdef), mode) != 0) { 1065*0Sstevel@tonic-gate (void) bofi_errdef_free((struct bofi_errent *) 1066*0Sstevel@tonic-gate (uintptr_t)errdef.errdef_handle); 1067*0Sstevel@tonic-gate kmem_free(namep, errdef.namesize+1); 1068*0Sstevel@tonic-gate return (EFAULT); 1069*0Sstevel@tonic-gate } 1070*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1071*0Sstevel@tonic-gate return (0); 1072*0Sstevel@tonic-gate case BOFI_DEL_DEF: 1073*0Sstevel@tonic-gate /* 1074*0Sstevel@tonic-gate * delete existing errdef 1075*0Sstevel@tonic-gate */ 1076*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &ed_handle, 1077*0Sstevel@tonic-gate sizeof (void *), mode) != 0) 1078*0Sstevel@tonic-gate return (EFAULT); 1079*0Sstevel@tonic-gate return (bofi_errdef_free((struct bofi_errent *)ed_handle)); 1080*0Sstevel@tonic-gate case BOFI_START: 1081*0Sstevel@tonic-gate /* 1082*0Sstevel@tonic-gate * start all errdefs corresponding to 1083*0Sstevel@tonic-gate * this name and instance 1084*0Sstevel@tonic-gate */ 1085*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 1086*0Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 1087*0Sstevel@tonic-gate return (EFAULT); 1088*0Sstevel@tonic-gate /* 1089*0Sstevel@tonic-gate * copy in name 1090*0Sstevel@tonic-gate */ 1091*0Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 1092*0Sstevel@tonic-gate return (EINVAL); 1093*0Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 1094*0Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 1095*0Sstevel@tonic-gate bofi_start(&errctl, namep); 1096*0Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 1097*0Sstevel@tonic-gate return (0); 1098*0Sstevel@tonic-gate case BOFI_STOP: 1099*0Sstevel@tonic-gate /* 1100*0Sstevel@tonic-gate * stop all errdefs corresponding to 1101*0Sstevel@tonic-gate * this name and instance 1102*0Sstevel@tonic-gate */ 1103*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 1104*0Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 1105*0Sstevel@tonic-gate return (EFAULT); 1106*0Sstevel@tonic-gate /* 1107*0Sstevel@tonic-gate * copy in name 1108*0Sstevel@tonic-gate */ 1109*0Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 1110*0Sstevel@tonic-gate return (EINVAL); 1111*0Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 1112*0Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 1113*0Sstevel@tonic-gate bofi_stop(&errctl, namep); 1114*0Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 1115*0Sstevel@tonic-gate return (0); 1116*0Sstevel@tonic-gate case BOFI_BROADCAST: 1117*0Sstevel@tonic-gate /* 1118*0Sstevel@tonic-gate * wakeup all errdefs corresponding to 1119*0Sstevel@tonic-gate * this name and instance 1120*0Sstevel@tonic-gate */ 1121*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 1122*0Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 1123*0Sstevel@tonic-gate return (EFAULT); 1124*0Sstevel@tonic-gate /* 1125*0Sstevel@tonic-gate * copy in name 1126*0Sstevel@tonic-gate */ 1127*0Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 1128*0Sstevel@tonic-gate return (EINVAL); 1129*0Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 1130*0Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 1131*0Sstevel@tonic-gate bofi_broadcast(&errctl, namep); 1132*0Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 1133*0Sstevel@tonic-gate return (0); 1134*0Sstevel@tonic-gate case BOFI_CLEAR_ACC_CHK: 1135*0Sstevel@tonic-gate /* 1136*0Sstevel@tonic-gate * clear "acc_chk" for all errdefs corresponding to 1137*0Sstevel@tonic-gate * this name and instance 1138*0Sstevel@tonic-gate */ 1139*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 1140*0Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 1141*0Sstevel@tonic-gate return (EFAULT); 1142*0Sstevel@tonic-gate /* 1143*0Sstevel@tonic-gate * copy in name 1144*0Sstevel@tonic-gate */ 1145*0Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 1146*0Sstevel@tonic-gate return (EINVAL); 1147*0Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 1148*0Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 1149*0Sstevel@tonic-gate bofi_clear_acc_chk(&errctl, namep); 1150*0Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 1151*0Sstevel@tonic-gate return (0); 1152*0Sstevel@tonic-gate case BOFI_CLEAR_ERRORS: 1153*0Sstevel@tonic-gate /* 1154*0Sstevel@tonic-gate * set "fail_count" to 0 for all errdefs corresponding to 1155*0Sstevel@tonic-gate * this name and instance whose "access_count" 1156*0Sstevel@tonic-gate * has expired. 1157*0Sstevel@tonic-gate */ 1158*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 1159*0Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 1160*0Sstevel@tonic-gate return (EFAULT); 1161*0Sstevel@tonic-gate /* 1162*0Sstevel@tonic-gate * copy in name 1163*0Sstevel@tonic-gate */ 1164*0Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 1165*0Sstevel@tonic-gate return (EINVAL); 1166*0Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 1167*0Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 1168*0Sstevel@tonic-gate bofi_clear_errors(&errctl, namep); 1169*0Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 1170*0Sstevel@tonic-gate return (0); 1171*0Sstevel@tonic-gate case BOFI_CLEAR_ERRDEFS: 1172*0Sstevel@tonic-gate /* 1173*0Sstevel@tonic-gate * set "access_count" and "fail_count" to 0 for all errdefs 1174*0Sstevel@tonic-gate * corresponding to this name and instance 1175*0Sstevel@tonic-gate */ 1176*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errctl, 1177*0Sstevel@tonic-gate sizeof (struct bofi_errctl), mode) != 0) 1178*0Sstevel@tonic-gate return (EFAULT); 1179*0Sstevel@tonic-gate /* 1180*0Sstevel@tonic-gate * copy in name 1181*0Sstevel@tonic-gate */ 1182*0Sstevel@tonic-gate if (errctl.namesize > NAMESIZE) 1183*0Sstevel@tonic-gate return (EINVAL); 1184*0Sstevel@tonic-gate namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP); 1185*0Sstevel@tonic-gate (void) strncpy(namep, errctl.name, errctl.namesize); 1186*0Sstevel@tonic-gate bofi_clear_errdefs(&errctl, namep); 1187*0Sstevel@tonic-gate kmem_free(namep, errctl.namesize+1); 1188*0Sstevel@tonic-gate return (0); 1189*0Sstevel@tonic-gate case BOFI_CHK_STATE: 1190*0Sstevel@tonic-gate { 1191*0Sstevel@tonic-gate struct acc_log_elem *klg; 1192*0Sstevel@tonic-gate size_t uls; 1193*0Sstevel@tonic-gate /* 1194*0Sstevel@tonic-gate * get state for this errdef - read in dummy errstate 1195*0Sstevel@tonic-gate * with just the errdef_handle filled in 1196*0Sstevel@tonic-gate */ 1197*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1198*0Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 1199*0Sstevel@tonic-gate case DDI_MODEL_ILP32: 1200*0Sstevel@tonic-gate { 1201*0Sstevel@tonic-gate /* 1202*0Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 1203*0Sstevel@tonic-gate * 64 bit ioctl 1204*0Sstevel@tonic-gate */ 1205*0Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate_32, 1208*0Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) { 1209*0Sstevel@tonic-gate return (EFAULT); 1210*0Sstevel@tonic-gate } 1211*0Sstevel@tonic-gate errstate.fail_time = errstate_32.fail_time; 1212*0Sstevel@tonic-gate errstate.msg_time = errstate_32.msg_time; 1213*0Sstevel@tonic-gate errstate.access_count = errstate_32.access_count; 1214*0Sstevel@tonic-gate errstate.fail_count = errstate_32.fail_count; 1215*0Sstevel@tonic-gate errstate.acc_chk = errstate_32.acc_chk; 1216*0Sstevel@tonic-gate errstate.errmsg_count = errstate_32.errmsg_count; 1217*0Sstevel@tonic-gate (void) strncpy(errstate.buffer, errstate_32.buffer, 1218*0Sstevel@tonic-gate ERRMSGSIZE); 1219*0Sstevel@tonic-gate errstate.severity = errstate_32.severity; 1220*0Sstevel@tonic-gate errstate.log.logsize = errstate_32.log.logsize; 1221*0Sstevel@tonic-gate errstate.log.entries = errstate_32.log.entries; 1222*0Sstevel@tonic-gate errstate.log.flags = errstate_32.log.flags; 1223*0Sstevel@tonic-gate errstate.log.wrapcnt = errstate_32.log.wrapcnt; 1224*0Sstevel@tonic-gate errstate.log.start_time = errstate_32.log.start_time; 1225*0Sstevel@tonic-gate errstate.log.stop_time = errstate_32.log.stop_time; 1226*0Sstevel@tonic-gate errstate.log.logbase = 1227*0Sstevel@tonic-gate (caddr_t)(uintptr_t)errstate_32.log.logbase; 1228*0Sstevel@tonic-gate errstate.errdef_handle = errstate_32.errdef_handle; 1229*0Sstevel@tonic-gate break; 1230*0Sstevel@tonic-gate } 1231*0Sstevel@tonic-gate case DDI_MODEL_NONE: 1232*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 1233*0Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 1234*0Sstevel@tonic-gate return (EFAULT); 1235*0Sstevel@tonic-gate break; 1236*0Sstevel@tonic-gate } 1237*0Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 1238*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 1239*0Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 1240*0Sstevel@tonic-gate return (EFAULT); 1241*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1242*0Sstevel@tonic-gate if ((retval = bofi_errdef_check(&errstate, &klg)) == EINVAL) 1243*0Sstevel@tonic-gate return (EINVAL); 1244*0Sstevel@tonic-gate /* 1245*0Sstevel@tonic-gate * copy out real errstate structure 1246*0Sstevel@tonic-gate */ 1247*0Sstevel@tonic-gate uls = errstate.log.logsize; 1248*0Sstevel@tonic-gate if (errstate.log.entries > uls && uls) 1249*0Sstevel@tonic-gate /* insufficient user memory */ 1250*0Sstevel@tonic-gate errstate.log.entries = uls; 1251*0Sstevel@tonic-gate /* always pass back a time */ 1252*0Sstevel@tonic-gate if (errstate.log.stop_time == 0ul) 1253*0Sstevel@tonic-gate (void) drv_getparm(TIME, &(errstate.log.stop_time)); 1254*0Sstevel@tonic-gate 1255*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1256*0Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 1257*0Sstevel@tonic-gate case DDI_MODEL_ILP32: 1258*0Sstevel@tonic-gate { 1259*0Sstevel@tonic-gate /* 1260*0Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 1261*0Sstevel@tonic-gate * 64 bit ioctl 1262*0Sstevel@tonic-gate */ 1263*0Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 1264*0Sstevel@tonic-gate 1265*0Sstevel@tonic-gate errstate_32.fail_time = errstate.fail_time; 1266*0Sstevel@tonic-gate errstate_32.msg_time = errstate.msg_time; 1267*0Sstevel@tonic-gate errstate_32.access_count = errstate.access_count; 1268*0Sstevel@tonic-gate errstate_32.fail_count = errstate.fail_count; 1269*0Sstevel@tonic-gate errstate_32.acc_chk = errstate.acc_chk; 1270*0Sstevel@tonic-gate errstate_32.errmsg_count = errstate.errmsg_count; 1271*0Sstevel@tonic-gate (void) strncpy(errstate_32.buffer, errstate.buffer, 1272*0Sstevel@tonic-gate ERRMSGSIZE); 1273*0Sstevel@tonic-gate errstate_32.severity = errstate.severity; 1274*0Sstevel@tonic-gate errstate_32.log.logsize = errstate.log.logsize; 1275*0Sstevel@tonic-gate errstate_32.log.entries = errstate.log.entries; 1276*0Sstevel@tonic-gate errstate_32.log.flags = errstate.log.flags; 1277*0Sstevel@tonic-gate errstate_32.log.wrapcnt = errstate.log.wrapcnt; 1278*0Sstevel@tonic-gate errstate_32.log.start_time = errstate.log.start_time; 1279*0Sstevel@tonic-gate errstate_32.log.stop_time = errstate.log.stop_time; 1280*0Sstevel@tonic-gate errstate_32.log.logbase = 1281*0Sstevel@tonic-gate (caddr32_t)(uintptr_t)errstate.log.logbase; 1282*0Sstevel@tonic-gate errstate_32.errdef_handle = errstate.errdef_handle; 1283*0Sstevel@tonic-gate if (ddi_copyout(&errstate_32, (void *)arg, 1284*0Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) 1285*0Sstevel@tonic-gate return (EFAULT); 1286*0Sstevel@tonic-gate break; 1287*0Sstevel@tonic-gate } 1288*0Sstevel@tonic-gate case DDI_MODEL_NONE: 1289*0Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 1290*0Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 1291*0Sstevel@tonic-gate return (EFAULT); 1292*0Sstevel@tonic-gate break; 1293*0Sstevel@tonic-gate } 1294*0Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 1295*0Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 1296*0Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 1297*0Sstevel@tonic-gate return (EFAULT); 1298*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1299*0Sstevel@tonic-gate if (uls && errstate.log.entries && 1300*0Sstevel@tonic-gate ddi_copyout(klg, errstate.log.logbase, 1301*0Sstevel@tonic-gate errstate.log.entries * sizeof (struct acc_log_elem), 1302*0Sstevel@tonic-gate mode) != 0) { 1303*0Sstevel@tonic-gate return (EFAULT); 1304*0Sstevel@tonic-gate } 1305*0Sstevel@tonic-gate return (retval); 1306*0Sstevel@tonic-gate } 1307*0Sstevel@tonic-gate case BOFI_CHK_STATE_W: 1308*0Sstevel@tonic-gate { 1309*0Sstevel@tonic-gate struct acc_log_elem *klg; 1310*0Sstevel@tonic-gate size_t uls; 1311*0Sstevel@tonic-gate /* 1312*0Sstevel@tonic-gate * get state for this errdef - read in dummy errstate 1313*0Sstevel@tonic-gate * with just the errdef_handle filled in. Then wait for 1314*0Sstevel@tonic-gate * a ddi_report_fault message to come back 1315*0Sstevel@tonic-gate */ 1316*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1317*0Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 1318*0Sstevel@tonic-gate case DDI_MODEL_ILP32: 1319*0Sstevel@tonic-gate { 1320*0Sstevel@tonic-gate /* 1321*0Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 1322*0Sstevel@tonic-gate * 64 bit ioctl 1323*0Sstevel@tonic-gate */ 1324*0Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 1325*0Sstevel@tonic-gate 1326*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate_32, 1327*0Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) { 1328*0Sstevel@tonic-gate return (EFAULT); 1329*0Sstevel@tonic-gate } 1330*0Sstevel@tonic-gate errstate.fail_time = errstate_32.fail_time; 1331*0Sstevel@tonic-gate errstate.msg_time = errstate_32.msg_time; 1332*0Sstevel@tonic-gate errstate.access_count = errstate_32.access_count; 1333*0Sstevel@tonic-gate errstate.fail_count = errstate_32.fail_count; 1334*0Sstevel@tonic-gate errstate.acc_chk = errstate_32.acc_chk; 1335*0Sstevel@tonic-gate errstate.errmsg_count = errstate_32.errmsg_count; 1336*0Sstevel@tonic-gate (void) strncpy(errstate.buffer, errstate_32.buffer, 1337*0Sstevel@tonic-gate ERRMSGSIZE); 1338*0Sstevel@tonic-gate errstate.severity = errstate_32.severity; 1339*0Sstevel@tonic-gate errstate.log.logsize = errstate_32.log.logsize; 1340*0Sstevel@tonic-gate errstate.log.entries = errstate_32.log.entries; 1341*0Sstevel@tonic-gate errstate.log.flags = errstate_32.log.flags; 1342*0Sstevel@tonic-gate errstate.log.wrapcnt = errstate_32.log.wrapcnt; 1343*0Sstevel@tonic-gate errstate.log.start_time = errstate_32.log.start_time; 1344*0Sstevel@tonic-gate errstate.log.stop_time = errstate_32.log.stop_time; 1345*0Sstevel@tonic-gate errstate.log.logbase = 1346*0Sstevel@tonic-gate (caddr_t)(uintptr_t)errstate_32.log.logbase; 1347*0Sstevel@tonic-gate errstate.errdef_handle = errstate_32.errdef_handle; 1348*0Sstevel@tonic-gate break; 1349*0Sstevel@tonic-gate } 1350*0Sstevel@tonic-gate case DDI_MODEL_NONE: 1351*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 1352*0Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 1353*0Sstevel@tonic-gate return (EFAULT); 1354*0Sstevel@tonic-gate break; 1355*0Sstevel@tonic-gate } 1356*0Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 1357*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &errstate, 1358*0Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 1359*0Sstevel@tonic-gate return (EFAULT); 1360*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1361*0Sstevel@tonic-gate if ((retval = bofi_errdef_check_w(&errstate, &klg)) == EINVAL) 1362*0Sstevel@tonic-gate return (EINVAL); 1363*0Sstevel@tonic-gate /* 1364*0Sstevel@tonic-gate * copy out real errstate structure 1365*0Sstevel@tonic-gate */ 1366*0Sstevel@tonic-gate uls = errstate.log.logsize; 1367*0Sstevel@tonic-gate uls = errstate.log.logsize; 1368*0Sstevel@tonic-gate if (errstate.log.entries > uls && uls) 1369*0Sstevel@tonic-gate /* insufficient user memory */ 1370*0Sstevel@tonic-gate errstate.log.entries = uls; 1371*0Sstevel@tonic-gate /* always pass back a time */ 1372*0Sstevel@tonic-gate if (errstate.log.stop_time == 0ul) 1373*0Sstevel@tonic-gate (void) drv_getparm(TIME, &(errstate.log.stop_time)); 1374*0Sstevel@tonic-gate 1375*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1376*0Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 1377*0Sstevel@tonic-gate case DDI_MODEL_ILP32: 1378*0Sstevel@tonic-gate { 1379*0Sstevel@tonic-gate /* 1380*0Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 1381*0Sstevel@tonic-gate * 64 bit ioctl 1382*0Sstevel@tonic-gate */ 1383*0Sstevel@tonic-gate struct bofi_errstate32 errstate_32; 1384*0Sstevel@tonic-gate 1385*0Sstevel@tonic-gate errstate_32.fail_time = errstate.fail_time; 1386*0Sstevel@tonic-gate errstate_32.msg_time = errstate.msg_time; 1387*0Sstevel@tonic-gate errstate_32.access_count = errstate.access_count; 1388*0Sstevel@tonic-gate errstate_32.fail_count = errstate.fail_count; 1389*0Sstevel@tonic-gate errstate_32.acc_chk = errstate.acc_chk; 1390*0Sstevel@tonic-gate errstate_32.errmsg_count = errstate.errmsg_count; 1391*0Sstevel@tonic-gate (void) strncpy(errstate_32.buffer, errstate.buffer, 1392*0Sstevel@tonic-gate ERRMSGSIZE); 1393*0Sstevel@tonic-gate errstate_32.severity = errstate.severity; 1394*0Sstevel@tonic-gate errstate_32.log.logsize = errstate.log.logsize; 1395*0Sstevel@tonic-gate errstate_32.log.entries = errstate.log.entries; 1396*0Sstevel@tonic-gate errstate_32.log.flags = errstate.log.flags; 1397*0Sstevel@tonic-gate errstate_32.log.wrapcnt = errstate.log.wrapcnt; 1398*0Sstevel@tonic-gate errstate_32.log.start_time = errstate.log.start_time; 1399*0Sstevel@tonic-gate errstate_32.log.stop_time = errstate.log.stop_time; 1400*0Sstevel@tonic-gate errstate_32.log.logbase = 1401*0Sstevel@tonic-gate (caddr32_t)(uintptr_t)errstate.log.logbase; 1402*0Sstevel@tonic-gate errstate_32.errdef_handle = errstate.errdef_handle; 1403*0Sstevel@tonic-gate if (ddi_copyout(&errstate_32, (void *)arg, 1404*0Sstevel@tonic-gate sizeof (struct bofi_errstate32), mode) != 0) 1405*0Sstevel@tonic-gate return (EFAULT); 1406*0Sstevel@tonic-gate break; 1407*0Sstevel@tonic-gate } 1408*0Sstevel@tonic-gate case DDI_MODEL_NONE: 1409*0Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 1410*0Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 1411*0Sstevel@tonic-gate return (EFAULT); 1412*0Sstevel@tonic-gate break; 1413*0Sstevel@tonic-gate } 1414*0Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 1415*0Sstevel@tonic-gate if (ddi_copyout(&errstate, (void *)arg, 1416*0Sstevel@tonic-gate sizeof (struct bofi_errstate), mode) != 0) 1417*0Sstevel@tonic-gate return (EFAULT); 1418*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1419*0Sstevel@tonic-gate 1420*0Sstevel@tonic-gate if (uls && errstate.log.entries && 1421*0Sstevel@tonic-gate ddi_copyout(klg, errstate.log.logbase, 1422*0Sstevel@tonic-gate errstate.log.entries * sizeof (struct acc_log_elem), 1423*0Sstevel@tonic-gate mode) != 0) { 1424*0Sstevel@tonic-gate return (EFAULT); 1425*0Sstevel@tonic-gate } 1426*0Sstevel@tonic-gate return (retval); 1427*0Sstevel@tonic-gate } 1428*0Sstevel@tonic-gate case BOFI_GET_HANDLES: 1429*0Sstevel@tonic-gate /* 1430*0Sstevel@tonic-gate * display existing handles 1431*0Sstevel@tonic-gate */ 1432*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1433*0Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 1434*0Sstevel@tonic-gate case DDI_MODEL_ILP32: 1435*0Sstevel@tonic-gate { 1436*0Sstevel@tonic-gate /* 1437*0Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 1438*0Sstevel@tonic-gate * 64 bit ioctl 1439*0Sstevel@tonic-gate */ 1440*0Sstevel@tonic-gate struct bofi_get_handles32 get_handles_32; 1441*0Sstevel@tonic-gate 1442*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &get_handles_32, 1443*0Sstevel@tonic-gate sizeof (get_handles_32), mode) != 0) { 1444*0Sstevel@tonic-gate return (EFAULT); 1445*0Sstevel@tonic-gate } 1446*0Sstevel@tonic-gate get_handles.namesize = get_handles_32.namesize; 1447*0Sstevel@tonic-gate (void) strncpy(get_handles.name, get_handles_32.name, 1448*0Sstevel@tonic-gate NAMESIZE); 1449*0Sstevel@tonic-gate get_handles.instance = get_handles_32.instance; 1450*0Sstevel@tonic-gate get_handles.count = get_handles_32.count; 1451*0Sstevel@tonic-gate get_handles.buffer = 1452*0Sstevel@tonic-gate (caddr_t)(uintptr_t)get_handles_32.buffer; 1453*0Sstevel@tonic-gate break; 1454*0Sstevel@tonic-gate } 1455*0Sstevel@tonic-gate case DDI_MODEL_NONE: 1456*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &get_handles, 1457*0Sstevel@tonic-gate sizeof (get_handles), mode) != 0) 1458*0Sstevel@tonic-gate return (EFAULT); 1459*0Sstevel@tonic-gate break; 1460*0Sstevel@tonic-gate } 1461*0Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 1462*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &get_handles, 1463*0Sstevel@tonic-gate sizeof (get_handles), mode) != 0) 1464*0Sstevel@tonic-gate return (EFAULT); 1465*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1466*0Sstevel@tonic-gate /* 1467*0Sstevel@tonic-gate * read in name 1468*0Sstevel@tonic-gate */ 1469*0Sstevel@tonic-gate if (get_handles.namesize > NAMESIZE) 1470*0Sstevel@tonic-gate return (EINVAL); 1471*0Sstevel@tonic-gate namep = kmem_zalloc(get_handles.namesize+1, KM_SLEEP); 1472*0Sstevel@tonic-gate (void) strncpy(namep, get_handles.name, get_handles.namesize); 1473*0Sstevel@tonic-gate req_count = get_handles.count; 1474*0Sstevel@tonic-gate bufptr = buffer = kmem_zalloc(req_count, KM_SLEEP); 1475*0Sstevel@tonic-gate endbuf = bufptr + req_count; 1476*0Sstevel@tonic-gate /* 1477*0Sstevel@tonic-gate * display existing handles 1478*0Sstevel@tonic-gate */ 1479*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 1480*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 1481*0Sstevel@tonic-gate for (i = 0; i < HDL_HASH_TBL_SIZE; i++) { 1482*0Sstevel@tonic-gate hhashp = &hhash_table[i]; 1483*0Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) { 1484*0Sstevel@tonic-gate if (!driver_under_test(hp->dip)) 1485*0Sstevel@tonic-gate continue; 1486*0Sstevel@tonic-gate if (ddi_name_to_major(ddi_get_name(hp->dip)) != 1487*0Sstevel@tonic-gate ddi_name_to_major(namep)) 1488*0Sstevel@tonic-gate continue; 1489*0Sstevel@tonic-gate if (hp->instance != get_handles.instance) 1490*0Sstevel@tonic-gate continue; 1491*0Sstevel@tonic-gate /* 1492*0Sstevel@tonic-gate * print information per handle - note that 1493*0Sstevel@tonic-gate * DMA* means an unbound DMA handle 1494*0Sstevel@tonic-gate */ 1495*0Sstevel@tonic-gate (void) snprintf(bufptr, (size_t)(endbuf-bufptr), 1496*0Sstevel@tonic-gate " %s %d %s ", hp->name, hp->instance, 1497*0Sstevel@tonic-gate (hp->type == BOFI_INT_HDL) ? "INTR" : 1498*0Sstevel@tonic-gate (hp->type == BOFI_ACC_HDL) ? "PIO" : 1499*0Sstevel@tonic-gate (hp->type == BOFI_DMA_HDL) ? "DMA" : 1500*0Sstevel@tonic-gate (hp->hparrayp != NULL) ? "DVMA" : "DMA*"); 1501*0Sstevel@tonic-gate bufptr += strlen(bufptr); 1502*0Sstevel@tonic-gate if (hp->type == BOFI_ACC_HDL) { 1503*0Sstevel@tonic-gate if (hp->len == INT_MAX - hp->offset) 1504*0Sstevel@tonic-gate (void) snprintf(bufptr, 1505*0Sstevel@tonic-gate (size_t)(endbuf-bufptr), 1506*0Sstevel@tonic-gate "reg set %d off 0x%llx\n", 1507*0Sstevel@tonic-gate hp->rnumber, hp->offset); 1508*0Sstevel@tonic-gate else 1509*0Sstevel@tonic-gate (void) snprintf(bufptr, 1510*0Sstevel@tonic-gate (size_t)(endbuf-bufptr), 1511*0Sstevel@tonic-gate "reg set %d off 0x%llx" 1512*0Sstevel@tonic-gate " len 0x%llx\n", 1513*0Sstevel@tonic-gate hp->rnumber, hp->offset, 1514*0Sstevel@tonic-gate hp->len); 1515*0Sstevel@tonic-gate } else if (hp->type == BOFI_DMA_HDL) 1516*0Sstevel@tonic-gate (void) snprintf(bufptr, 1517*0Sstevel@tonic-gate (size_t)(endbuf-bufptr), 1518*0Sstevel@tonic-gate "handle no %d len 0x%llx" 1519*0Sstevel@tonic-gate " addr 0x%p\n", hp->rnumber, 1520*0Sstevel@tonic-gate hp->len, (void *)hp->addr); 1521*0Sstevel@tonic-gate else if (hp->type == BOFI_NULL && 1522*0Sstevel@tonic-gate hp->hparrayp == NULL) 1523*0Sstevel@tonic-gate (void) snprintf(bufptr, 1524*0Sstevel@tonic-gate (size_t)(endbuf-bufptr), 1525*0Sstevel@tonic-gate "handle no %d\n", hp->rnumber); 1526*0Sstevel@tonic-gate else 1527*0Sstevel@tonic-gate (void) snprintf(bufptr, 1528*0Sstevel@tonic-gate (size_t)(endbuf-bufptr), "\n"); 1529*0Sstevel@tonic-gate bufptr += strlen(bufptr); 1530*0Sstevel@tonic-gate } 1531*0Sstevel@tonic-gate } 1532*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 1533*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 1534*0Sstevel@tonic-gate err = ddi_copyout(buffer, get_handles.buffer, req_count, mode); 1535*0Sstevel@tonic-gate kmem_free(namep, get_handles.namesize+1); 1536*0Sstevel@tonic-gate kmem_free(buffer, req_count); 1537*0Sstevel@tonic-gate if (err != 0) 1538*0Sstevel@tonic-gate return (EFAULT); 1539*0Sstevel@tonic-gate else 1540*0Sstevel@tonic-gate return (0); 1541*0Sstevel@tonic-gate case BOFI_GET_HANDLE_INFO: 1542*0Sstevel@tonic-gate /* 1543*0Sstevel@tonic-gate * display existing handles 1544*0Sstevel@tonic-gate */ 1545*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1546*0Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 1547*0Sstevel@tonic-gate case DDI_MODEL_ILP32: 1548*0Sstevel@tonic-gate { 1549*0Sstevel@tonic-gate /* 1550*0Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 1551*0Sstevel@tonic-gate * 64 bit ioctl 1552*0Sstevel@tonic-gate */ 1553*0Sstevel@tonic-gate struct bofi_get_hdl_info32 hdl_info_32; 1554*0Sstevel@tonic-gate 1555*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &hdl_info_32, 1556*0Sstevel@tonic-gate sizeof (hdl_info_32), mode)) { 1557*0Sstevel@tonic-gate return (EFAULT); 1558*0Sstevel@tonic-gate } 1559*0Sstevel@tonic-gate hdl_info.namesize = hdl_info_32.namesize; 1560*0Sstevel@tonic-gate (void) strncpy(hdl_info.name, hdl_info_32.name, 1561*0Sstevel@tonic-gate NAMESIZE); 1562*0Sstevel@tonic-gate hdl_info.count = hdl_info_32.count; 1563*0Sstevel@tonic-gate hdl_info.hdli = (caddr_t)(uintptr_t)hdl_info_32.hdli; 1564*0Sstevel@tonic-gate break; 1565*0Sstevel@tonic-gate } 1566*0Sstevel@tonic-gate case DDI_MODEL_NONE: 1567*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &hdl_info, 1568*0Sstevel@tonic-gate sizeof (hdl_info), mode)) 1569*0Sstevel@tonic-gate return (EFAULT); 1570*0Sstevel@tonic-gate break; 1571*0Sstevel@tonic-gate } 1572*0Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 1573*0Sstevel@tonic-gate if (ddi_copyin((void *)arg, &hdl_info, 1574*0Sstevel@tonic-gate sizeof (hdl_info), mode)) 1575*0Sstevel@tonic-gate return (EFAULT); 1576*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1577*0Sstevel@tonic-gate if (hdl_info.namesize > NAMESIZE) 1578*0Sstevel@tonic-gate return (EINVAL); 1579*0Sstevel@tonic-gate namep = kmem_zalloc(hdl_info.namesize + 1, KM_SLEEP); 1580*0Sstevel@tonic-gate (void) strncpy(namep, hdl_info.name, hdl_info.namesize); 1581*0Sstevel@tonic-gate req_count = hdl_info.count; 1582*0Sstevel@tonic-gate count = hdl_info.count = 0; /* the actual no of handles */ 1583*0Sstevel@tonic-gate if (req_count > 0) { 1584*0Sstevel@tonic-gate hib = hdlip = 1585*0Sstevel@tonic-gate kmem_zalloc(req_count * sizeof (struct handle_info), 1586*0Sstevel@tonic-gate KM_SLEEP); 1587*0Sstevel@tonic-gate } else { 1588*0Sstevel@tonic-gate hib = hdlip = 0; 1589*0Sstevel@tonic-gate req_count = hdl_info.count = 0; 1590*0Sstevel@tonic-gate } 1591*0Sstevel@tonic-gate 1592*0Sstevel@tonic-gate /* 1593*0Sstevel@tonic-gate * display existing handles 1594*0Sstevel@tonic-gate */ 1595*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 1596*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 1597*0Sstevel@tonic-gate for (i = 0; i < HDL_HASH_TBL_SIZE; i++) { 1598*0Sstevel@tonic-gate hhashp = &hhash_table[i]; 1599*0Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) { 1600*0Sstevel@tonic-gate if (!driver_under_test(hp->dip) || 1601*0Sstevel@tonic-gate ddi_name_to_major(ddi_get_name(hp->dip)) != 1602*0Sstevel@tonic-gate ddi_name_to_major(namep) || 1603*0Sstevel@tonic-gate ++(hdl_info.count) > req_count || 1604*0Sstevel@tonic-gate count == req_count) 1605*0Sstevel@tonic-gate continue; 1606*0Sstevel@tonic-gate 1607*0Sstevel@tonic-gate hdlip->instance = hp->instance; 1608*0Sstevel@tonic-gate hdlip->rnumber = hp->rnumber; 1609*0Sstevel@tonic-gate switch (hp->type) { 1610*0Sstevel@tonic-gate case BOFI_ACC_HDL: 1611*0Sstevel@tonic-gate hdlip->access_type = BOFI_PIO_RW; 1612*0Sstevel@tonic-gate hdlip->offset = hp->offset; 1613*0Sstevel@tonic-gate hdlip->len = hp->len; 1614*0Sstevel@tonic-gate break; 1615*0Sstevel@tonic-gate case BOFI_DMA_HDL: 1616*0Sstevel@tonic-gate hdlip->access_type = 0; 1617*0Sstevel@tonic-gate if (hp->flags & DDI_DMA_WRITE) 1618*0Sstevel@tonic-gate hdlip->access_type |= 1619*0Sstevel@tonic-gate BOFI_DMA_W; 1620*0Sstevel@tonic-gate if (hp->flags & DDI_DMA_READ) 1621*0Sstevel@tonic-gate hdlip->access_type |= 1622*0Sstevel@tonic-gate BOFI_DMA_R; 1623*0Sstevel@tonic-gate hdlip->len = hp->len; 1624*0Sstevel@tonic-gate hdlip->addr_cookie = 1625*0Sstevel@tonic-gate (uint64_t)(uintptr_t)hp->addr; 1626*0Sstevel@tonic-gate break; 1627*0Sstevel@tonic-gate case BOFI_INT_HDL: 1628*0Sstevel@tonic-gate hdlip->access_type = BOFI_INTR; 1629*0Sstevel@tonic-gate break; 1630*0Sstevel@tonic-gate default: 1631*0Sstevel@tonic-gate hdlip->access_type = 0; 1632*0Sstevel@tonic-gate break; 1633*0Sstevel@tonic-gate } 1634*0Sstevel@tonic-gate hdlip++; 1635*0Sstevel@tonic-gate count++; 1636*0Sstevel@tonic-gate } 1637*0Sstevel@tonic-gate } 1638*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 1639*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 1640*0Sstevel@tonic-gate err = 0; 1641*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1642*0Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 1643*0Sstevel@tonic-gate case DDI_MODEL_ILP32: 1644*0Sstevel@tonic-gate { 1645*0Sstevel@tonic-gate /* 1646*0Sstevel@tonic-gate * For use when a 32 bit app makes a call into a 1647*0Sstevel@tonic-gate * 64 bit ioctl 1648*0Sstevel@tonic-gate */ 1649*0Sstevel@tonic-gate struct bofi_get_hdl_info32 hdl_info_32; 1650*0Sstevel@tonic-gate 1651*0Sstevel@tonic-gate hdl_info_32.namesize = hdl_info.namesize; 1652*0Sstevel@tonic-gate (void) strncpy(hdl_info_32.name, hdl_info.name, 1653*0Sstevel@tonic-gate NAMESIZE); 1654*0Sstevel@tonic-gate hdl_info_32.count = hdl_info.count; 1655*0Sstevel@tonic-gate hdl_info_32.hdli = (caddr32_t)(uintptr_t)hdl_info.hdli; 1656*0Sstevel@tonic-gate if (ddi_copyout(&hdl_info_32, (void *)arg, 1657*0Sstevel@tonic-gate sizeof (hdl_info_32), mode) != 0) { 1658*0Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 1659*0Sstevel@tonic-gate if (req_count > 0) 1660*0Sstevel@tonic-gate kmem_free(hib, 1661*0Sstevel@tonic-gate req_count * sizeof (*hib)); 1662*0Sstevel@tonic-gate return (EFAULT); 1663*0Sstevel@tonic-gate } 1664*0Sstevel@tonic-gate break; 1665*0Sstevel@tonic-gate } 1666*0Sstevel@tonic-gate case DDI_MODEL_NONE: 1667*0Sstevel@tonic-gate if (ddi_copyout(&hdl_info, (void *)arg, 1668*0Sstevel@tonic-gate sizeof (hdl_info), mode) != 0) { 1669*0Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 1670*0Sstevel@tonic-gate if (req_count > 0) 1671*0Sstevel@tonic-gate kmem_free(hib, 1672*0Sstevel@tonic-gate req_count * sizeof (*hib)); 1673*0Sstevel@tonic-gate return (EFAULT); 1674*0Sstevel@tonic-gate } 1675*0Sstevel@tonic-gate break; 1676*0Sstevel@tonic-gate } 1677*0Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */ 1678*0Sstevel@tonic-gate if (ddi_copyout(&hdl_info, (void *)arg, 1679*0Sstevel@tonic-gate sizeof (hdl_info), mode) != 0) { 1680*0Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 1681*0Sstevel@tonic-gate if (req_count > 0) 1682*0Sstevel@tonic-gate kmem_free(hib, req_count * sizeof (*hib)); 1683*0Sstevel@tonic-gate return (EFAULT); 1684*0Sstevel@tonic-gate } 1685*0Sstevel@tonic-gate #endif /* ! _MULTI_DATAMODEL */ 1686*0Sstevel@tonic-gate if (count > 0) { 1687*0Sstevel@tonic-gate if (ddi_copyout(hib, hdl_info.hdli, 1688*0Sstevel@tonic-gate count * sizeof (*hib), mode) != 0) { 1689*0Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 1690*0Sstevel@tonic-gate if (req_count > 0) 1691*0Sstevel@tonic-gate kmem_free(hib, 1692*0Sstevel@tonic-gate req_count * sizeof (*hib)); 1693*0Sstevel@tonic-gate return (EFAULT); 1694*0Sstevel@tonic-gate } 1695*0Sstevel@tonic-gate } 1696*0Sstevel@tonic-gate kmem_free(namep, hdl_info.namesize+1); 1697*0Sstevel@tonic-gate if (req_count > 0) 1698*0Sstevel@tonic-gate kmem_free(hib, req_count * sizeof (*hib)); 1699*0Sstevel@tonic-gate return (err); 1700*0Sstevel@tonic-gate default: 1701*0Sstevel@tonic-gate return (ENOTTY); 1702*0Sstevel@tonic-gate } 1703*0Sstevel@tonic-gate } 1704*0Sstevel@tonic-gate 1705*0Sstevel@tonic-gate 1706*0Sstevel@tonic-gate /* 1707*0Sstevel@tonic-gate * add a new error definition 1708*0Sstevel@tonic-gate */ 1709*0Sstevel@tonic-gate static int 1710*0Sstevel@tonic-gate bofi_errdef_alloc(struct bofi_errdef *errdefp, char *namep, 1711*0Sstevel@tonic-gate struct bofi_errent *softc) 1712*0Sstevel@tonic-gate { 1713*0Sstevel@tonic-gate struct bofi_errent *ep; 1714*0Sstevel@tonic-gate struct bofi_shadow *hp; 1715*0Sstevel@tonic-gate struct bofi_link *lp; 1716*0Sstevel@tonic-gate 1717*0Sstevel@tonic-gate /* 1718*0Sstevel@tonic-gate * allocate errdef structure and put on in-use list 1719*0Sstevel@tonic-gate */ 1720*0Sstevel@tonic-gate ep = kmem_zalloc(sizeof (struct bofi_errent), KM_SLEEP); 1721*0Sstevel@tonic-gate ep->errdef = *errdefp; 1722*0Sstevel@tonic-gate ep->name = namep; 1723*0Sstevel@tonic-gate ep->errdef.errdef_handle = (uint64_t)(uintptr_t)ep; 1724*0Sstevel@tonic-gate ep->errstate.errdef_handle = (uint64_t)(uintptr_t)ep; 1725*0Sstevel@tonic-gate cv_init(&ep->cv, NULL, CV_DRIVER, NULL); 1726*0Sstevel@tonic-gate /* 1727*0Sstevel@tonic-gate * allocate space for logging 1728*0Sstevel@tonic-gate */ 1729*0Sstevel@tonic-gate ep->errdef.log.entries = 0; 1730*0Sstevel@tonic-gate ep->errdef.log.wrapcnt = 0; 1731*0Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) 1732*0Sstevel@tonic-gate ep->logbase = kmem_alloc(sizeof (struct acc_log_elem) * 1733*0Sstevel@tonic-gate ep->errdef.log.logsize, KM_SLEEP); 1734*0Sstevel@tonic-gate else 1735*0Sstevel@tonic-gate ep->logbase = NULL; 1736*0Sstevel@tonic-gate /* 1737*0Sstevel@tonic-gate * put on in-use list 1738*0Sstevel@tonic-gate */ 1739*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 1740*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 1741*0Sstevel@tonic-gate ep->next = errent_listp; 1742*0Sstevel@tonic-gate errent_listp = ep; 1743*0Sstevel@tonic-gate /* 1744*0Sstevel@tonic-gate * and add it to the per-clone list 1745*0Sstevel@tonic-gate */ 1746*0Sstevel@tonic-gate ep->cnext = softc->cnext; 1747*0Sstevel@tonic-gate softc->cnext->cprev = ep; 1748*0Sstevel@tonic-gate ep->cprev = softc; 1749*0Sstevel@tonic-gate softc->cnext = ep; 1750*0Sstevel@tonic-gate 1751*0Sstevel@tonic-gate /* 1752*0Sstevel@tonic-gate * look for corresponding shadow handle structures and if we find any 1753*0Sstevel@tonic-gate * tag this errdef structure on to their link lists. 1754*0Sstevel@tonic-gate */ 1755*0Sstevel@tonic-gate for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) { 1756*0Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == ddi_name_to_major(namep) && 1757*0Sstevel@tonic-gate hp->instance == errdefp->instance && 1758*0Sstevel@tonic-gate (((errdefp->access_type & BOFI_DMA_RW) && 1759*0Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 1760*0Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 1761*0Sstevel@tonic-gate hp->type == BOFI_DMA_HDL && 1762*0Sstevel@tonic-gate (((uintptr_t)(hp->addr + ep->errdef.offset + 1763*0Sstevel@tonic-gate ep->errdef.len) & ~LLSZMASK) > 1764*0Sstevel@tonic-gate ((uintptr_t)((hp->addr + ep->errdef.offset) + 1765*0Sstevel@tonic-gate LLSZMASK) & ~LLSZMASK))) || 1766*0Sstevel@tonic-gate ((errdefp->access_type & BOFI_INTR) && 1767*0Sstevel@tonic-gate hp->type == BOFI_INT_HDL) || 1768*0Sstevel@tonic-gate ((errdefp->access_type & BOFI_PIO_RW) && 1769*0Sstevel@tonic-gate hp->type == BOFI_ACC_HDL && 1770*0Sstevel@tonic-gate (errdefp->rnumber == -1 || 1771*0Sstevel@tonic-gate hp->rnumber == errdefp->rnumber) && 1772*0Sstevel@tonic-gate (errdefp->len == 0 || 1773*0Sstevel@tonic-gate hp->offset < errdefp->offset + errdefp->len) && 1774*0Sstevel@tonic-gate hp->offset + hp->len > errdefp->offset))) { 1775*0Sstevel@tonic-gate lp = bofi_link_freelist; 1776*0Sstevel@tonic-gate if (lp != NULL) { 1777*0Sstevel@tonic-gate bofi_link_freelist = lp->link; 1778*0Sstevel@tonic-gate lp->errentp = ep; 1779*0Sstevel@tonic-gate lp->link = hp->link; 1780*0Sstevel@tonic-gate hp->link = lp; 1781*0Sstevel@tonic-gate } 1782*0Sstevel@tonic-gate } 1783*0Sstevel@tonic-gate } 1784*0Sstevel@tonic-gate errdefp->errdef_handle = (uint64_t)(uintptr_t)ep; 1785*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 1786*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 1787*0Sstevel@tonic-gate ep->softintr_id = NULL; 1788*0Sstevel@tonic-gate return (ddi_add_softintr(our_dip, DDI_SOFTINT_MED, &ep->softintr_id, 1789*0Sstevel@tonic-gate NULL, NULL, bofi_signal, (caddr_t)&ep->errdef)); 1790*0Sstevel@tonic-gate } 1791*0Sstevel@tonic-gate 1792*0Sstevel@tonic-gate 1793*0Sstevel@tonic-gate /* 1794*0Sstevel@tonic-gate * delete existing errdef 1795*0Sstevel@tonic-gate */ 1796*0Sstevel@tonic-gate static int 1797*0Sstevel@tonic-gate bofi_errdef_free(struct bofi_errent *ep) 1798*0Sstevel@tonic-gate { 1799*0Sstevel@tonic-gate struct bofi_errent *hep, *prev_hep; 1800*0Sstevel@tonic-gate struct bofi_link *lp, *prev_lp, *next_lp; 1801*0Sstevel@tonic-gate struct bofi_shadow *hp; 1802*0Sstevel@tonic-gate 1803*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 1804*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 1805*0Sstevel@tonic-gate /* 1806*0Sstevel@tonic-gate * don't just assume its a valid ep - check that its on the 1807*0Sstevel@tonic-gate * in-use list 1808*0Sstevel@tonic-gate */ 1809*0Sstevel@tonic-gate prev_hep = NULL; 1810*0Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; ) { 1811*0Sstevel@tonic-gate if (hep == ep) 1812*0Sstevel@tonic-gate break; 1813*0Sstevel@tonic-gate prev_hep = hep; 1814*0Sstevel@tonic-gate hep = hep->next; 1815*0Sstevel@tonic-gate } 1816*0Sstevel@tonic-gate if (hep == NULL) { 1817*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 1818*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 1819*0Sstevel@tonic-gate return (EINVAL); 1820*0Sstevel@tonic-gate } 1821*0Sstevel@tonic-gate /* 1822*0Sstevel@tonic-gate * found it - delete from in-use list 1823*0Sstevel@tonic-gate */ 1824*0Sstevel@tonic-gate 1825*0Sstevel@tonic-gate if (prev_hep) 1826*0Sstevel@tonic-gate prev_hep->next = hep->next; 1827*0Sstevel@tonic-gate else 1828*0Sstevel@tonic-gate errent_listp = hep->next; 1829*0Sstevel@tonic-gate /* 1830*0Sstevel@tonic-gate * and take it off the per-clone list 1831*0Sstevel@tonic-gate */ 1832*0Sstevel@tonic-gate hep->cnext->cprev = hep->cprev; 1833*0Sstevel@tonic-gate hep->cprev->cnext = hep->cnext; 1834*0Sstevel@tonic-gate /* 1835*0Sstevel@tonic-gate * see if we are on any shadow handle link lists - and if we 1836*0Sstevel@tonic-gate * are then take us off 1837*0Sstevel@tonic-gate */ 1838*0Sstevel@tonic-gate for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) { 1839*0Sstevel@tonic-gate prev_lp = NULL; 1840*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 1841*0Sstevel@tonic-gate if (lp->errentp == ep) { 1842*0Sstevel@tonic-gate if (prev_lp) 1843*0Sstevel@tonic-gate prev_lp->link = lp->link; 1844*0Sstevel@tonic-gate else 1845*0Sstevel@tonic-gate hp->link = lp->link; 1846*0Sstevel@tonic-gate next_lp = lp->link; 1847*0Sstevel@tonic-gate lp->link = bofi_link_freelist; 1848*0Sstevel@tonic-gate bofi_link_freelist = lp; 1849*0Sstevel@tonic-gate lp = next_lp; 1850*0Sstevel@tonic-gate } else { 1851*0Sstevel@tonic-gate prev_lp = lp; 1852*0Sstevel@tonic-gate lp = lp->link; 1853*0Sstevel@tonic-gate } 1854*0Sstevel@tonic-gate } 1855*0Sstevel@tonic-gate } 1856*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 1857*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 1858*0Sstevel@tonic-gate 1859*0Sstevel@tonic-gate cv_destroy(&ep->cv); 1860*0Sstevel@tonic-gate kmem_free(ep->name, ep->errdef.namesize+1); 1861*0Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_LOG) && 1862*0Sstevel@tonic-gate ep->errdef.log.logsize && ep->logbase) /* double check */ 1863*0Sstevel@tonic-gate kmem_free(ep->logbase, 1864*0Sstevel@tonic-gate sizeof (struct acc_log_elem) * ep->errdef.log.logsize); 1865*0Sstevel@tonic-gate 1866*0Sstevel@tonic-gate if (ep->softintr_id) 1867*0Sstevel@tonic-gate ddi_remove_softintr(ep->softintr_id); 1868*0Sstevel@tonic-gate kmem_free(ep, sizeof (struct bofi_errent)); 1869*0Sstevel@tonic-gate return (0); 1870*0Sstevel@tonic-gate } 1871*0Sstevel@tonic-gate 1872*0Sstevel@tonic-gate 1873*0Sstevel@tonic-gate /* 1874*0Sstevel@tonic-gate * start all errdefs corresponding to this name and instance 1875*0Sstevel@tonic-gate */ 1876*0Sstevel@tonic-gate static void 1877*0Sstevel@tonic-gate bofi_start(struct bofi_errctl *errctlp, char *namep) 1878*0Sstevel@tonic-gate { 1879*0Sstevel@tonic-gate struct bofi_errent *ep; 1880*0Sstevel@tonic-gate 1881*0Sstevel@tonic-gate /* 1882*0Sstevel@tonic-gate * look for any errdefs with matching name and instance 1883*0Sstevel@tonic-gate */ 1884*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 1885*0Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 1886*0Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 1887*0Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 1888*0Sstevel@tonic-gate ep->state |= BOFI_DEV_ACTIVE; 1889*0Sstevel@tonic-gate (void) drv_getparm(TIME, &(ep->errdef.log.start_time)); 1890*0Sstevel@tonic-gate ep->errdef.log.stop_time = 0ul; 1891*0Sstevel@tonic-gate } 1892*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 1893*0Sstevel@tonic-gate } 1894*0Sstevel@tonic-gate 1895*0Sstevel@tonic-gate 1896*0Sstevel@tonic-gate /* 1897*0Sstevel@tonic-gate * stop all errdefs corresponding to this name and instance 1898*0Sstevel@tonic-gate */ 1899*0Sstevel@tonic-gate static void 1900*0Sstevel@tonic-gate bofi_stop(struct bofi_errctl *errctlp, char *namep) 1901*0Sstevel@tonic-gate { 1902*0Sstevel@tonic-gate struct bofi_errent *ep; 1903*0Sstevel@tonic-gate 1904*0Sstevel@tonic-gate /* 1905*0Sstevel@tonic-gate * look for any errdefs with matching name and instance 1906*0Sstevel@tonic-gate */ 1907*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 1908*0Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 1909*0Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 1910*0Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 1911*0Sstevel@tonic-gate ep->state &= ~BOFI_DEV_ACTIVE; 1912*0Sstevel@tonic-gate if (ep->errdef.log.stop_time == 0ul) 1913*0Sstevel@tonic-gate (void) drv_getparm(TIME, 1914*0Sstevel@tonic-gate &(ep->errdef.log.stop_time)); 1915*0Sstevel@tonic-gate } 1916*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 1917*0Sstevel@tonic-gate } 1918*0Sstevel@tonic-gate 1919*0Sstevel@tonic-gate 1920*0Sstevel@tonic-gate /* 1921*0Sstevel@tonic-gate * wake up any thread waiting on this errdefs 1922*0Sstevel@tonic-gate */ 1923*0Sstevel@tonic-gate static uint_t 1924*0Sstevel@tonic-gate bofi_signal(caddr_t arg) 1925*0Sstevel@tonic-gate { 1926*0Sstevel@tonic-gate struct bofi_errdef *edp = (struct bofi_errdef *)arg; 1927*0Sstevel@tonic-gate struct bofi_errent *hep; 1928*0Sstevel@tonic-gate struct bofi_errent *ep = 1929*0Sstevel@tonic-gate (struct bofi_errent *)(uintptr_t)edp->errdef_handle; 1930*0Sstevel@tonic-gate 1931*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 1932*0Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; ) { 1933*0Sstevel@tonic-gate if (hep == ep) 1934*0Sstevel@tonic-gate break; 1935*0Sstevel@tonic-gate hep = hep->next; 1936*0Sstevel@tonic-gate } 1937*0Sstevel@tonic-gate if (hep == NULL) { 1938*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 1939*0Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 1940*0Sstevel@tonic-gate } 1941*0Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_LOG) && 1942*0Sstevel@tonic-gate (edp->log.flags & BOFI_LOG_FULL)) { 1943*0Sstevel@tonic-gate edp->log.stop_time = bofi_gettime(); 1944*0Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 1945*0Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 1946*0Sstevel@tonic-gate cv_broadcast(&ep->cv); 1947*0Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 1948*0Sstevel@tonic-gate } 1949*0Sstevel@tonic-gate if (ep->errstate.msg_time != 0) { 1950*0Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 1951*0Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 1952*0Sstevel@tonic-gate cv_broadcast(&ep->cv); 1953*0Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 1954*0Sstevel@tonic-gate } 1955*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 1956*0Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 1957*0Sstevel@tonic-gate } 1958*0Sstevel@tonic-gate 1959*0Sstevel@tonic-gate 1960*0Sstevel@tonic-gate /* 1961*0Sstevel@tonic-gate * wake up all errdefs corresponding to this name and instance 1962*0Sstevel@tonic-gate */ 1963*0Sstevel@tonic-gate static void 1964*0Sstevel@tonic-gate bofi_broadcast(struct bofi_errctl *errctlp, char *namep) 1965*0Sstevel@tonic-gate { 1966*0Sstevel@tonic-gate struct bofi_errent *ep; 1967*0Sstevel@tonic-gate 1968*0Sstevel@tonic-gate /* 1969*0Sstevel@tonic-gate * look for any errdefs with matching name and instance 1970*0Sstevel@tonic-gate */ 1971*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 1972*0Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 1973*0Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 1974*0Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 1975*0Sstevel@tonic-gate /* 1976*0Sstevel@tonic-gate * wake up sleepers 1977*0Sstevel@tonic-gate */ 1978*0Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 1979*0Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 1980*0Sstevel@tonic-gate cv_broadcast(&ep->cv); 1981*0Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 1982*0Sstevel@tonic-gate } 1983*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 1984*0Sstevel@tonic-gate } 1985*0Sstevel@tonic-gate 1986*0Sstevel@tonic-gate 1987*0Sstevel@tonic-gate /* 1988*0Sstevel@tonic-gate * clear "acc_chk" for all errdefs corresponding to this name and instance 1989*0Sstevel@tonic-gate * and wake them up. 1990*0Sstevel@tonic-gate */ 1991*0Sstevel@tonic-gate static void 1992*0Sstevel@tonic-gate bofi_clear_acc_chk(struct bofi_errctl *errctlp, char *namep) 1993*0Sstevel@tonic-gate { 1994*0Sstevel@tonic-gate struct bofi_errent *ep; 1995*0Sstevel@tonic-gate 1996*0Sstevel@tonic-gate /* 1997*0Sstevel@tonic-gate * look for any errdefs with matching name and instance 1998*0Sstevel@tonic-gate */ 1999*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 2000*0Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 2001*0Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 2002*0Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 2003*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 2004*0Sstevel@tonic-gate if (ep->errdef.access_count == 0 && 2005*0Sstevel@tonic-gate ep->errdef.fail_count == 0) 2006*0Sstevel@tonic-gate ep->errdef.acc_chk = 0; 2007*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2008*0Sstevel@tonic-gate /* 2009*0Sstevel@tonic-gate * wake up sleepers 2010*0Sstevel@tonic-gate */ 2011*0Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 2012*0Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 2013*0Sstevel@tonic-gate cv_broadcast(&ep->cv); 2014*0Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 2015*0Sstevel@tonic-gate } 2016*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 2017*0Sstevel@tonic-gate } 2018*0Sstevel@tonic-gate 2019*0Sstevel@tonic-gate 2020*0Sstevel@tonic-gate /* 2021*0Sstevel@tonic-gate * set "fail_count" to 0 for all errdefs corresponding to this name and instance 2022*0Sstevel@tonic-gate * whose "access_count" has expired, set "acc_chk" to 0 and wake them up. 2023*0Sstevel@tonic-gate */ 2024*0Sstevel@tonic-gate static void 2025*0Sstevel@tonic-gate bofi_clear_errors(struct bofi_errctl *errctlp, char *namep) 2026*0Sstevel@tonic-gate { 2027*0Sstevel@tonic-gate struct bofi_errent *ep; 2028*0Sstevel@tonic-gate 2029*0Sstevel@tonic-gate /* 2030*0Sstevel@tonic-gate * look for any errdefs with matching name and instance 2031*0Sstevel@tonic-gate */ 2032*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 2033*0Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 2034*0Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 2035*0Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 2036*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 2037*0Sstevel@tonic-gate if (ep->errdef.access_count == 0) { 2038*0Sstevel@tonic-gate ep->errdef.acc_chk = 0; 2039*0Sstevel@tonic-gate ep->errdef.fail_count = 0; 2040*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2041*0Sstevel@tonic-gate if (ep->errdef.log.stop_time == 0ul) 2042*0Sstevel@tonic-gate (void) drv_getparm(TIME, 2043*0Sstevel@tonic-gate &(ep->errdef.log.stop_time)); 2044*0Sstevel@tonic-gate } else 2045*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2046*0Sstevel@tonic-gate /* 2047*0Sstevel@tonic-gate * wake up sleepers 2048*0Sstevel@tonic-gate */ 2049*0Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 2050*0Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 2051*0Sstevel@tonic-gate cv_broadcast(&ep->cv); 2052*0Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 2053*0Sstevel@tonic-gate } 2054*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 2055*0Sstevel@tonic-gate } 2056*0Sstevel@tonic-gate 2057*0Sstevel@tonic-gate 2058*0Sstevel@tonic-gate /* 2059*0Sstevel@tonic-gate * set "access_count" and "fail_count" to 0 for all errdefs corresponding to 2060*0Sstevel@tonic-gate * this name and instance, set "acc_chk" to 0, and wake them up. 2061*0Sstevel@tonic-gate */ 2062*0Sstevel@tonic-gate static void 2063*0Sstevel@tonic-gate bofi_clear_errdefs(struct bofi_errctl *errctlp, char *namep) 2064*0Sstevel@tonic-gate { 2065*0Sstevel@tonic-gate struct bofi_errent *ep; 2066*0Sstevel@tonic-gate 2067*0Sstevel@tonic-gate /* 2068*0Sstevel@tonic-gate * look for any errdefs with matching name and instance 2069*0Sstevel@tonic-gate */ 2070*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 2071*0Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) 2072*0Sstevel@tonic-gate if (strncmp(namep, ep->name, NAMESIZE) == 0 && 2073*0Sstevel@tonic-gate errctlp->instance == ep->errdef.instance) { 2074*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 2075*0Sstevel@tonic-gate ep->errdef.acc_chk = 0; 2076*0Sstevel@tonic-gate ep->errdef.access_count = 0; 2077*0Sstevel@tonic-gate ep->errdef.fail_count = 0; 2078*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2079*0Sstevel@tonic-gate if (ep->errdef.log.stop_time == 0ul) 2080*0Sstevel@tonic-gate (void) drv_getparm(TIME, 2081*0Sstevel@tonic-gate &(ep->errdef.log.stop_time)); 2082*0Sstevel@tonic-gate /* 2083*0Sstevel@tonic-gate * wake up sleepers 2084*0Sstevel@tonic-gate */ 2085*0Sstevel@tonic-gate ep->state |= BOFI_NEW_MESSAGE; 2086*0Sstevel@tonic-gate if (ep->state & BOFI_MESSAGE_WAIT) 2087*0Sstevel@tonic-gate cv_broadcast(&ep->cv); 2088*0Sstevel@tonic-gate ep->state &= ~BOFI_MESSAGE_WAIT; 2089*0Sstevel@tonic-gate } 2090*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 2091*0Sstevel@tonic-gate } 2092*0Sstevel@tonic-gate 2093*0Sstevel@tonic-gate 2094*0Sstevel@tonic-gate /* 2095*0Sstevel@tonic-gate * get state for this errdef 2096*0Sstevel@tonic-gate */ 2097*0Sstevel@tonic-gate static int 2098*0Sstevel@tonic-gate bofi_errdef_check(struct bofi_errstate *errstatep, struct acc_log_elem **logpp) 2099*0Sstevel@tonic-gate { 2100*0Sstevel@tonic-gate struct bofi_errent *hep; 2101*0Sstevel@tonic-gate struct bofi_errent *ep; 2102*0Sstevel@tonic-gate 2103*0Sstevel@tonic-gate ep = (struct bofi_errent *)(uintptr_t)errstatep->errdef_handle; 2104*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 2105*0Sstevel@tonic-gate /* 2106*0Sstevel@tonic-gate * don't just assume its a valid ep - check that its on the 2107*0Sstevel@tonic-gate * in-use list 2108*0Sstevel@tonic-gate */ 2109*0Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; hep = hep->next) 2110*0Sstevel@tonic-gate if (hep == ep) 2111*0Sstevel@tonic-gate break; 2112*0Sstevel@tonic-gate if (hep == NULL) { 2113*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 2114*0Sstevel@tonic-gate return (EINVAL); 2115*0Sstevel@tonic-gate } 2116*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 2117*0Sstevel@tonic-gate ep->errstate.access_count = ep->errdef.access_count; 2118*0Sstevel@tonic-gate ep->errstate.fail_count = ep->errdef.fail_count; 2119*0Sstevel@tonic-gate ep->errstate.acc_chk = ep->errdef.acc_chk; 2120*0Sstevel@tonic-gate ep->errstate.log = ep->errdef.log; 2121*0Sstevel@tonic-gate *logpp = ep->logbase; 2122*0Sstevel@tonic-gate *errstatep = ep->errstate; 2123*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2124*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 2125*0Sstevel@tonic-gate return (0); 2126*0Sstevel@tonic-gate } 2127*0Sstevel@tonic-gate 2128*0Sstevel@tonic-gate 2129*0Sstevel@tonic-gate /* 2130*0Sstevel@tonic-gate * Wait for a ddi_report_fault message to come back for this errdef 2131*0Sstevel@tonic-gate * Then return state for this errdef. 2132*0Sstevel@tonic-gate * fault report is intercepted by bofi_post_event, which triggers 2133*0Sstevel@tonic-gate * bofi_signal via a softint, which will wake up this routine if 2134*0Sstevel@tonic-gate * we are waiting 2135*0Sstevel@tonic-gate */ 2136*0Sstevel@tonic-gate static int 2137*0Sstevel@tonic-gate bofi_errdef_check_w(struct bofi_errstate *errstatep, 2138*0Sstevel@tonic-gate struct acc_log_elem **logpp) 2139*0Sstevel@tonic-gate { 2140*0Sstevel@tonic-gate struct bofi_errent *hep; 2141*0Sstevel@tonic-gate struct bofi_errent *ep; 2142*0Sstevel@tonic-gate int rval = 0; 2143*0Sstevel@tonic-gate 2144*0Sstevel@tonic-gate ep = (struct bofi_errent *)(uintptr_t)errstatep->errdef_handle; 2145*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 2146*0Sstevel@tonic-gate retry: 2147*0Sstevel@tonic-gate /* 2148*0Sstevel@tonic-gate * don't just assume its a valid ep - check that its on the 2149*0Sstevel@tonic-gate * in-use list 2150*0Sstevel@tonic-gate */ 2151*0Sstevel@tonic-gate for (hep = errent_listp; hep != NULL; hep = hep->next) 2152*0Sstevel@tonic-gate if (hep == ep) 2153*0Sstevel@tonic-gate break; 2154*0Sstevel@tonic-gate if (hep == NULL) { 2155*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 2156*0Sstevel@tonic-gate return (EINVAL); 2157*0Sstevel@tonic-gate } 2158*0Sstevel@tonic-gate /* 2159*0Sstevel@tonic-gate * wait for ddi_report_fault for the devinfo corresponding 2160*0Sstevel@tonic-gate * to this errdef 2161*0Sstevel@tonic-gate */ 2162*0Sstevel@tonic-gate if (rval == 0 && !(ep->state & BOFI_NEW_MESSAGE)) { 2163*0Sstevel@tonic-gate ep->state |= BOFI_MESSAGE_WAIT; 2164*0Sstevel@tonic-gate if (cv_wait_sig(&ep->cv, &bofi_low_mutex) == 0) 2165*0Sstevel@tonic-gate rval = EINTR; 2166*0Sstevel@tonic-gate goto retry; 2167*0Sstevel@tonic-gate } 2168*0Sstevel@tonic-gate ep->state &= ~BOFI_NEW_MESSAGE; 2169*0Sstevel@tonic-gate /* 2170*0Sstevel@tonic-gate * we either didn't need to sleep, we've been woken up or we've been 2171*0Sstevel@tonic-gate * signaled - either way return state now 2172*0Sstevel@tonic-gate */ 2173*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 2174*0Sstevel@tonic-gate ep->errstate.access_count = ep->errdef.access_count; 2175*0Sstevel@tonic-gate ep->errstate.fail_count = ep->errdef.fail_count; 2176*0Sstevel@tonic-gate ep->errstate.acc_chk = ep->errdef.acc_chk; 2177*0Sstevel@tonic-gate ep->errstate.log = ep->errdef.log; 2178*0Sstevel@tonic-gate *logpp = ep->logbase; 2179*0Sstevel@tonic-gate *errstatep = ep->errstate; 2180*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2181*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 2182*0Sstevel@tonic-gate return (rval); 2183*0Sstevel@tonic-gate } 2184*0Sstevel@tonic-gate 2185*0Sstevel@tonic-gate 2186*0Sstevel@tonic-gate /* 2187*0Sstevel@tonic-gate * support routine - check if requested driver is defined as under test in the 2188*0Sstevel@tonic-gate * conf file. 2189*0Sstevel@tonic-gate */ 2190*0Sstevel@tonic-gate static int 2191*0Sstevel@tonic-gate driver_under_test(dev_info_t *rdip) 2192*0Sstevel@tonic-gate { 2193*0Sstevel@tonic-gate int i; 2194*0Sstevel@tonic-gate char *rname; 2195*0Sstevel@tonic-gate major_t rmaj; 2196*0Sstevel@tonic-gate 2197*0Sstevel@tonic-gate rname = ddi_get_name(rdip); 2198*0Sstevel@tonic-gate rmaj = ddi_name_to_major(rname); 2199*0Sstevel@tonic-gate 2200*0Sstevel@tonic-gate /* 2201*0Sstevel@tonic-gate * Enforce the user to specifically request the following drivers. 2202*0Sstevel@tonic-gate */ 2203*0Sstevel@tonic-gate for (i = 0; i < driver_list_size; i += (1 + strlen(&driver_list[i]))) { 2204*0Sstevel@tonic-gate if (driver_list_neg == 0) { 2205*0Sstevel@tonic-gate if (rmaj == ddi_name_to_major(&driver_list[i])) 2206*0Sstevel@tonic-gate return (1); 2207*0Sstevel@tonic-gate } else { 2208*0Sstevel@tonic-gate if (rmaj == ddi_name_to_major(&driver_list[i+1])) 2209*0Sstevel@tonic-gate return (0); 2210*0Sstevel@tonic-gate } 2211*0Sstevel@tonic-gate } 2212*0Sstevel@tonic-gate if (driver_list_neg == 0) 2213*0Sstevel@tonic-gate return (0); 2214*0Sstevel@tonic-gate else 2215*0Sstevel@tonic-gate return (1); 2216*0Sstevel@tonic-gate 2217*0Sstevel@tonic-gate } 2218*0Sstevel@tonic-gate 2219*0Sstevel@tonic-gate 2220*0Sstevel@tonic-gate static void 2221*0Sstevel@tonic-gate log_acc_event(struct bofi_errent *ep, uint_t at, offset_t offset, off_t len, 2222*0Sstevel@tonic-gate size_t repcount, uint64_t *valuep) 2223*0Sstevel@tonic-gate { 2224*0Sstevel@tonic-gate struct bofi_errdef *edp = &(ep->errdef); 2225*0Sstevel@tonic-gate struct acc_log *log = &edp->log; 2226*0Sstevel@tonic-gate 2227*0Sstevel@tonic-gate ASSERT(log != NULL); 2228*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 2229*0Sstevel@tonic-gate 2230*0Sstevel@tonic-gate if (log->flags & BOFI_LOG_REPIO) 2231*0Sstevel@tonic-gate repcount = 1; 2232*0Sstevel@tonic-gate else if (repcount == 0 && edp->access_count > 0 && 2233*0Sstevel@tonic-gate (log->flags & BOFI_LOG_FULL) == 0) 2234*0Sstevel@tonic-gate edp->access_count += 1; 2235*0Sstevel@tonic-gate 2236*0Sstevel@tonic-gate if (repcount && log->entries < log->logsize) { 2237*0Sstevel@tonic-gate struct acc_log_elem *elem = ep->logbase + log->entries; 2238*0Sstevel@tonic-gate 2239*0Sstevel@tonic-gate if (log->flags & BOFI_LOG_TIMESTAMP) 2240*0Sstevel@tonic-gate elem->access_time = bofi_gettime(); 2241*0Sstevel@tonic-gate elem->access_type = at; 2242*0Sstevel@tonic-gate elem->offset = offset; 2243*0Sstevel@tonic-gate elem->value = valuep ? *valuep : 0ll; 2244*0Sstevel@tonic-gate elem->size = len; 2245*0Sstevel@tonic-gate elem->repcount = repcount; 2246*0Sstevel@tonic-gate ++log->entries; 2247*0Sstevel@tonic-gate if (log->entries == log->logsize) { 2248*0Sstevel@tonic-gate log->flags |= BOFI_LOG_FULL; 2249*0Sstevel@tonic-gate ddi_trigger_softintr(((struct bofi_errent *) 2250*0Sstevel@tonic-gate (uintptr_t)edp->errdef_handle)->softintr_id); 2251*0Sstevel@tonic-gate } 2252*0Sstevel@tonic-gate } 2253*0Sstevel@tonic-gate if ((log->flags & BOFI_LOG_WRAP) && edp->access_count <= 1) { 2254*0Sstevel@tonic-gate log->wrapcnt++; 2255*0Sstevel@tonic-gate edp->access_count = log->logsize; 2256*0Sstevel@tonic-gate log->entries = 0; /* wrap back to the start */ 2257*0Sstevel@tonic-gate } 2258*0Sstevel@tonic-gate } 2259*0Sstevel@tonic-gate 2260*0Sstevel@tonic-gate 2261*0Sstevel@tonic-gate /* 2262*0Sstevel@tonic-gate * got a condition match on dma read/write - check counts and corrupt 2263*0Sstevel@tonic-gate * data if necessary 2264*0Sstevel@tonic-gate * 2265*0Sstevel@tonic-gate * bofi_mutex always held when this is called. 2266*0Sstevel@tonic-gate */ 2267*0Sstevel@tonic-gate static void 2268*0Sstevel@tonic-gate do_dma_corrupt(struct bofi_shadow *hp, struct bofi_errent *ep, 2269*0Sstevel@tonic-gate uint_t synctype, off_t off, off_t length) 2270*0Sstevel@tonic-gate { 2271*0Sstevel@tonic-gate uint64_t operand; 2272*0Sstevel@tonic-gate int i; 2273*0Sstevel@tonic-gate off_t len; 2274*0Sstevel@tonic-gate caddr_t logaddr; 2275*0Sstevel@tonic-gate uint64_t *addr; 2276*0Sstevel@tonic-gate uint64_t *endaddr; 2277*0Sstevel@tonic-gate 2278*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 2279*0Sstevel@tonic-gate if ((ep->errdef.access_count || 2280*0Sstevel@tonic-gate ep->errdef.fail_count) && 2281*0Sstevel@tonic-gate (ep->errdef.access_type & BOFI_LOG)) { 2282*0Sstevel@tonic-gate uint_t atype; 2283*0Sstevel@tonic-gate 2284*0Sstevel@tonic-gate if (synctype == DDI_DMA_SYNC_FORDEV) 2285*0Sstevel@tonic-gate atype = BOFI_DMA_W; 2286*0Sstevel@tonic-gate else if (synctype == DDI_DMA_SYNC_FORCPU || 2287*0Sstevel@tonic-gate synctype == DDI_DMA_SYNC_FORKERNEL) 2288*0Sstevel@tonic-gate atype = BOFI_DMA_R; 2289*0Sstevel@tonic-gate else 2290*0Sstevel@tonic-gate atype = 0; 2291*0Sstevel@tonic-gate if ((off <= ep->errdef.offset && 2292*0Sstevel@tonic-gate off + length > ep->errdef.offset) || 2293*0Sstevel@tonic-gate (off > ep->errdef.offset && 2294*0Sstevel@tonic-gate off < ep->errdef.offset + ep->errdef.len)) { 2295*0Sstevel@tonic-gate logaddr = (caddr_t)((uintptr_t)(hp->addr + 2296*0Sstevel@tonic-gate off + LLSZMASK) & ~LLSZMASK); 2297*0Sstevel@tonic-gate 2298*0Sstevel@tonic-gate log_acc_event(ep, atype, logaddr - hp->addr, 2299*0Sstevel@tonic-gate length, 1, 0); 2300*0Sstevel@tonic-gate } 2301*0Sstevel@tonic-gate } 2302*0Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 2303*0Sstevel@tonic-gate ep->errdef.access_count--; 2304*0Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 2305*0Sstevel@tonic-gate ep->errdef.fail_count--; 2306*0Sstevel@tonic-gate ep->errdef.access_count = 0; 2307*0Sstevel@tonic-gate /* 2308*0Sstevel@tonic-gate * OK do the corruption 2309*0Sstevel@tonic-gate */ 2310*0Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 2311*0Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 2312*0Sstevel@tonic-gate /* 2313*0Sstevel@tonic-gate * work out how much to corrupt 2314*0Sstevel@tonic-gate * 2315*0Sstevel@tonic-gate * Make sure endaddr isn't greater than hp->addr + hp->len. 2316*0Sstevel@tonic-gate * If endaddr becomes less than addr len becomes negative 2317*0Sstevel@tonic-gate * and the following loop isn't entered. 2318*0Sstevel@tonic-gate */ 2319*0Sstevel@tonic-gate addr = (uint64_t *)((uintptr_t)((hp->addr + 2320*0Sstevel@tonic-gate ep->errdef.offset) + LLSZMASK) & ~LLSZMASK); 2321*0Sstevel@tonic-gate endaddr = (uint64_t *)((uintptr_t)(hp->addr + min(hp->len, 2322*0Sstevel@tonic-gate ep->errdef.offset + ep->errdef.len)) & ~LLSZMASK); 2323*0Sstevel@tonic-gate len = endaddr - addr; 2324*0Sstevel@tonic-gate operand = ep->errdef.operand; 2325*0Sstevel@tonic-gate switch (ep->errdef.optype) { 2326*0Sstevel@tonic-gate case BOFI_EQUAL : 2327*0Sstevel@tonic-gate for (i = 0; i < len; i++) 2328*0Sstevel@tonic-gate *(addr + i) = operand; 2329*0Sstevel@tonic-gate break; 2330*0Sstevel@tonic-gate case BOFI_AND : 2331*0Sstevel@tonic-gate for (i = 0; i < len; i++) 2332*0Sstevel@tonic-gate *(addr + i) &= operand; 2333*0Sstevel@tonic-gate break; 2334*0Sstevel@tonic-gate case BOFI_OR : 2335*0Sstevel@tonic-gate for (i = 0; i < len; i++) 2336*0Sstevel@tonic-gate *(addr + i) |= operand; 2337*0Sstevel@tonic-gate break; 2338*0Sstevel@tonic-gate case BOFI_XOR : 2339*0Sstevel@tonic-gate for (i = 0; i < len; i++) 2340*0Sstevel@tonic-gate *(addr + i) ^= operand; 2341*0Sstevel@tonic-gate break; 2342*0Sstevel@tonic-gate default: 2343*0Sstevel@tonic-gate /* do nothing */ 2344*0Sstevel@tonic-gate break; 2345*0Sstevel@tonic-gate } 2346*0Sstevel@tonic-gate } 2347*0Sstevel@tonic-gate } 2348*0Sstevel@tonic-gate 2349*0Sstevel@tonic-gate 2350*0Sstevel@tonic-gate static uint64_t do_bofi_rd8(struct bofi_shadow *, caddr_t); 2351*0Sstevel@tonic-gate static uint64_t do_bofi_rd16(struct bofi_shadow *, caddr_t); 2352*0Sstevel@tonic-gate static uint64_t do_bofi_rd32(struct bofi_shadow *, caddr_t); 2353*0Sstevel@tonic-gate static uint64_t do_bofi_rd64(struct bofi_shadow *, caddr_t); 2354*0Sstevel@tonic-gate 2355*0Sstevel@tonic-gate 2356*0Sstevel@tonic-gate /* 2357*0Sstevel@tonic-gate * check all errdefs linked to this shadow handle. If we've got a condition 2358*0Sstevel@tonic-gate * match check counts and corrupt data if necessary 2359*0Sstevel@tonic-gate * 2360*0Sstevel@tonic-gate * bofi_mutex always held when this is called. 2361*0Sstevel@tonic-gate * 2362*0Sstevel@tonic-gate * because of possibility of BOFI_NO_TRANSFER, we couldn't get data 2363*0Sstevel@tonic-gate * from io-space before calling this, so we pass in the func to do the 2364*0Sstevel@tonic-gate * transfer as a parameter. 2365*0Sstevel@tonic-gate */ 2366*0Sstevel@tonic-gate static uint64_t 2367*0Sstevel@tonic-gate do_pior_corrupt(struct bofi_shadow *hp, caddr_t addr, 2368*0Sstevel@tonic-gate uint64_t (*func)(), size_t repcount, size_t accsize) 2369*0Sstevel@tonic-gate { 2370*0Sstevel@tonic-gate struct bofi_errent *ep; 2371*0Sstevel@tonic-gate struct bofi_link *lp; 2372*0Sstevel@tonic-gate uint64_t operand; 2373*0Sstevel@tonic-gate uintptr_t minlen; 2374*0Sstevel@tonic-gate intptr_t base; 2375*0Sstevel@tonic-gate int done_get = 0; 2376*0Sstevel@tonic-gate uint64_t get_val, gv; 2377*0Sstevel@tonic-gate 2378*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 2379*0Sstevel@tonic-gate /* 2380*0Sstevel@tonic-gate * check through all errdefs associated with this shadow handle 2381*0Sstevel@tonic-gate */ 2382*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 2383*0Sstevel@tonic-gate ep = lp->errentp; 2384*0Sstevel@tonic-gate if (ep->errdef.len == 0) 2385*0Sstevel@tonic-gate minlen = hp->len; 2386*0Sstevel@tonic-gate else 2387*0Sstevel@tonic-gate minlen = min(hp->len, ep->errdef.len); 2388*0Sstevel@tonic-gate base = addr - hp->addr - ep->errdef.offset + hp->offset; 2389*0Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_PIO_R) && 2390*0Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE) && 2391*0Sstevel@tonic-gate base >= 0 && base < minlen) { 2392*0Sstevel@tonic-gate /* 2393*0Sstevel@tonic-gate * condition match for pio read 2394*0Sstevel@tonic-gate */ 2395*0Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 2396*0Sstevel@tonic-gate ep->errdef.access_count--; 2397*0Sstevel@tonic-gate if (done_get == 0) { 2398*0Sstevel@tonic-gate done_get = 1; 2399*0Sstevel@tonic-gate gv = get_val = func(hp, addr); 2400*0Sstevel@tonic-gate } 2401*0Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) { 2402*0Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_R, 2403*0Sstevel@tonic-gate addr - hp->addr, 2404*0Sstevel@tonic-gate accsize, repcount, &gv); 2405*0Sstevel@tonic-gate } 2406*0Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 2407*0Sstevel@tonic-gate ep->errdef.fail_count--; 2408*0Sstevel@tonic-gate ep->errdef.access_count = 0; 2409*0Sstevel@tonic-gate /* 2410*0Sstevel@tonic-gate * OK do corruption 2411*0Sstevel@tonic-gate */ 2412*0Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 2413*0Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 2414*0Sstevel@tonic-gate operand = ep->errdef.operand; 2415*0Sstevel@tonic-gate if (done_get == 0) { 2416*0Sstevel@tonic-gate if (ep->errdef.optype == 2417*0Sstevel@tonic-gate BOFI_NO_TRANSFER) 2418*0Sstevel@tonic-gate /* 2419*0Sstevel@tonic-gate * no transfer - bomb out 2420*0Sstevel@tonic-gate */ 2421*0Sstevel@tonic-gate return (operand); 2422*0Sstevel@tonic-gate done_get = 1; 2423*0Sstevel@tonic-gate gv = get_val = func(hp, addr); 2424*0Sstevel@tonic-gate 2425*0Sstevel@tonic-gate } 2426*0Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) { 2427*0Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_R, 2428*0Sstevel@tonic-gate addr - hp->addr, 2429*0Sstevel@tonic-gate accsize, repcount, &gv); 2430*0Sstevel@tonic-gate } 2431*0Sstevel@tonic-gate switch (ep->errdef.optype) { 2432*0Sstevel@tonic-gate case BOFI_EQUAL : 2433*0Sstevel@tonic-gate get_val = operand; 2434*0Sstevel@tonic-gate break; 2435*0Sstevel@tonic-gate case BOFI_AND : 2436*0Sstevel@tonic-gate get_val &= operand; 2437*0Sstevel@tonic-gate break; 2438*0Sstevel@tonic-gate case BOFI_OR : 2439*0Sstevel@tonic-gate get_val |= operand; 2440*0Sstevel@tonic-gate break; 2441*0Sstevel@tonic-gate case BOFI_XOR : 2442*0Sstevel@tonic-gate get_val ^= operand; 2443*0Sstevel@tonic-gate break; 2444*0Sstevel@tonic-gate default: 2445*0Sstevel@tonic-gate /* do nothing */ 2446*0Sstevel@tonic-gate break; 2447*0Sstevel@tonic-gate } 2448*0Sstevel@tonic-gate } 2449*0Sstevel@tonic-gate } 2450*0Sstevel@tonic-gate } 2451*0Sstevel@tonic-gate if (done_get == 0) 2452*0Sstevel@tonic-gate return (func(hp, addr)); 2453*0Sstevel@tonic-gate else 2454*0Sstevel@tonic-gate return (get_val); 2455*0Sstevel@tonic-gate } 2456*0Sstevel@tonic-gate 2457*0Sstevel@tonic-gate 2458*0Sstevel@tonic-gate /* 2459*0Sstevel@tonic-gate * check all errdefs linked to this shadow handle. If we've got a condition 2460*0Sstevel@tonic-gate * match check counts and corrupt data if necessary 2461*0Sstevel@tonic-gate * 2462*0Sstevel@tonic-gate * bofi_mutex always held when this is called. 2463*0Sstevel@tonic-gate * 2464*0Sstevel@tonic-gate * because of possibility of BOFI_NO_TRANSFER, we return 0 if no data 2465*0Sstevel@tonic-gate * is to be written out to io-space, 1 otherwise 2466*0Sstevel@tonic-gate */ 2467*0Sstevel@tonic-gate static int 2468*0Sstevel@tonic-gate do_piow_corrupt(struct bofi_shadow *hp, caddr_t addr, uint64_t *valuep, 2469*0Sstevel@tonic-gate size_t size, size_t repcount) 2470*0Sstevel@tonic-gate { 2471*0Sstevel@tonic-gate struct bofi_errent *ep; 2472*0Sstevel@tonic-gate struct bofi_link *lp; 2473*0Sstevel@tonic-gate uintptr_t minlen; 2474*0Sstevel@tonic-gate intptr_t base; 2475*0Sstevel@tonic-gate uint64_t v = *valuep; 2476*0Sstevel@tonic-gate 2477*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 2478*0Sstevel@tonic-gate /* 2479*0Sstevel@tonic-gate * check through all errdefs associated with this shadow handle 2480*0Sstevel@tonic-gate */ 2481*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 2482*0Sstevel@tonic-gate ep = lp->errentp; 2483*0Sstevel@tonic-gate if (ep->errdef.len == 0) 2484*0Sstevel@tonic-gate minlen = hp->len; 2485*0Sstevel@tonic-gate else 2486*0Sstevel@tonic-gate minlen = min(hp->len, ep->errdef.len); 2487*0Sstevel@tonic-gate base = (caddr_t)addr - hp->addr - ep->errdef.offset +hp->offset; 2488*0Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_PIO_W) && 2489*0Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE) && 2490*0Sstevel@tonic-gate base >= 0 && base < minlen) { 2491*0Sstevel@tonic-gate /* 2492*0Sstevel@tonic-gate * condition match for pio write 2493*0Sstevel@tonic-gate */ 2494*0Sstevel@tonic-gate 2495*0Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 2496*0Sstevel@tonic-gate ep->errdef.access_count--; 2497*0Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) 2498*0Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_W, 2499*0Sstevel@tonic-gate addr - hp->addr, size, 2500*0Sstevel@tonic-gate repcount, &v); 2501*0Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 2502*0Sstevel@tonic-gate ep->errdef.fail_count--; 2503*0Sstevel@tonic-gate ep->errdef.access_count = 0; 2504*0Sstevel@tonic-gate if (ep->errdef.access_type & BOFI_LOG) 2505*0Sstevel@tonic-gate log_acc_event(ep, BOFI_PIO_W, 2506*0Sstevel@tonic-gate addr - hp->addr, size, 2507*0Sstevel@tonic-gate repcount, &v); 2508*0Sstevel@tonic-gate /* 2509*0Sstevel@tonic-gate * OK do corruption 2510*0Sstevel@tonic-gate */ 2511*0Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 2512*0Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 2513*0Sstevel@tonic-gate switch (ep->errdef.optype) { 2514*0Sstevel@tonic-gate case BOFI_EQUAL : 2515*0Sstevel@tonic-gate *valuep = ep->errdef.operand; 2516*0Sstevel@tonic-gate break; 2517*0Sstevel@tonic-gate case BOFI_AND : 2518*0Sstevel@tonic-gate *valuep &= ep->errdef.operand; 2519*0Sstevel@tonic-gate break; 2520*0Sstevel@tonic-gate case BOFI_OR : 2521*0Sstevel@tonic-gate *valuep |= ep->errdef.operand; 2522*0Sstevel@tonic-gate break; 2523*0Sstevel@tonic-gate case BOFI_XOR : 2524*0Sstevel@tonic-gate *valuep ^= ep->errdef.operand; 2525*0Sstevel@tonic-gate break; 2526*0Sstevel@tonic-gate case BOFI_NO_TRANSFER : 2527*0Sstevel@tonic-gate /* 2528*0Sstevel@tonic-gate * no transfer - bomb out 2529*0Sstevel@tonic-gate */ 2530*0Sstevel@tonic-gate return (0); 2531*0Sstevel@tonic-gate default: 2532*0Sstevel@tonic-gate /* do nothing */ 2533*0Sstevel@tonic-gate break; 2534*0Sstevel@tonic-gate } 2535*0Sstevel@tonic-gate } 2536*0Sstevel@tonic-gate } 2537*0Sstevel@tonic-gate } 2538*0Sstevel@tonic-gate return (1); 2539*0Sstevel@tonic-gate } 2540*0Sstevel@tonic-gate 2541*0Sstevel@tonic-gate 2542*0Sstevel@tonic-gate static uint64_t 2543*0Sstevel@tonic-gate do_bofi_rd8(struct bofi_shadow *hp, caddr_t addr) 2544*0Sstevel@tonic-gate { 2545*0Sstevel@tonic-gate return (hp->save.acc.ahi_get8(&hp->save.acc, (uint8_t *)addr)); 2546*0Sstevel@tonic-gate } 2547*0Sstevel@tonic-gate 2548*0Sstevel@tonic-gate #define BOFI_READ_CHECKS(type) \ 2549*0Sstevel@tonic-gate if (bofi_ddi_check) \ 2550*0Sstevel@tonic-gate addr = (type *)((uintptr_t)addr - 64 + hp->addr); \ 2551*0Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)addr < hp->addr || \ 2552*0Sstevel@tonic-gate (caddr_t)addr - hp->addr >= hp->len)) { \ 2553*0Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 2554*0Sstevel@tonic-gate "ddi_get() out of range addr %p not in %p/%llx", \ 2555*0Sstevel@tonic-gate (void *)addr, (void *)hp->addr, hp->len); \ 2556*0Sstevel@tonic-gate return (0); \ 2557*0Sstevel@tonic-gate } 2558*0Sstevel@tonic-gate 2559*0Sstevel@tonic-gate /* 2560*0Sstevel@tonic-gate * our getb() routine - use tryenter 2561*0Sstevel@tonic-gate */ 2562*0Sstevel@tonic-gate static uint8_t 2563*0Sstevel@tonic-gate bofi_rd8(ddi_acc_impl_t *handle, uint8_t *addr) 2564*0Sstevel@tonic-gate { 2565*0Sstevel@tonic-gate struct bofi_shadow *hp; 2566*0Sstevel@tonic-gate uint8_t retval; 2567*0Sstevel@tonic-gate 2568*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2569*0Sstevel@tonic-gate BOFI_READ_CHECKS(uint8_t) 2570*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 2571*0Sstevel@tonic-gate return (hp->save.acc.ahi_get8(&hp->save.acc, addr)); 2572*0Sstevel@tonic-gate retval = (uint8_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd8, 1, 2573*0Sstevel@tonic-gate 1); 2574*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2575*0Sstevel@tonic-gate return (retval); 2576*0Sstevel@tonic-gate } 2577*0Sstevel@tonic-gate 2578*0Sstevel@tonic-gate 2579*0Sstevel@tonic-gate static uint64_t 2580*0Sstevel@tonic-gate do_bofi_rd16(struct bofi_shadow *hp, caddr_t addr) 2581*0Sstevel@tonic-gate { 2582*0Sstevel@tonic-gate return (hp->save.acc.ahi_get16(&hp->save.acc, (uint16_t *)addr)); 2583*0Sstevel@tonic-gate } 2584*0Sstevel@tonic-gate 2585*0Sstevel@tonic-gate 2586*0Sstevel@tonic-gate /* 2587*0Sstevel@tonic-gate * our getw() routine - use tryenter 2588*0Sstevel@tonic-gate */ 2589*0Sstevel@tonic-gate static uint16_t 2590*0Sstevel@tonic-gate bofi_rd16(ddi_acc_impl_t *handle, uint16_t *addr) 2591*0Sstevel@tonic-gate { 2592*0Sstevel@tonic-gate struct bofi_shadow *hp; 2593*0Sstevel@tonic-gate uint16_t retval; 2594*0Sstevel@tonic-gate 2595*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2596*0Sstevel@tonic-gate BOFI_READ_CHECKS(uint16_t) 2597*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 2598*0Sstevel@tonic-gate return (hp->save.acc.ahi_get16(&hp->save.acc, addr)); 2599*0Sstevel@tonic-gate retval = (uint16_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd16, 1, 2600*0Sstevel@tonic-gate 2); 2601*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2602*0Sstevel@tonic-gate return (retval); 2603*0Sstevel@tonic-gate } 2604*0Sstevel@tonic-gate 2605*0Sstevel@tonic-gate 2606*0Sstevel@tonic-gate static uint64_t 2607*0Sstevel@tonic-gate do_bofi_rd32(struct bofi_shadow *hp, caddr_t addr) 2608*0Sstevel@tonic-gate { 2609*0Sstevel@tonic-gate return (hp->save.acc.ahi_get32(&hp->save.acc, (uint32_t *)addr)); 2610*0Sstevel@tonic-gate } 2611*0Sstevel@tonic-gate 2612*0Sstevel@tonic-gate 2613*0Sstevel@tonic-gate /* 2614*0Sstevel@tonic-gate * our getl() routine - use tryenter 2615*0Sstevel@tonic-gate */ 2616*0Sstevel@tonic-gate static uint32_t 2617*0Sstevel@tonic-gate bofi_rd32(ddi_acc_impl_t *handle, uint32_t *addr) 2618*0Sstevel@tonic-gate { 2619*0Sstevel@tonic-gate struct bofi_shadow *hp; 2620*0Sstevel@tonic-gate uint32_t retval; 2621*0Sstevel@tonic-gate 2622*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2623*0Sstevel@tonic-gate BOFI_READ_CHECKS(uint32_t) 2624*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 2625*0Sstevel@tonic-gate return (hp->save.acc.ahi_get32(&hp->save.acc, addr)); 2626*0Sstevel@tonic-gate retval = (uint32_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd32, 1, 2627*0Sstevel@tonic-gate 4); 2628*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2629*0Sstevel@tonic-gate return (retval); 2630*0Sstevel@tonic-gate } 2631*0Sstevel@tonic-gate 2632*0Sstevel@tonic-gate 2633*0Sstevel@tonic-gate static uint64_t 2634*0Sstevel@tonic-gate do_bofi_rd64(struct bofi_shadow *hp, caddr_t addr) 2635*0Sstevel@tonic-gate { 2636*0Sstevel@tonic-gate return (hp->save.acc.ahi_get64(&hp->save.acc, (uint64_t *)addr)); 2637*0Sstevel@tonic-gate } 2638*0Sstevel@tonic-gate 2639*0Sstevel@tonic-gate 2640*0Sstevel@tonic-gate /* 2641*0Sstevel@tonic-gate * our getll() routine - use tryenter 2642*0Sstevel@tonic-gate */ 2643*0Sstevel@tonic-gate static uint64_t 2644*0Sstevel@tonic-gate bofi_rd64(ddi_acc_impl_t *handle, uint64_t *addr) 2645*0Sstevel@tonic-gate { 2646*0Sstevel@tonic-gate struct bofi_shadow *hp; 2647*0Sstevel@tonic-gate uint64_t retval; 2648*0Sstevel@tonic-gate 2649*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2650*0Sstevel@tonic-gate BOFI_READ_CHECKS(uint64_t) 2651*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) 2652*0Sstevel@tonic-gate return (hp->save.acc.ahi_get64(&hp->save.acc, addr)); 2653*0Sstevel@tonic-gate retval = (uint64_t)do_pior_corrupt(hp, (caddr_t)addr, do_bofi_rd64, 1, 2654*0Sstevel@tonic-gate 8); 2655*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2656*0Sstevel@tonic-gate return (retval); 2657*0Sstevel@tonic-gate } 2658*0Sstevel@tonic-gate 2659*0Sstevel@tonic-gate #define BOFI_WRITE_TESTS(type) \ 2660*0Sstevel@tonic-gate if (bofi_ddi_check) \ 2661*0Sstevel@tonic-gate addr = (type *)((uintptr_t)addr - 64 + hp->addr); \ 2662*0Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)addr < hp->addr || \ 2663*0Sstevel@tonic-gate (caddr_t)addr - hp->addr >= hp->len)) { \ 2664*0Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 2665*0Sstevel@tonic-gate "ddi_put() out of range addr %p not in %p/%llx\n", \ 2666*0Sstevel@tonic-gate (void *)addr, (void *)hp->addr, hp->len); \ 2667*0Sstevel@tonic-gate return; \ 2668*0Sstevel@tonic-gate } 2669*0Sstevel@tonic-gate 2670*0Sstevel@tonic-gate /* 2671*0Sstevel@tonic-gate * our putb() routine - use tryenter 2672*0Sstevel@tonic-gate */ 2673*0Sstevel@tonic-gate static void 2674*0Sstevel@tonic-gate bofi_wr8(ddi_acc_impl_t *handle, uint8_t *addr, uint8_t value) 2675*0Sstevel@tonic-gate { 2676*0Sstevel@tonic-gate struct bofi_shadow *hp; 2677*0Sstevel@tonic-gate uint64_t llvalue = value; 2678*0Sstevel@tonic-gate 2679*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2680*0Sstevel@tonic-gate BOFI_WRITE_TESTS(uint8_t) 2681*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2682*0Sstevel@tonic-gate hp->save.acc.ahi_put8(&hp->save.acc, addr, (uint8_t)llvalue); 2683*0Sstevel@tonic-gate return; 2684*0Sstevel@tonic-gate } 2685*0Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 1, 1)) 2686*0Sstevel@tonic-gate hp->save.acc.ahi_put8(&hp->save.acc, addr, (uint8_t)llvalue); 2687*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2688*0Sstevel@tonic-gate } 2689*0Sstevel@tonic-gate 2690*0Sstevel@tonic-gate 2691*0Sstevel@tonic-gate /* 2692*0Sstevel@tonic-gate * our putw() routine - use tryenter 2693*0Sstevel@tonic-gate */ 2694*0Sstevel@tonic-gate static void 2695*0Sstevel@tonic-gate bofi_wr16(ddi_acc_impl_t *handle, uint16_t *addr, uint16_t value) 2696*0Sstevel@tonic-gate { 2697*0Sstevel@tonic-gate struct bofi_shadow *hp; 2698*0Sstevel@tonic-gate uint64_t llvalue = value; 2699*0Sstevel@tonic-gate 2700*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2701*0Sstevel@tonic-gate BOFI_WRITE_TESTS(uint16_t) 2702*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2703*0Sstevel@tonic-gate hp->save.acc.ahi_put16(&hp->save.acc, addr, (uint16_t)llvalue); 2704*0Sstevel@tonic-gate return; 2705*0Sstevel@tonic-gate } 2706*0Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 2, 1)) 2707*0Sstevel@tonic-gate hp->save.acc.ahi_put16(&hp->save.acc, addr, (uint16_t)llvalue); 2708*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2709*0Sstevel@tonic-gate } 2710*0Sstevel@tonic-gate 2711*0Sstevel@tonic-gate 2712*0Sstevel@tonic-gate /* 2713*0Sstevel@tonic-gate * our putl() routine - use tryenter 2714*0Sstevel@tonic-gate */ 2715*0Sstevel@tonic-gate static void 2716*0Sstevel@tonic-gate bofi_wr32(ddi_acc_impl_t *handle, uint32_t *addr, uint32_t value) 2717*0Sstevel@tonic-gate { 2718*0Sstevel@tonic-gate struct bofi_shadow *hp; 2719*0Sstevel@tonic-gate uint64_t llvalue = value; 2720*0Sstevel@tonic-gate 2721*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2722*0Sstevel@tonic-gate BOFI_WRITE_TESTS(uint32_t) 2723*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2724*0Sstevel@tonic-gate hp->save.acc.ahi_put32(&hp->save.acc, addr, (uint32_t)llvalue); 2725*0Sstevel@tonic-gate return; 2726*0Sstevel@tonic-gate } 2727*0Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 4, 1)) 2728*0Sstevel@tonic-gate hp->save.acc.ahi_put32(&hp->save.acc, addr, (uint32_t)llvalue); 2729*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2730*0Sstevel@tonic-gate } 2731*0Sstevel@tonic-gate 2732*0Sstevel@tonic-gate 2733*0Sstevel@tonic-gate /* 2734*0Sstevel@tonic-gate * our putll() routine - use tryenter 2735*0Sstevel@tonic-gate */ 2736*0Sstevel@tonic-gate static void 2737*0Sstevel@tonic-gate bofi_wr64(ddi_acc_impl_t *handle, uint64_t *addr, uint64_t value) 2738*0Sstevel@tonic-gate { 2739*0Sstevel@tonic-gate struct bofi_shadow *hp; 2740*0Sstevel@tonic-gate uint64_t llvalue = value; 2741*0Sstevel@tonic-gate 2742*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2743*0Sstevel@tonic-gate BOFI_WRITE_TESTS(uint64_t) 2744*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2745*0Sstevel@tonic-gate hp->save.acc.ahi_put64(&hp->save.acc, addr, (uint64_t)llvalue); 2746*0Sstevel@tonic-gate return; 2747*0Sstevel@tonic-gate } 2748*0Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 8, 1)) 2749*0Sstevel@tonic-gate hp->save.acc.ahi_put64(&hp->save.acc, addr, (uint64_t)llvalue); 2750*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2751*0Sstevel@tonic-gate } 2752*0Sstevel@tonic-gate 2753*0Sstevel@tonic-gate #define BOFI_REP_READ_TESTS(type) \ 2754*0Sstevel@tonic-gate if (bofi_ddi_check) \ 2755*0Sstevel@tonic-gate dev_addr = (type *)((uintptr_t)dev_addr - 64 + hp->addr); \ 2756*0Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)dev_addr < hp->addr || \ 2757*0Sstevel@tonic-gate (caddr_t)(dev_addr + repcount) - hp->addr > hp->len)) { \ 2758*0Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 2759*0Sstevel@tonic-gate "ddi_rep_get() out of range addr %p not in %p/%llx\n", \ 2760*0Sstevel@tonic-gate (void *)dev_addr, (void *)hp->addr, hp->len); \ 2761*0Sstevel@tonic-gate if ((caddr_t)dev_addr < hp->addr || \ 2762*0Sstevel@tonic-gate (caddr_t)dev_addr - hp->addr >= hp->len) \ 2763*0Sstevel@tonic-gate return; \ 2764*0Sstevel@tonic-gate repcount = (type *)(hp->addr + hp->len) - dev_addr; \ 2765*0Sstevel@tonic-gate } 2766*0Sstevel@tonic-gate 2767*0Sstevel@tonic-gate /* 2768*0Sstevel@tonic-gate * our rep_getb() routine - use tryenter 2769*0Sstevel@tonic-gate */ 2770*0Sstevel@tonic-gate static void 2771*0Sstevel@tonic-gate bofi_rep_rd8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr, 2772*0Sstevel@tonic-gate size_t repcount, uint_t flags) 2773*0Sstevel@tonic-gate { 2774*0Sstevel@tonic-gate struct bofi_shadow *hp; 2775*0Sstevel@tonic-gate int i; 2776*0Sstevel@tonic-gate uint8_t *addr; 2777*0Sstevel@tonic-gate 2778*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2779*0Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint8_t) 2780*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2781*0Sstevel@tonic-gate hp->save.acc.ahi_rep_get8(&hp->save.acc, host_addr, dev_addr, 2782*0Sstevel@tonic-gate repcount, flags); 2783*0Sstevel@tonic-gate return; 2784*0Sstevel@tonic-gate } 2785*0Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 2786*0Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 2787*0Sstevel@tonic-gate *(host_addr + i) = (uint8_t)do_pior_corrupt(hp, (caddr_t)addr, 2788*0Sstevel@tonic-gate do_bofi_rd8, i ? 0 : repcount, 1); 2789*0Sstevel@tonic-gate } 2790*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2791*0Sstevel@tonic-gate } 2792*0Sstevel@tonic-gate 2793*0Sstevel@tonic-gate 2794*0Sstevel@tonic-gate /* 2795*0Sstevel@tonic-gate * our rep_getw() routine - use tryenter 2796*0Sstevel@tonic-gate */ 2797*0Sstevel@tonic-gate static void 2798*0Sstevel@tonic-gate bofi_rep_rd16(ddi_acc_impl_t *handle, uint16_t *host_addr, 2799*0Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 2800*0Sstevel@tonic-gate { 2801*0Sstevel@tonic-gate struct bofi_shadow *hp; 2802*0Sstevel@tonic-gate int i; 2803*0Sstevel@tonic-gate uint16_t *addr; 2804*0Sstevel@tonic-gate 2805*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2806*0Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint16_t) 2807*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2808*0Sstevel@tonic-gate hp->save.acc.ahi_rep_get16(&hp->save.acc, host_addr, dev_addr, 2809*0Sstevel@tonic-gate repcount, flags); 2810*0Sstevel@tonic-gate return; 2811*0Sstevel@tonic-gate } 2812*0Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 2813*0Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 2814*0Sstevel@tonic-gate *(host_addr + i) = (uint16_t)do_pior_corrupt(hp, (caddr_t)addr, 2815*0Sstevel@tonic-gate do_bofi_rd16, i ? 0 : repcount, 2); 2816*0Sstevel@tonic-gate } 2817*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2818*0Sstevel@tonic-gate } 2819*0Sstevel@tonic-gate 2820*0Sstevel@tonic-gate 2821*0Sstevel@tonic-gate /* 2822*0Sstevel@tonic-gate * our rep_getl() routine - use tryenter 2823*0Sstevel@tonic-gate */ 2824*0Sstevel@tonic-gate static void 2825*0Sstevel@tonic-gate bofi_rep_rd32(ddi_acc_impl_t *handle, uint32_t *host_addr, 2826*0Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 2827*0Sstevel@tonic-gate { 2828*0Sstevel@tonic-gate struct bofi_shadow *hp; 2829*0Sstevel@tonic-gate int i; 2830*0Sstevel@tonic-gate uint32_t *addr; 2831*0Sstevel@tonic-gate 2832*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2833*0Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint32_t) 2834*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2835*0Sstevel@tonic-gate hp->save.acc.ahi_rep_get32(&hp->save.acc, host_addr, dev_addr, 2836*0Sstevel@tonic-gate repcount, flags); 2837*0Sstevel@tonic-gate return; 2838*0Sstevel@tonic-gate } 2839*0Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 2840*0Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 2841*0Sstevel@tonic-gate *(host_addr + i) = (uint32_t)do_pior_corrupt(hp, (caddr_t)addr, 2842*0Sstevel@tonic-gate do_bofi_rd32, i ? 0 : repcount, 4); 2843*0Sstevel@tonic-gate } 2844*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2845*0Sstevel@tonic-gate } 2846*0Sstevel@tonic-gate 2847*0Sstevel@tonic-gate 2848*0Sstevel@tonic-gate /* 2849*0Sstevel@tonic-gate * our rep_getll() routine - use tryenter 2850*0Sstevel@tonic-gate */ 2851*0Sstevel@tonic-gate static void 2852*0Sstevel@tonic-gate bofi_rep_rd64(ddi_acc_impl_t *handle, uint64_t *host_addr, 2853*0Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 2854*0Sstevel@tonic-gate { 2855*0Sstevel@tonic-gate struct bofi_shadow *hp; 2856*0Sstevel@tonic-gate int i; 2857*0Sstevel@tonic-gate uint64_t *addr; 2858*0Sstevel@tonic-gate 2859*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2860*0Sstevel@tonic-gate BOFI_REP_READ_TESTS(uint64_t) 2861*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2862*0Sstevel@tonic-gate hp->save.acc.ahi_rep_get64(&hp->save.acc, host_addr, dev_addr, 2863*0Sstevel@tonic-gate repcount, flags); 2864*0Sstevel@tonic-gate return; 2865*0Sstevel@tonic-gate } 2866*0Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 2867*0Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 2868*0Sstevel@tonic-gate *(host_addr + i) = (uint64_t)do_pior_corrupt(hp, (caddr_t)addr, 2869*0Sstevel@tonic-gate do_bofi_rd64, i ? 0 : repcount, 8); 2870*0Sstevel@tonic-gate } 2871*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2872*0Sstevel@tonic-gate } 2873*0Sstevel@tonic-gate 2874*0Sstevel@tonic-gate #define BOFI_REP_WRITE_TESTS(type) \ 2875*0Sstevel@tonic-gate if (bofi_ddi_check) \ 2876*0Sstevel@tonic-gate dev_addr = (type *)((uintptr_t)dev_addr - 64 + hp->addr); \ 2877*0Sstevel@tonic-gate if (bofi_range_check && ((caddr_t)dev_addr < hp->addr || \ 2878*0Sstevel@tonic-gate (caddr_t)(dev_addr + repcount) - hp->addr > hp->len)) { \ 2879*0Sstevel@tonic-gate cmn_err((bofi_range_check == 2) ? CE_PANIC : CE_WARN, \ 2880*0Sstevel@tonic-gate "ddi_rep_put() out of range addr %p not in %p/%llx\n", \ 2881*0Sstevel@tonic-gate (void *)dev_addr, (void *)hp->addr, hp->len); \ 2882*0Sstevel@tonic-gate if ((caddr_t)dev_addr < hp->addr || \ 2883*0Sstevel@tonic-gate (caddr_t)dev_addr - hp->addr >= hp->len) \ 2884*0Sstevel@tonic-gate return; \ 2885*0Sstevel@tonic-gate repcount = (type *)(hp->addr + hp->len) - dev_addr; \ 2886*0Sstevel@tonic-gate } 2887*0Sstevel@tonic-gate 2888*0Sstevel@tonic-gate /* 2889*0Sstevel@tonic-gate * our rep_putb() routine - use tryenter 2890*0Sstevel@tonic-gate */ 2891*0Sstevel@tonic-gate static void 2892*0Sstevel@tonic-gate bofi_rep_wr8(ddi_acc_impl_t *handle, uint8_t *host_addr, uint8_t *dev_addr, 2893*0Sstevel@tonic-gate size_t repcount, uint_t flags) 2894*0Sstevel@tonic-gate { 2895*0Sstevel@tonic-gate struct bofi_shadow *hp; 2896*0Sstevel@tonic-gate int i; 2897*0Sstevel@tonic-gate uint64_t llvalue; 2898*0Sstevel@tonic-gate uint8_t *addr; 2899*0Sstevel@tonic-gate 2900*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2901*0Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint8_t) 2902*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2903*0Sstevel@tonic-gate hp->save.acc.ahi_rep_put8(&hp->save.acc, host_addr, dev_addr, 2904*0Sstevel@tonic-gate repcount, flags); 2905*0Sstevel@tonic-gate return; 2906*0Sstevel@tonic-gate } 2907*0Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 2908*0Sstevel@tonic-gate llvalue = *(host_addr + i); 2909*0Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 2910*0Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 1, i ? 0 : 2911*0Sstevel@tonic-gate repcount)) 2912*0Sstevel@tonic-gate hp->save.acc.ahi_put8(&hp->save.acc, addr, 2913*0Sstevel@tonic-gate (uint8_t)llvalue); 2914*0Sstevel@tonic-gate } 2915*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2916*0Sstevel@tonic-gate } 2917*0Sstevel@tonic-gate 2918*0Sstevel@tonic-gate 2919*0Sstevel@tonic-gate /* 2920*0Sstevel@tonic-gate * our rep_putw() routine - use tryenter 2921*0Sstevel@tonic-gate */ 2922*0Sstevel@tonic-gate static void 2923*0Sstevel@tonic-gate bofi_rep_wr16(ddi_acc_impl_t *handle, uint16_t *host_addr, 2924*0Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 2925*0Sstevel@tonic-gate { 2926*0Sstevel@tonic-gate struct bofi_shadow *hp; 2927*0Sstevel@tonic-gate int i; 2928*0Sstevel@tonic-gate uint64_t llvalue; 2929*0Sstevel@tonic-gate uint16_t *addr; 2930*0Sstevel@tonic-gate 2931*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2932*0Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint16_t) 2933*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2934*0Sstevel@tonic-gate hp->save.acc.ahi_rep_put16(&hp->save.acc, host_addr, dev_addr, 2935*0Sstevel@tonic-gate repcount, flags); 2936*0Sstevel@tonic-gate return; 2937*0Sstevel@tonic-gate } 2938*0Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 2939*0Sstevel@tonic-gate llvalue = *(host_addr + i); 2940*0Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 2941*0Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 2, i ? 0 : 2942*0Sstevel@tonic-gate repcount)) 2943*0Sstevel@tonic-gate hp->save.acc.ahi_put16(&hp->save.acc, addr, 2944*0Sstevel@tonic-gate (uint16_t)llvalue); 2945*0Sstevel@tonic-gate } 2946*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2947*0Sstevel@tonic-gate } 2948*0Sstevel@tonic-gate 2949*0Sstevel@tonic-gate 2950*0Sstevel@tonic-gate /* 2951*0Sstevel@tonic-gate * our rep_putl() routine - use tryenter 2952*0Sstevel@tonic-gate */ 2953*0Sstevel@tonic-gate static void 2954*0Sstevel@tonic-gate bofi_rep_wr32(ddi_acc_impl_t *handle, uint32_t *host_addr, 2955*0Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 2956*0Sstevel@tonic-gate { 2957*0Sstevel@tonic-gate struct bofi_shadow *hp; 2958*0Sstevel@tonic-gate int i; 2959*0Sstevel@tonic-gate uint64_t llvalue; 2960*0Sstevel@tonic-gate uint32_t *addr; 2961*0Sstevel@tonic-gate 2962*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2963*0Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint32_t) 2964*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2965*0Sstevel@tonic-gate hp->save.acc.ahi_rep_put32(&hp->save.acc, host_addr, dev_addr, 2966*0Sstevel@tonic-gate repcount, flags); 2967*0Sstevel@tonic-gate return; 2968*0Sstevel@tonic-gate } 2969*0Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 2970*0Sstevel@tonic-gate llvalue = *(host_addr + i); 2971*0Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 2972*0Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 4, i ? 0 : 2973*0Sstevel@tonic-gate repcount)) 2974*0Sstevel@tonic-gate hp->save.acc.ahi_put32(&hp->save.acc, addr, 2975*0Sstevel@tonic-gate (uint32_t)llvalue); 2976*0Sstevel@tonic-gate } 2977*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 2978*0Sstevel@tonic-gate } 2979*0Sstevel@tonic-gate 2980*0Sstevel@tonic-gate 2981*0Sstevel@tonic-gate /* 2982*0Sstevel@tonic-gate * our rep_putll() routine - use tryenter 2983*0Sstevel@tonic-gate */ 2984*0Sstevel@tonic-gate static void 2985*0Sstevel@tonic-gate bofi_rep_wr64(ddi_acc_impl_t *handle, uint64_t *host_addr, 2986*0Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 2987*0Sstevel@tonic-gate { 2988*0Sstevel@tonic-gate struct bofi_shadow *hp; 2989*0Sstevel@tonic-gate int i; 2990*0Sstevel@tonic-gate uint64_t llvalue; 2991*0Sstevel@tonic-gate uint64_t *addr; 2992*0Sstevel@tonic-gate 2993*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 2994*0Sstevel@tonic-gate BOFI_REP_WRITE_TESTS(uint64_t) 2995*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 2996*0Sstevel@tonic-gate hp->save.acc.ahi_rep_put64(&hp->save.acc, host_addr, dev_addr, 2997*0Sstevel@tonic-gate repcount, flags); 2998*0Sstevel@tonic-gate return; 2999*0Sstevel@tonic-gate } 3000*0Sstevel@tonic-gate for (i = 0; i < repcount; i++) { 3001*0Sstevel@tonic-gate llvalue = *(host_addr + i); 3002*0Sstevel@tonic-gate addr = dev_addr + ((flags == DDI_DEV_AUTOINCR) ? i : 0); 3003*0Sstevel@tonic-gate if (do_piow_corrupt(hp, (caddr_t)addr, &llvalue, 8, i ? 0 : 3004*0Sstevel@tonic-gate repcount)) 3005*0Sstevel@tonic-gate hp->save.acc.ahi_put64(&hp->save.acc, addr, 3006*0Sstevel@tonic-gate (uint64_t)llvalue); 3007*0Sstevel@tonic-gate } 3008*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3009*0Sstevel@tonic-gate } 3010*0Sstevel@tonic-gate 3011*0Sstevel@tonic-gate 3012*0Sstevel@tonic-gate /* 3013*0Sstevel@tonic-gate * our ddi_map routine 3014*0Sstevel@tonic-gate */ 3015*0Sstevel@tonic-gate static int 3016*0Sstevel@tonic-gate bofi_map(dev_info_t *dip, dev_info_t *rdip, 3017*0Sstevel@tonic-gate ddi_map_req_t *reqp, off_t offset, off_t len, caddr_t *vaddrp) 3018*0Sstevel@tonic-gate { 3019*0Sstevel@tonic-gate ddi_acc_impl_t *ap; 3020*0Sstevel@tonic-gate struct bofi_shadow *hp; 3021*0Sstevel@tonic-gate struct bofi_errent *ep; 3022*0Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 3023*0Sstevel@tonic-gate int retval; 3024*0Sstevel@tonic-gate struct bofi_shadow *dhashp; 3025*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 3026*0Sstevel@tonic-gate 3027*0Sstevel@tonic-gate switch (reqp->map_op) { 3028*0Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: 3029*0Sstevel@tonic-gate /* 3030*0Sstevel@tonic-gate * for this case get nexus to do real work first 3031*0Sstevel@tonic-gate */ 3032*0Sstevel@tonic-gate retval = save_bus_ops.bus_map(dip, rdip, reqp, offset, len, 3033*0Sstevel@tonic-gate vaddrp); 3034*0Sstevel@tonic-gate if (retval != DDI_SUCCESS) 3035*0Sstevel@tonic-gate return (retval); 3036*0Sstevel@tonic-gate 3037*0Sstevel@tonic-gate ap = (ddi_acc_impl_t *)reqp->map_handlep; 3038*0Sstevel@tonic-gate if (ap == NULL) 3039*0Sstevel@tonic-gate return (DDI_SUCCESS); 3040*0Sstevel@tonic-gate /* 3041*0Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 3042*0Sstevel@tonic-gate */ 3043*0Sstevel@tonic-gate if (!driver_under_test(ap->ahi_common.ah_dip)) 3044*0Sstevel@tonic-gate return (DDI_SUCCESS); 3045*0Sstevel@tonic-gate 3046*0Sstevel@tonic-gate /* 3047*0Sstevel@tonic-gate * support for ddi_regs_map_setup() 3048*0Sstevel@tonic-gate * - allocate shadow handle structure and fill it in 3049*0Sstevel@tonic-gate */ 3050*0Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), KM_SLEEP); 3051*0Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(ap->ahi_common.ah_dip), 3052*0Sstevel@tonic-gate NAMESIZE); 3053*0Sstevel@tonic-gate hp->instance = ddi_get_instance(ap->ahi_common.ah_dip); 3054*0Sstevel@tonic-gate hp->dip = ap->ahi_common.ah_dip; 3055*0Sstevel@tonic-gate hp->addr = *vaddrp; 3056*0Sstevel@tonic-gate /* 3057*0Sstevel@tonic-gate * return spurious value to catch direct access to registers 3058*0Sstevel@tonic-gate */ 3059*0Sstevel@tonic-gate if (bofi_ddi_check) 3060*0Sstevel@tonic-gate *vaddrp = (caddr_t)64; 3061*0Sstevel@tonic-gate hp->rnumber = ((ddi_acc_hdl_t *)ap)->ah_rnumber; 3062*0Sstevel@tonic-gate hp->offset = offset; 3063*0Sstevel@tonic-gate if (len == 0) 3064*0Sstevel@tonic-gate hp->len = INT_MAX - offset; 3065*0Sstevel@tonic-gate else 3066*0Sstevel@tonic-gate hp->len = min(len, INT_MAX - offset); 3067*0Sstevel@tonic-gate hp->hdl.acc_handle = (ddi_acc_handle_t)ap; 3068*0Sstevel@tonic-gate hp->link = NULL; 3069*0Sstevel@tonic-gate hp->type = BOFI_ACC_HDL; 3070*0Sstevel@tonic-gate /* 3071*0Sstevel@tonic-gate * save existing function pointers and plug in our own 3072*0Sstevel@tonic-gate */ 3073*0Sstevel@tonic-gate hp->save.acc = *ap; 3074*0Sstevel@tonic-gate ap->ahi_get8 = bofi_rd8; 3075*0Sstevel@tonic-gate ap->ahi_get16 = bofi_rd16; 3076*0Sstevel@tonic-gate ap->ahi_get32 = bofi_rd32; 3077*0Sstevel@tonic-gate ap->ahi_get64 = bofi_rd64; 3078*0Sstevel@tonic-gate ap->ahi_put8 = bofi_wr8; 3079*0Sstevel@tonic-gate ap->ahi_put16 = bofi_wr16; 3080*0Sstevel@tonic-gate ap->ahi_put32 = bofi_wr32; 3081*0Sstevel@tonic-gate ap->ahi_put64 = bofi_wr64; 3082*0Sstevel@tonic-gate ap->ahi_rep_get8 = bofi_rep_rd8; 3083*0Sstevel@tonic-gate ap->ahi_rep_get16 = bofi_rep_rd16; 3084*0Sstevel@tonic-gate ap->ahi_rep_get32 = bofi_rep_rd32; 3085*0Sstevel@tonic-gate ap->ahi_rep_get64 = bofi_rep_rd64; 3086*0Sstevel@tonic-gate ap->ahi_rep_put8 = bofi_rep_wr8; 3087*0Sstevel@tonic-gate ap->ahi_rep_put16 = bofi_rep_wr16; 3088*0Sstevel@tonic-gate ap->ahi_rep_put32 = bofi_rep_wr32; 3089*0Sstevel@tonic-gate ap->ahi_rep_put64 = bofi_rep_wr64; 3090*0Sstevel@tonic-gate ap->ahi_fault_check = bofi_check_acc_hdl; 3091*0Sstevel@tonic-gate #if defined(__sparc) 3092*0Sstevel@tonic-gate #else 3093*0Sstevel@tonic-gate ap->ahi_acc_attr &= ~DDI_ACCATTR_DIRECT; 3094*0Sstevel@tonic-gate #endif 3095*0Sstevel@tonic-gate /* 3096*0Sstevel@tonic-gate * stick in a pointer to our shadow handle 3097*0Sstevel@tonic-gate */ 3098*0Sstevel@tonic-gate ap->ahi_common.ah_bus_private = hp; 3099*0Sstevel@tonic-gate /* 3100*0Sstevel@tonic-gate * add to dhash, hhash and inuse lists 3101*0Sstevel@tonic-gate */ 3102*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3103*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3104*0Sstevel@tonic-gate hp->next = shadow_list.next; 3105*0Sstevel@tonic-gate shadow_list.next->prev = hp; 3106*0Sstevel@tonic-gate hp->prev = &shadow_list; 3107*0Sstevel@tonic-gate shadow_list.next = hp; 3108*0Sstevel@tonic-gate hhashp = HDL_HHASH(ap); 3109*0Sstevel@tonic-gate hp->hnext = hhashp->hnext; 3110*0Sstevel@tonic-gate hhashp->hnext->hprev = hp; 3111*0Sstevel@tonic-gate hp->hprev = hhashp; 3112*0Sstevel@tonic-gate hhashp->hnext = hp; 3113*0Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 3114*0Sstevel@tonic-gate hp->dnext = dhashp->dnext; 3115*0Sstevel@tonic-gate dhashp->dnext->dprev = hp; 3116*0Sstevel@tonic-gate hp->dprev = dhashp; 3117*0Sstevel@tonic-gate dhashp->dnext = hp; 3118*0Sstevel@tonic-gate /* 3119*0Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 3120*0Sstevel@tonic-gate * acc_handle 3121*0Sstevel@tonic-gate */ 3122*0Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 3123*0Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 3124*0Sstevel@tonic-gate ddi_name_to_major(ep->name) && 3125*0Sstevel@tonic-gate hp->instance == ep->errdef.instance && 3126*0Sstevel@tonic-gate (ep->errdef.access_type & BOFI_PIO_RW) && 3127*0Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 3128*0Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 3129*0Sstevel@tonic-gate (ep->errdef.len == 0 || 3130*0Sstevel@tonic-gate offset < ep->errdef.offset + ep->errdef.len) && 3131*0Sstevel@tonic-gate offset + hp->len > ep->errdef.offset) { 3132*0Sstevel@tonic-gate lp = bofi_link_freelist; 3133*0Sstevel@tonic-gate if (lp != NULL) { 3134*0Sstevel@tonic-gate bofi_link_freelist = lp->link; 3135*0Sstevel@tonic-gate lp->errentp = ep; 3136*0Sstevel@tonic-gate lp->link = hp->link; 3137*0Sstevel@tonic-gate hp->link = lp; 3138*0Sstevel@tonic-gate } 3139*0Sstevel@tonic-gate } 3140*0Sstevel@tonic-gate } 3141*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3142*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3143*0Sstevel@tonic-gate return (DDI_SUCCESS); 3144*0Sstevel@tonic-gate case DDI_MO_UNMAP: 3145*0Sstevel@tonic-gate 3146*0Sstevel@tonic-gate ap = (ddi_acc_impl_t *)reqp->map_handlep; 3147*0Sstevel@tonic-gate if (ap == NULL) 3148*0Sstevel@tonic-gate break; 3149*0Sstevel@tonic-gate /* 3150*0Sstevel@tonic-gate * support for ddi_regs_map_free() 3151*0Sstevel@tonic-gate * - check we really have a shadow handle for this one 3152*0Sstevel@tonic-gate */ 3153*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3154*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3155*0Sstevel@tonic-gate hhashp = HDL_HHASH(ap); 3156*0Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 3157*0Sstevel@tonic-gate if (hp->hdl.acc_handle == (ddi_acc_handle_t)ap) 3158*0Sstevel@tonic-gate break; 3159*0Sstevel@tonic-gate if (hp == hhashp) { 3160*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3161*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3162*0Sstevel@tonic-gate break; 3163*0Sstevel@tonic-gate } 3164*0Sstevel@tonic-gate /* 3165*0Sstevel@tonic-gate * got a shadow handle - restore original pointers 3166*0Sstevel@tonic-gate */ 3167*0Sstevel@tonic-gate *ap = hp->save.acc; 3168*0Sstevel@tonic-gate *vaddrp = hp->addr; 3169*0Sstevel@tonic-gate /* 3170*0Sstevel@tonic-gate * remove from dhash, hhash and inuse lists 3171*0Sstevel@tonic-gate */ 3172*0Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 3173*0Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 3174*0Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 3175*0Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 3176*0Sstevel@tonic-gate hp->next->prev = hp->prev; 3177*0Sstevel@tonic-gate hp->prev->next = hp->next; 3178*0Sstevel@tonic-gate /* 3179*0Sstevel@tonic-gate * free any errdef link structures tagged onto the shadow handle 3180*0Sstevel@tonic-gate */ 3181*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 3182*0Sstevel@tonic-gate next_lp = lp->link; 3183*0Sstevel@tonic-gate lp->link = bofi_link_freelist; 3184*0Sstevel@tonic-gate bofi_link_freelist = lp; 3185*0Sstevel@tonic-gate lp = next_lp; 3186*0Sstevel@tonic-gate } 3187*0Sstevel@tonic-gate hp->link = NULL; 3188*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3189*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3190*0Sstevel@tonic-gate /* 3191*0Sstevel@tonic-gate * finally delete shadow handle 3192*0Sstevel@tonic-gate */ 3193*0Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 3194*0Sstevel@tonic-gate break; 3195*0Sstevel@tonic-gate default: 3196*0Sstevel@tonic-gate break; 3197*0Sstevel@tonic-gate } 3198*0Sstevel@tonic-gate return (save_bus_ops.bus_map(dip, rdip, reqp, offset, len, vaddrp)); 3199*0Sstevel@tonic-gate } 3200*0Sstevel@tonic-gate 3201*0Sstevel@tonic-gate 3202*0Sstevel@tonic-gate /* 3203*0Sstevel@tonic-gate * chain any pre-existing errdefs on to newly created dma handle 3204*0Sstevel@tonic-gate * if required call do_dma_corrupt() to corrupt data 3205*0Sstevel@tonic-gate */ 3206*0Sstevel@tonic-gate static void 3207*0Sstevel@tonic-gate chain_on_errdefs(struct bofi_shadow *hp) 3208*0Sstevel@tonic-gate { 3209*0Sstevel@tonic-gate struct bofi_errent *ep; 3210*0Sstevel@tonic-gate struct bofi_link *lp; 3211*0Sstevel@tonic-gate 3212*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bofi_mutex)); 3213*0Sstevel@tonic-gate /* 3214*0Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this dma_handle 3215*0Sstevel@tonic-gate */ 3216*0Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 3217*0Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 3218*0Sstevel@tonic-gate ddi_name_to_major(ep->name) && 3219*0Sstevel@tonic-gate hp->instance == ep->errdef.instance && 3220*0Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 3221*0Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 3222*0Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_RW) && 3223*0Sstevel@tonic-gate (((uintptr_t)(hp->addr + ep->errdef.offset + 3224*0Sstevel@tonic-gate ep->errdef.len) & ~LLSZMASK) > 3225*0Sstevel@tonic-gate ((uintptr_t)((hp->addr + ep->errdef.offset) + 3226*0Sstevel@tonic-gate LLSZMASK) & ~LLSZMASK)))) { 3227*0Sstevel@tonic-gate /* 3228*0Sstevel@tonic-gate * got a match - link it on 3229*0Sstevel@tonic-gate */ 3230*0Sstevel@tonic-gate lp = bofi_link_freelist; 3231*0Sstevel@tonic-gate if (lp != NULL) { 3232*0Sstevel@tonic-gate bofi_link_freelist = lp->link; 3233*0Sstevel@tonic-gate lp->errentp = ep; 3234*0Sstevel@tonic-gate lp->link = hp->link; 3235*0Sstevel@tonic-gate hp->link = lp; 3236*0Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_W) && 3237*0Sstevel@tonic-gate (hp->flags & DDI_DMA_WRITE) && 3238*0Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 3239*0Sstevel@tonic-gate do_dma_corrupt(hp, ep, 3240*0Sstevel@tonic-gate DDI_DMA_SYNC_FORDEV, 3241*0Sstevel@tonic-gate 0, hp->len); 3242*0Sstevel@tonic-gate } 3243*0Sstevel@tonic-gate } 3244*0Sstevel@tonic-gate } 3245*0Sstevel@tonic-gate } 3246*0Sstevel@tonic-gate } 3247*0Sstevel@tonic-gate 3248*0Sstevel@tonic-gate 3249*0Sstevel@tonic-gate /* 3250*0Sstevel@tonic-gate * need to do copy byte-by-byte in case one of pages is little-endian 3251*0Sstevel@tonic-gate */ 3252*0Sstevel@tonic-gate static void 3253*0Sstevel@tonic-gate xbcopy(void *from, void *to, u_longlong_t len) 3254*0Sstevel@tonic-gate { 3255*0Sstevel@tonic-gate uchar_t *f = from; 3256*0Sstevel@tonic-gate uchar_t *t = to; 3257*0Sstevel@tonic-gate 3258*0Sstevel@tonic-gate while (len--) 3259*0Sstevel@tonic-gate *t++ = *f++; 3260*0Sstevel@tonic-gate } 3261*0Sstevel@tonic-gate 3262*0Sstevel@tonic-gate 3263*0Sstevel@tonic-gate /* 3264*0Sstevel@tonic-gate * our ddi_dma_map routine 3265*0Sstevel@tonic-gate */ 3266*0Sstevel@tonic-gate static int 3267*0Sstevel@tonic-gate bofi_dma_map(dev_info_t *dip, dev_info_t *rdip, 3268*0Sstevel@tonic-gate struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep) 3269*0Sstevel@tonic-gate { 3270*0Sstevel@tonic-gate struct bofi_shadow *hp, *xhp; 3271*0Sstevel@tonic-gate int maxrnumber = 0; 3272*0Sstevel@tonic-gate int retval = DDI_DMA_NORESOURCES; 3273*0Sstevel@tonic-gate auto struct ddi_dma_req dmareq; 3274*0Sstevel@tonic-gate int sleep; 3275*0Sstevel@tonic-gate struct bofi_shadow *dhashp; 3276*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 3277*0Sstevel@tonic-gate ddi_dma_impl_t *mp; 3278*0Sstevel@tonic-gate unsigned long pagemask = ddi_ptob(rdip, 1) - 1; 3279*0Sstevel@tonic-gate 3280*0Sstevel@tonic-gate /* 3281*0Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 3282*0Sstevel@tonic-gate */ 3283*0Sstevel@tonic-gate if (handlep == NULL || !driver_under_test(rdip)) 3284*0Sstevel@tonic-gate return (save_bus_ops.bus_dma_map(dip, rdip, dmareqp, handlep)); 3285*0Sstevel@tonic-gate 3286*0Sstevel@tonic-gate sleep = (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 3287*0Sstevel@tonic-gate /* 3288*0Sstevel@tonic-gate * allocate shadow handle structure and fill it in 3289*0Sstevel@tonic-gate */ 3290*0Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), sleep); 3291*0Sstevel@tonic-gate if (hp == NULL) 3292*0Sstevel@tonic-gate goto error; 3293*0Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 3294*0Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 3295*0Sstevel@tonic-gate hp->dip = rdip; 3296*0Sstevel@tonic-gate hp->flags = dmareqp->dmar_flags; 3297*0Sstevel@tonic-gate hp->link = NULL; 3298*0Sstevel@tonic-gate hp->type = BOFI_DMA_HDL; 3299*0Sstevel@tonic-gate /* 3300*0Sstevel@tonic-gate * get a kernel virtual mapping 3301*0Sstevel@tonic-gate */ 3302*0Sstevel@tonic-gate hp->addr = ddi_dmareq_mapin(dmareqp, &hp->mapaddr, &hp->len); 3303*0Sstevel@tonic-gate if (hp->addr == NULL) 3304*0Sstevel@tonic-gate goto error; 3305*0Sstevel@tonic-gate if (bofi_sync_check) { 3306*0Sstevel@tonic-gate /* 3307*0Sstevel@tonic-gate * Take a copy and pass pointers to this up to nexus instead. 3308*0Sstevel@tonic-gate * Data will be copied from the original on explicit 3309*0Sstevel@tonic-gate * and implicit ddi_dma_sync() 3310*0Sstevel@tonic-gate * 3311*0Sstevel@tonic-gate * - maintain page alignment because some devices assume it. 3312*0Sstevel@tonic-gate */ 3313*0Sstevel@tonic-gate hp->origaddr = hp->addr; 3314*0Sstevel@tonic-gate hp->allocaddr = ddi_umem_alloc( 3315*0Sstevel@tonic-gate ((uintptr_t)hp->addr & pagemask) + hp->len, sleep, 3316*0Sstevel@tonic-gate &hp->umem_cookie); 3317*0Sstevel@tonic-gate if (hp->allocaddr == NULL) 3318*0Sstevel@tonic-gate goto error; 3319*0Sstevel@tonic-gate hp->addr = hp->allocaddr + ((uintptr_t)hp->addr & pagemask); 3320*0Sstevel@tonic-gate if (dmareqp->dmar_flags & DDI_DMA_WRITE) 3321*0Sstevel@tonic-gate xbcopy(hp->origaddr, hp->addr, hp->len); 3322*0Sstevel@tonic-gate dmareq = *dmareqp; 3323*0Sstevel@tonic-gate dmareq.dmar_object.dmao_size = hp->len; 3324*0Sstevel@tonic-gate dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR; 3325*0Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_as = &kas; 3326*0Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_addr = hp->addr; 3327*0Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL; 3328*0Sstevel@tonic-gate dmareqp = &dmareq; 3329*0Sstevel@tonic-gate } 3330*0Sstevel@tonic-gate /* 3331*0Sstevel@tonic-gate * call nexus to do the real work 3332*0Sstevel@tonic-gate */ 3333*0Sstevel@tonic-gate retval = save_bus_ops.bus_dma_map(dip, rdip, dmareqp, handlep); 3334*0Sstevel@tonic-gate if (retval != DDI_SUCCESS) 3335*0Sstevel@tonic-gate goto error2; 3336*0Sstevel@tonic-gate /* 3337*0Sstevel@tonic-gate * now set dma_handle to point to real handle 3338*0Sstevel@tonic-gate */ 3339*0Sstevel@tonic-gate hp->hdl.dma_handle = *handlep; 3340*0Sstevel@tonic-gate /* 3341*0Sstevel@tonic-gate * unset DMP_NOSYNC 3342*0Sstevel@tonic-gate */ 3343*0Sstevel@tonic-gate mp = (ddi_dma_impl_t *)*handlep; 3344*0Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 3345*0Sstevel@tonic-gate mp->dmai_fault_check = bofi_check_dma_hdl; 3346*0Sstevel@tonic-gate /* 3347*0Sstevel@tonic-gate * bind and unbind are cached in devinfo - must overwrite them 3348*0Sstevel@tonic-gate * - note that our bind and unbind are quite happy dealing with 3349*0Sstevel@tonic-gate * any handles for this devinfo that were previously allocated 3350*0Sstevel@tonic-gate */ 3351*0Sstevel@tonic-gate if (save_bus_ops.bus_dma_bindhdl == DEVI(rdip)->devi_bus_dma_bindfunc) 3352*0Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_bindfunc = bofi_dma_bindhdl; 3353*0Sstevel@tonic-gate if (save_bus_ops.bus_dma_unbindhdl == 3354*0Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc) 3355*0Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc = bofi_dma_unbindhdl; 3356*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3357*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3358*0Sstevel@tonic-gate /* 3359*0Sstevel@tonic-gate * get an "rnumber" for this handle - really just seeking to 3360*0Sstevel@tonic-gate * get a unique number - generally only care for early allocated 3361*0Sstevel@tonic-gate * handles - so we get as far as INT_MAX, just stay there 3362*0Sstevel@tonic-gate */ 3363*0Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 3364*0Sstevel@tonic-gate for (xhp = dhashp->dnext; xhp != dhashp; xhp = xhp->dnext) 3365*0Sstevel@tonic-gate if (ddi_name_to_major(xhp->name) == 3366*0Sstevel@tonic-gate ddi_name_to_major(hp->name) && 3367*0Sstevel@tonic-gate xhp->instance == hp->instance && 3368*0Sstevel@tonic-gate xhp->type == BOFI_DMA_HDL) 3369*0Sstevel@tonic-gate if (xhp->rnumber >= maxrnumber) { 3370*0Sstevel@tonic-gate if (xhp->rnumber == INT_MAX) 3371*0Sstevel@tonic-gate maxrnumber = INT_MAX; 3372*0Sstevel@tonic-gate else 3373*0Sstevel@tonic-gate maxrnumber = xhp->rnumber + 1; 3374*0Sstevel@tonic-gate } 3375*0Sstevel@tonic-gate hp->rnumber = maxrnumber; 3376*0Sstevel@tonic-gate /* 3377*0Sstevel@tonic-gate * add to dhash, hhash and inuse lists 3378*0Sstevel@tonic-gate */ 3379*0Sstevel@tonic-gate hp->next = shadow_list.next; 3380*0Sstevel@tonic-gate shadow_list.next->prev = hp; 3381*0Sstevel@tonic-gate hp->prev = &shadow_list; 3382*0Sstevel@tonic-gate shadow_list.next = hp; 3383*0Sstevel@tonic-gate hhashp = HDL_HHASH(*handlep); 3384*0Sstevel@tonic-gate hp->hnext = hhashp->hnext; 3385*0Sstevel@tonic-gate hhashp->hnext->hprev = hp; 3386*0Sstevel@tonic-gate hp->hprev = hhashp; 3387*0Sstevel@tonic-gate hhashp->hnext = hp; 3388*0Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 3389*0Sstevel@tonic-gate hp->dnext = dhashp->dnext; 3390*0Sstevel@tonic-gate dhashp->dnext->dprev = hp; 3391*0Sstevel@tonic-gate hp->dprev = dhashp; 3392*0Sstevel@tonic-gate dhashp->dnext = hp; 3393*0Sstevel@tonic-gate /* 3394*0Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 3395*0Sstevel@tonic-gate * acc_handle and corrupt if required (as there is an implicit 3396*0Sstevel@tonic-gate * ddi_dma_sync() in this call) 3397*0Sstevel@tonic-gate */ 3398*0Sstevel@tonic-gate chain_on_errdefs(hp); 3399*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3400*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3401*0Sstevel@tonic-gate return (retval); 3402*0Sstevel@tonic-gate error: 3403*0Sstevel@tonic-gate if (dmareqp->dmar_fp != DDI_DMA_DONTWAIT) { 3404*0Sstevel@tonic-gate /* 3405*0Sstevel@tonic-gate * what to do here? Wait a bit and try again 3406*0Sstevel@tonic-gate */ 3407*0Sstevel@tonic-gate (void) timeout((void (*)())dmareqp->dmar_fp, 3408*0Sstevel@tonic-gate dmareqp->dmar_arg, 10); 3409*0Sstevel@tonic-gate } 3410*0Sstevel@tonic-gate error2: 3411*0Sstevel@tonic-gate if (hp) { 3412*0Sstevel@tonic-gate ddi_dmareq_mapout(hp->mapaddr, hp->len); 3413*0Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 3414*0Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 3415*0Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 3416*0Sstevel@tonic-gate } 3417*0Sstevel@tonic-gate return (retval); 3418*0Sstevel@tonic-gate } 3419*0Sstevel@tonic-gate 3420*0Sstevel@tonic-gate 3421*0Sstevel@tonic-gate /* 3422*0Sstevel@tonic-gate * our ddi_dma_allochdl routine 3423*0Sstevel@tonic-gate */ 3424*0Sstevel@tonic-gate static int 3425*0Sstevel@tonic-gate bofi_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp, 3426*0Sstevel@tonic-gate int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 3427*0Sstevel@tonic-gate { 3428*0Sstevel@tonic-gate int retval = DDI_DMA_NORESOURCES; 3429*0Sstevel@tonic-gate struct bofi_shadow *hp, *xhp; 3430*0Sstevel@tonic-gate int maxrnumber = 0; 3431*0Sstevel@tonic-gate struct bofi_shadow *dhashp; 3432*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 3433*0Sstevel@tonic-gate ddi_dma_impl_t *mp; 3434*0Sstevel@tonic-gate 3435*0Sstevel@tonic-gate /* 3436*0Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 3437*0Sstevel@tonic-gate */ 3438*0Sstevel@tonic-gate if (!driver_under_test(rdip)) 3439*0Sstevel@tonic-gate return (save_bus_ops.bus_dma_allochdl(dip, rdip, attrp, 3440*0Sstevel@tonic-gate waitfp, arg, handlep)); 3441*0Sstevel@tonic-gate 3442*0Sstevel@tonic-gate /* 3443*0Sstevel@tonic-gate * allocate shadow handle structure and fill it in 3444*0Sstevel@tonic-gate */ 3445*0Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), 3446*0Sstevel@tonic-gate ((waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP)); 3447*0Sstevel@tonic-gate if (hp == NULL) { 3448*0Sstevel@tonic-gate /* 3449*0Sstevel@tonic-gate * what to do here? Wait a bit and try again 3450*0Sstevel@tonic-gate */ 3451*0Sstevel@tonic-gate if (waitfp != DDI_DMA_DONTWAIT) 3452*0Sstevel@tonic-gate (void) timeout((void (*)())waitfp, arg, 10); 3453*0Sstevel@tonic-gate return (retval); 3454*0Sstevel@tonic-gate } 3455*0Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 3456*0Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 3457*0Sstevel@tonic-gate hp->dip = rdip; 3458*0Sstevel@tonic-gate hp->link = NULL; 3459*0Sstevel@tonic-gate hp->type = BOFI_NULL; 3460*0Sstevel@tonic-gate /* 3461*0Sstevel@tonic-gate * call nexus to do the real work 3462*0Sstevel@tonic-gate */ 3463*0Sstevel@tonic-gate retval = save_bus_ops.bus_dma_allochdl(dip, rdip, attrp, waitfp, arg, 3464*0Sstevel@tonic-gate handlep); 3465*0Sstevel@tonic-gate if (retval != DDI_SUCCESS) { 3466*0Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 3467*0Sstevel@tonic-gate return (retval); 3468*0Sstevel@tonic-gate } 3469*0Sstevel@tonic-gate /* 3470*0Sstevel@tonic-gate * now point set dma_handle to point to real handle 3471*0Sstevel@tonic-gate */ 3472*0Sstevel@tonic-gate hp->hdl.dma_handle = *handlep; 3473*0Sstevel@tonic-gate mp = (ddi_dma_impl_t *)*handlep; 3474*0Sstevel@tonic-gate mp->dmai_fault_check = bofi_check_dma_hdl; 3475*0Sstevel@tonic-gate /* 3476*0Sstevel@tonic-gate * bind and unbind are cached in devinfo - must overwrite them 3477*0Sstevel@tonic-gate * - note that our bind and unbind are quite happy dealing with 3478*0Sstevel@tonic-gate * any handles for this devinfo that were previously allocated 3479*0Sstevel@tonic-gate */ 3480*0Sstevel@tonic-gate if (save_bus_ops.bus_dma_bindhdl == DEVI(rdip)->devi_bus_dma_bindfunc) 3481*0Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_bindfunc = bofi_dma_bindhdl; 3482*0Sstevel@tonic-gate if (save_bus_ops.bus_dma_unbindhdl == 3483*0Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc) 3484*0Sstevel@tonic-gate DEVI(rdip)->devi_bus_dma_unbindfunc = bofi_dma_unbindhdl; 3485*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3486*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3487*0Sstevel@tonic-gate /* 3488*0Sstevel@tonic-gate * get an "rnumber" for this handle - really just seeking to 3489*0Sstevel@tonic-gate * get a unique number - generally only care for early allocated 3490*0Sstevel@tonic-gate * handles - so we get as far as INT_MAX, just stay there 3491*0Sstevel@tonic-gate */ 3492*0Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 3493*0Sstevel@tonic-gate for (xhp = dhashp->dnext; xhp != dhashp; xhp = xhp->dnext) 3494*0Sstevel@tonic-gate if (ddi_name_to_major(xhp->name) == 3495*0Sstevel@tonic-gate ddi_name_to_major(hp->name) && 3496*0Sstevel@tonic-gate xhp->instance == hp->instance && 3497*0Sstevel@tonic-gate (xhp->type == BOFI_DMA_HDL || 3498*0Sstevel@tonic-gate xhp->type == BOFI_NULL)) 3499*0Sstevel@tonic-gate if (xhp->rnumber >= maxrnumber) { 3500*0Sstevel@tonic-gate if (xhp->rnumber == INT_MAX) 3501*0Sstevel@tonic-gate maxrnumber = INT_MAX; 3502*0Sstevel@tonic-gate else 3503*0Sstevel@tonic-gate maxrnumber = xhp->rnumber + 1; 3504*0Sstevel@tonic-gate } 3505*0Sstevel@tonic-gate hp->rnumber = maxrnumber; 3506*0Sstevel@tonic-gate /* 3507*0Sstevel@tonic-gate * add to dhash, hhash and inuse lists 3508*0Sstevel@tonic-gate */ 3509*0Sstevel@tonic-gate hp->next = shadow_list.next; 3510*0Sstevel@tonic-gate shadow_list.next->prev = hp; 3511*0Sstevel@tonic-gate hp->prev = &shadow_list; 3512*0Sstevel@tonic-gate shadow_list.next = hp; 3513*0Sstevel@tonic-gate hhashp = HDL_HHASH(*handlep); 3514*0Sstevel@tonic-gate hp->hnext = hhashp->hnext; 3515*0Sstevel@tonic-gate hhashp->hnext->hprev = hp; 3516*0Sstevel@tonic-gate hp->hprev = hhashp; 3517*0Sstevel@tonic-gate hhashp->hnext = hp; 3518*0Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 3519*0Sstevel@tonic-gate hp->dnext = dhashp->dnext; 3520*0Sstevel@tonic-gate dhashp->dnext->dprev = hp; 3521*0Sstevel@tonic-gate hp->dprev = dhashp; 3522*0Sstevel@tonic-gate dhashp->dnext = hp; 3523*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3524*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3525*0Sstevel@tonic-gate return (retval); 3526*0Sstevel@tonic-gate } 3527*0Sstevel@tonic-gate 3528*0Sstevel@tonic-gate 3529*0Sstevel@tonic-gate /* 3530*0Sstevel@tonic-gate * our ddi_dma_freehdl routine 3531*0Sstevel@tonic-gate */ 3532*0Sstevel@tonic-gate static int 3533*0Sstevel@tonic-gate bofi_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 3534*0Sstevel@tonic-gate { 3535*0Sstevel@tonic-gate int retval; 3536*0Sstevel@tonic-gate struct bofi_shadow *hp; 3537*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 3538*0Sstevel@tonic-gate 3539*0Sstevel@tonic-gate /* 3540*0Sstevel@tonic-gate * find shadow for this handle 3541*0Sstevel@tonic-gate */ 3542*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3543*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3544*0Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 3545*0Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 3546*0Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 3547*0Sstevel@tonic-gate break; 3548*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3549*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3550*0Sstevel@tonic-gate /* 3551*0Sstevel@tonic-gate * call nexus to do the real work 3552*0Sstevel@tonic-gate */ 3553*0Sstevel@tonic-gate retval = save_bus_ops.bus_dma_freehdl(dip, rdip, handle); 3554*0Sstevel@tonic-gate if (retval != DDI_SUCCESS) { 3555*0Sstevel@tonic-gate return (retval); 3556*0Sstevel@tonic-gate } 3557*0Sstevel@tonic-gate /* 3558*0Sstevel@tonic-gate * did we really have a shadow for this handle 3559*0Sstevel@tonic-gate */ 3560*0Sstevel@tonic-gate if (hp == hhashp) 3561*0Sstevel@tonic-gate return (retval); 3562*0Sstevel@tonic-gate /* 3563*0Sstevel@tonic-gate * yes we have - see if it's still bound 3564*0Sstevel@tonic-gate */ 3565*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3566*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3567*0Sstevel@tonic-gate if (hp->type != BOFI_NULL) 3568*0Sstevel@tonic-gate panic("driver freeing bound dma_handle"); 3569*0Sstevel@tonic-gate /* 3570*0Sstevel@tonic-gate * remove from dhash, hhash and inuse lists 3571*0Sstevel@tonic-gate */ 3572*0Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 3573*0Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 3574*0Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 3575*0Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 3576*0Sstevel@tonic-gate hp->next->prev = hp->prev; 3577*0Sstevel@tonic-gate hp->prev->next = hp->next; 3578*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3579*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3580*0Sstevel@tonic-gate 3581*0Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 3582*0Sstevel@tonic-gate return (retval); 3583*0Sstevel@tonic-gate } 3584*0Sstevel@tonic-gate 3585*0Sstevel@tonic-gate 3586*0Sstevel@tonic-gate /* 3587*0Sstevel@tonic-gate * our ddi_dma_bindhdl routine 3588*0Sstevel@tonic-gate */ 3589*0Sstevel@tonic-gate static int 3590*0Sstevel@tonic-gate bofi_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 3591*0Sstevel@tonic-gate ddi_dma_handle_t handle, struct ddi_dma_req *dmareqp, 3592*0Sstevel@tonic-gate ddi_dma_cookie_t *cookiep, uint_t *ccountp) 3593*0Sstevel@tonic-gate { 3594*0Sstevel@tonic-gate int retval = DDI_DMA_NORESOURCES; 3595*0Sstevel@tonic-gate auto struct ddi_dma_req dmareq; 3596*0Sstevel@tonic-gate struct bofi_shadow *hp; 3597*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 3598*0Sstevel@tonic-gate ddi_dma_impl_t *mp; 3599*0Sstevel@tonic-gate unsigned long pagemask = ddi_ptob(rdip, 1) - 1; 3600*0Sstevel@tonic-gate 3601*0Sstevel@tonic-gate /* 3602*0Sstevel@tonic-gate * check we really have a shadow for this handle 3603*0Sstevel@tonic-gate */ 3604*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3605*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3606*0Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 3607*0Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 3608*0Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 3609*0Sstevel@tonic-gate break; 3610*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3611*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3612*0Sstevel@tonic-gate if (hp == hhashp) { 3613*0Sstevel@tonic-gate /* 3614*0Sstevel@tonic-gate * no we don't - just call nexus to do the real work 3615*0Sstevel@tonic-gate */ 3616*0Sstevel@tonic-gate return save_bus_ops.bus_dma_bindhdl(dip, rdip, handle, dmareqp, 3617*0Sstevel@tonic-gate cookiep, ccountp); 3618*0Sstevel@tonic-gate } 3619*0Sstevel@tonic-gate /* 3620*0Sstevel@tonic-gate * yes we have - see if it's already bound 3621*0Sstevel@tonic-gate */ 3622*0Sstevel@tonic-gate if (hp->type != BOFI_NULL) 3623*0Sstevel@tonic-gate return (DDI_DMA_INUSE); 3624*0Sstevel@tonic-gate 3625*0Sstevel@tonic-gate hp->flags = dmareqp->dmar_flags; 3626*0Sstevel@tonic-gate /* 3627*0Sstevel@tonic-gate * get a kernel virtual mapping 3628*0Sstevel@tonic-gate */ 3629*0Sstevel@tonic-gate hp->addr = ddi_dmareq_mapin(dmareqp, &hp->mapaddr, &hp->len); 3630*0Sstevel@tonic-gate if (hp->addr == NULL) 3631*0Sstevel@tonic-gate goto error; 3632*0Sstevel@tonic-gate if (bofi_sync_check) { 3633*0Sstevel@tonic-gate /* 3634*0Sstevel@tonic-gate * Take a copy and pass pointers to this up to nexus instead. 3635*0Sstevel@tonic-gate * Data will be copied from the original on explicit 3636*0Sstevel@tonic-gate * and implicit ddi_dma_sync() 3637*0Sstevel@tonic-gate * 3638*0Sstevel@tonic-gate * - maintain page alignment because some devices assume it. 3639*0Sstevel@tonic-gate */ 3640*0Sstevel@tonic-gate hp->origaddr = hp->addr; 3641*0Sstevel@tonic-gate hp->allocaddr = ddi_umem_alloc( 3642*0Sstevel@tonic-gate ((uintptr_t)hp->addr & pagemask) + hp->len, 3643*0Sstevel@tonic-gate (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP, 3644*0Sstevel@tonic-gate &hp->umem_cookie); 3645*0Sstevel@tonic-gate if (hp->allocaddr == NULL) 3646*0Sstevel@tonic-gate goto error; 3647*0Sstevel@tonic-gate hp->addr = hp->allocaddr + ((uintptr_t)hp->addr & pagemask); 3648*0Sstevel@tonic-gate if (dmareqp->dmar_flags & DDI_DMA_WRITE) 3649*0Sstevel@tonic-gate xbcopy(hp->origaddr, hp->addr, hp->len); 3650*0Sstevel@tonic-gate dmareq = *dmareqp; 3651*0Sstevel@tonic-gate dmareq.dmar_object.dmao_size = hp->len; 3652*0Sstevel@tonic-gate dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR; 3653*0Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_as = &kas; 3654*0Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_addr = hp->addr; 3655*0Sstevel@tonic-gate dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL; 3656*0Sstevel@tonic-gate dmareqp = &dmareq; 3657*0Sstevel@tonic-gate } 3658*0Sstevel@tonic-gate /* 3659*0Sstevel@tonic-gate * call nexus to do the real work 3660*0Sstevel@tonic-gate */ 3661*0Sstevel@tonic-gate retval = save_bus_ops.bus_dma_bindhdl(dip, rdip, handle, dmareqp, 3662*0Sstevel@tonic-gate cookiep, ccountp); 3663*0Sstevel@tonic-gate if (retval != DDI_SUCCESS) 3664*0Sstevel@tonic-gate goto error2; 3665*0Sstevel@tonic-gate /* 3666*0Sstevel@tonic-gate * unset DMP_NOSYNC 3667*0Sstevel@tonic-gate */ 3668*0Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 3669*0Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 3670*0Sstevel@tonic-gate /* 3671*0Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 3672*0Sstevel@tonic-gate * acc_handle and corrupt if required (as there is an implicit 3673*0Sstevel@tonic-gate * ddi_dma_sync() in this call) 3674*0Sstevel@tonic-gate */ 3675*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3676*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3677*0Sstevel@tonic-gate hp->type = BOFI_DMA_HDL; 3678*0Sstevel@tonic-gate chain_on_errdefs(hp); 3679*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3680*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3681*0Sstevel@tonic-gate return (retval); 3682*0Sstevel@tonic-gate 3683*0Sstevel@tonic-gate error: 3684*0Sstevel@tonic-gate if (dmareqp->dmar_fp != DDI_DMA_DONTWAIT) { 3685*0Sstevel@tonic-gate /* 3686*0Sstevel@tonic-gate * what to do here? Wait a bit and try again 3687*0Sstevel@tonic-gate */ 3688*0Sstevel@tonic-gate (void) timeout((void (*)())dmareqp->dmar_fp, 3689*0Sstevel@tonic-gate dmareqp->dmar_arg, 10); 3690*0Sstevel@tonic-gate } 3691*0Sstevel@tonic-gate error2: 3692*0Sstevel@tonic-gate if (hp) { 3693*0Sstevel@tonic-gate ddi_dmareq_mapout(hp->mapaddr, hp->len); 3694*0Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 3695*0Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 3696*0Sstevel@tonic-gate hp->mapaddr = NULL; 3697*0Sstevel@tonic-gate hp->allocaddr = NULL; 3698*0Sstevel@tonic-gate hp->origaddr = NULL; 3699*0Sstevel@tonic-gate } 3700*0Sstevel@tonic-gate return (retval); 3701*0Sstevel@tonic-gate } 3702*0Sstevel@tonic-gate 3703*0Sstevel@tonic-gate 3704*0Sstevel@tonic-gate /* 3705*0Sstevel@tonic-gate * our ddi_dma_unbindhdl routine 3706*0Sstevel@tonic-gate */ 3707*0Sstevel@tonic-gate static int 3708*0Sstevel@tonic-gate bofi_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 3709*0Sstevel@tonic-gate { 3710*0Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 3711*0Sstevel@tonic-gate struct bofi_errent *ep; 3712*0Sstevel@tonic-gate int retval; 3713*0Sstevel@tonic-gate struct bofi_shadow *hp; 3714*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 3715*0Sstevel@tonic-gate 3716*0Sstevel@tonic-gate /* 3717*0Sstevel@tonic-gate * call nexus to do the real work 3718*0Sstevel@tonic-gate */ 3719*0Sstevel@tonic-gate retval = save_bus_ops.bus_dma_unbindhdl(dip, rdip, handle); 3720*0Sstevel@tonic-gate if (retval != DDI_SUCCESS) 3721*0Sstevel@tonic-gate return (retval); 3722*0Sstevel@tonic-gate /* 3723*0Sstevel@tonic-gate * check we really have a shadow for this handle 3724*0Sstevel@tonic-gate */ 3725*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3726*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3727*0Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 3728*0Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 3729*0Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 3730*0Sstevel@tonic-gate break; 3731*0Sstevel@tonic-gate if (hp == hhashp) { 3732*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3733*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3734*0Sstevel@tonic-gate return (retval); 3735*0Sstevel@tonic-gate } 3736*0Sstevel@tonic-gate /* 3737*0Sstevel@tonic-gate * yes we have - see if it's already unbound 3738*0Sstevel@tonic-gate */ 3739*0Sstevel@tonic-gate if (hp->type == BOFI_NULL) 3740*0Sstevel@tonic-gate panic("driver unbinding unbound dma_handle"); 3741*0Sstevel@tonic-gate /* 3742*0Sstevel@tonic-gate * free any errdef link structures tagged on to this 3743*0Sstevel@tonic-gate * shadow handle 3744*0Sstevel@tonic-gate */ 3745*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 3746*0Sstevel@tonic-gate next_lp = lp->link; 3747*0Sstevel@tonic-gate /* 3748*0Sstevel@tonic-gate * there is an implicit sync_for_cpu on free - 3749*0Sstevel@tonic-gate * may need to corrupt 3750*0Sstevel@tonic-gate */ 3751*0Sstevel@tonic-gate ep = lp->errentp; 3752*0Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_R) && 3753*0Sstevel@tonic-gate (hp->flags & DDI_DMA_READ) && 3754*0Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 3755*0Sstevel@tonic-gate do_dma_corrupt(hp, ep, DDI_DMA_SYNC_FORCPU, 0, hp->len); 3756*0Sstevel@tonic-gate } 3757*0Sstevel@tonic-gate lp->link = bofi_link_freelist; 3758*0Sstevel@tonic-gate bofi_link_freelist = lp; 3759*0Sstevel@tonic-gate lp = next_lp; 3760*0Sstevel@tonic-gate } 3761*0Sstevel@tonic-gate hp->link = NULL; 3762*0Sstevel@tonic-gate hp->type = BOFI_NULL; 3763*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3764*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3765*0Sstevel@tonic-gate 3766*0Sstevel@tonic-gate if (bofi_sync_check && (hp->flags & DDI_DMA_READ)) 3767*0Sstevel@tonic-gate /* 3768*0Sstevel@tonic-gate * implicit sync_for_cpu - copy data back 3769*0Sstevel@tonic-gate */ 3770*0Sstevel@tonic-gate if (hp->allocaddr) 3771*0Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 3772*0Sstevel@tonic-gate ddi_dmareq_mapout(hp->mapaddr, hp->len); 3773*0Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 3774*0Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 3775*0Sstevel@tonic-gate hp->mapaddr = NULL; 3776*0Sstevel@tonic-gate hp->allocaddr = NULL; 3777*0Sstevel@tonic-gate hp->origaddr = NULL; 3778*0Sstevel@tonic-gate return (retval); 3779*0Sstevel@tonic-gate } 3780*0Sstevel@tonic-gate 3781*0Sstevel@tonic-gate 3782*0Sstevel@tonic-gate /* 3783*0Sstevel@tonic-gate * our ddi_dma_sync routine 3784*0Sstevel@tonic-gate */ 3785*0Sstevel@tonic-gate static int 3786*0Sstevel@tonic-gate bofi_dma_flush(dev_info_t *dip, dev_info_t *rdip, 3787*0Sstevel@tonic-gate ddi_dma_handle_t handle, off_t off, size_t len, uint_t flags) 3788*0Sstevel@tonic-gate { 3789*0Sstevel@tonic-gate struct bofi_link *lp; 3790*0Sstevel@tonic-gate struct bofi_errent *ep; 3791*0Sstevel@tonic-gate struct bofi_shadow *hp; 3792*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 3793*0Sstevel@tonic-gate int retval; 3794*0Sstevel@tonic-gate 3795*0Sstevel@tonic-gate if (flags == DDI_DMA_SYNC_FORCPU || flags == DDI_DMA_SYNC_FORKERNEL) { 3796*0Sstevel@tonic-gate /* 3797*0Sstevel@tonic-gate * in this case get nexus driver to do sync first 3798*0Sstevel@tonic-gate */ 3799*0Sstevel@tonic-gate retval = save_bus_ops.bus_dma_flush(dip, rdip, handle, off, 3800*0Sstevel@tonic-gate len, flags); 3801*0Sstevel@tonic-gate if (retval != DDI_SUCCESS) 3802*0Sstevel@tonic-gate return (retval); 3803*0Sstevel@tonic-gate } 3804*0Sstevel@tonic-gate /* 3805*0Sstevel@tonic-gate * check we really have a shadow for this handle 3806*0Sstevel@tonic-gate */ 3807*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3808*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3809*0Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 3810*0Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 3811*0Sstevel@tonic-gate if (hp->hdl.dma_handle == handle && 3812*0Sstevel@tonic-gate hp->type == BOFI_DMA_HDL) 3813*0Sstevel@tonic-gate break; 3814*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3815*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3816*0Sstevel@tonic-gate if (hp != hhashp) { 3817*0Sstevel@tonic-gate /* 3818*0Sstevel@tonic-gate * yes - do we need to copy data from original 3819*0Sstevel@tonic-gate */ 3820*0Sstevel@tonic-gate if (bofi_sync_check && flags == DDI_DMA_SYNC_FORDEV) 3821*0Sstevel@tonic-gate if (hp->allocaddr) 3822*0Sstevel@tonic-gate xbcopy(hp->origaddr+off, hp->addr+off, 3823*0Sstevel@tonic-gate len ? len : (hp->len - off)); 3824*0Sstevel@tonic-gate /* 3825*0Sstevel@tonic-gate * yes - check if we need to corrupt the data 3826*0Sstevel@tonic-gate */ 3827*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3828*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3829*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 3830*0Sstevel@tonic-gate ep = lp->errentp; 3831*0Sstevel@tonic-gate if ((((ep->errdef.access_type & BOFI_DMA_R) && 3832*0Sstevel@tonic-gate (flags == DDI_DMA_SYNC_FORCPU || 3833*0Sstevel@tonic-gate flags == DDI_DMA_SYNC_FORKERNEL)) || 3834*0Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_W) && 3835*0Sstevel@tonic-gate (flags == DDI_DMA_SYNC_FORDEV))) && 3836*0Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 3837*0Sstevel@tonic-gate do_dma_corrupt(hp, ep, flags, off, 3838*0Sstevel@tonic-gate len ? len : (hp->len - off)); 3839*0Sstevel@tonic-gate } 3840*0Sstevel@tonic-gate } 3841*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3842*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3843*0Sstevel@tonic-gate /* 3844*0Sstevel@tonic-gate * do we need to copy data to original 3845*0Sstevel@tonic-gate */ 3846*0Sstevel@tonic-gate if (bofi_sync_check && (flags == DDI_DMA_SYNC_FORCPU || 3847*0Sstevel@tonic-gate flags == DDI_DMA_SYNC_FORKERNEL)) 3848*0Sstevel@tonic-gate if (hp->allocaddr) 3849*0Sstevel@tonic-gate xbcopy(hp->addr+off, hp->origaddr+off, 3850*0Sstevel@tonic-gate len ? len : (hp->len - off)); 3851*0Sstevel@tonic-gate } 3852*0Sstevel@tonic-gate if (flags == DDI_DMA_SYNC_FORDEV) 3853*0Sstevel@tonic-gate /* 3854*0Sstevel@tonic-gate * in this case get nexus driver to do sync last 3855*0Sstevel@tonic-gate */ 3856*0Sstevel@tonic-gate retval = save_bus_ops.bus_dma_flush(dip, rdip, handle, off, 3857*0Sstevel@tonic-gate len, flags); 3858*0Sstevel@tonic-gate return (retval); 3859*0Sstevel@tonic-gate } 3860*0Sstevel@tonic-gate 3861*0Sstevel@tonic-gate 3862*0Sstevel@tonic-gate /* 3863*0Sstevel@tonic-gate * our dma_win routine 3864*0Sstevel@tonic-gate */ 3865*0Sstevel@tonic-gate static int 3866*0Sstevel@tonic-gate bofi_dma_win(dev_info_t *dip, dev_info_t *rdip, 3867*0Sstevel@tonic-gate ddi_dma_handle_t handle, uint_t win, off_t *offp, 3868*0Sstevel@tonic-gate size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp) 3869*0Sstevel@tonic-gate { 3870*0Sstevel@tonic-gate struct bofi_shadow *hp; 3871*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 3872*0Sstevel@tonic-gate int retval; 3873*0Sstevel@tonic-gate ddi_dma_impl_t *mp; 3874*0Sstevel@tonic-gate 3875*0Sstevel@tonic-gate /* 3876*0Sstevel@tonic-gate * call nexus to do the real work 3877*0Sstevel@tonic-gate */ 3878*0Sstevel@tonic-gate retval = save_bus_ops.bus_dma_win(dip, rdip, handle, win, offp, lenp, 3879*0Sstevel@tonic-gate cookiep, ccountp); 3880*0Sstevel@tonic-gate if (retval != DDI_SUCCESS) 3881*0Sstevel@tonic-gate return (retval); 3882*0Sstevel@tonic-gate /* 3883*0Sstevel@tonic-gate * check we really have a shadow for this handle 3884*0Sstevel@tonic-gate */ 3885*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3886*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3887*0Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 3888*0Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 3889*0Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 3890*0Sstevel@tonic-gate break; 3891*0Sstevel@tonic-gate if (hp != hhashp) { 3892*0Sstevel@tonic-gate /* 3893*0Sstevel@tonic-gate * yes - make sure DMP_NOSYNC is unset 3894*0Sstevel@tonic-gate */ 3895*0Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 3896*0Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 3897*0Sstevel@tonic-gate } 3898*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3899*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3900*0Sstevel@tonic-gate return (retval); 3901*0Sstevel@tonic-gate } 3902*0Sstevel@tonic-gate 3903*0Sstevel@tonic-gate 3904*0Sstevel@tonic-gate /* 3905*0Sstevel@tonic-gate * our dma_ctl routine 3906*0Sstevel@tonic-gate */ 3907*0Sstevel@tonic-gate static int 3908*0Sstevel@tonic-gate bofi_dma_ctl(dev_info_t *dip, dev_info_t *rdip, 3909*0Sstevel@tonic-gate ddi_dma_handle_t handle, enum ddi_dma_ctlops request, 3910*0Sstevel@tonic-gate off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags) 3911*0Sstevel@tonic-gate { 3912*0Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 3913*0Sstevel@tonic-gate struct bofi_errent *ep; 3914*0Sstevel@tonic-gate struct bofi_shadow *hp; 3915*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 3916*0Sstevel@tonic-gate int retval; 3917*0Sstevel@tonic-gate int i; 3918*0Sstevel@tonic-gate struct bofi_shadow *dummyhp; 3919*0Sstevel@tonic-gate ddi_dma_impl_t *mp; 3920*0Sstevel@tonic-gate 3921*0Sstevel@tonic-gate /* 3922*0Sstevel@tonic-gate * get nexus to do real work 3923*0Sstevel@tonic-gate */ 3924*0Sstevel@tonic-gate retval = save_bus_ops.bus_dma_ctl(dip, rdip, handle, request, offp, 3925*0Sstevel@tonic-gate lenp, objp, flags); 3926*0Sstevel@tonic-gate if (retval != DDI_SUCCESS) 3927*0Sstevel@tonic-gate return (retval); 3928*0Sstevel@tonic-gate /* 3929*0Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 3930*0Sstevel@tonic-gate */ 3931*0Sstevel@tonic-gate if (!driver_under_test(rdip)) 3932*0Sstevel@tonic-gate return (DDI_SUCCESS); 3933*0Sstevel@tonic-gate 3934*0Sstevel@tonic-gate #if defined(__sparc) 3935*0Sstevel@tonic-gate /* 3936*0Sstevel@tonic-gate * check if this is a dvma_reserve - that one's like a 3937*0Sstevel@tonic-gate * dma_allochdl and needs to be handled separately 3938*0Sstevel@tonic-gate */ 3939*0Sstevel@tonic-gate if (request == DDI_DMA_RESERVE) { 3940*0Sstevel@tonic-gate bofi_dvma_reserve(rdip, *(ddi_dma_handle_t *)objp); 3941*0Sstevel@tonic-gate return (DDI_SUCCESS); 3942*0Sstevel@tonic-gate } 3943*0Sstevel@tonic-gate #endif 3944*0Sstevel@tonic-gate /* 3945*0Sstevel@tonic-gate * check we really have a shadow for this handle 3946*0Sstevel@tonic-gate */ 3947*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3948*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3949*0Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 3950*0Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 3951*0Sstevel@tonic-gate if (hp->hdl.dma_handle == handle) 3952*0Sstevel@tonic-gate break; 3953*0Sstevel@tonic-gate if (hp == hhashp) { 3954*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3955*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3956*0Sstevel@tonic-gate return (retval); 3957*0Sstevel@tonic-gate } 3958*0Sstevel@tonic-gate /* 3959*0Sstevel@tonic-gate * yes we have - see what kind of command this is 3960*0Sstevel@tonic-gate */ 3961*0Sstevel@tonic-gate switch (request) { 3962*0Sstevel@tonic-gate case DDI_DMA_RELEASE: 3963*0Sstevel@tonic-gate /* 3964*0Sstevel@tonic-gate * dvma release - release dummy handle and all the index handles 3965*0Sstevel@tonic-gate */ 3966*0Sstevel@tonic-gate dummyhp = hp; 3967*0Sstevel@tonic-gate dummyhp->hnext->hprev = dummyhp->hprev; 3968*0Sstevel@tonic-gate dummyhp->hprev->hnext = dummyhp->hnext; 3969*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3970*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3971*0Sstevel@tonic-gate for (i = 0; i < dummyhp->len; i++) { 3972*0Sstevel@tonic-gate hp = dummyhp->hparrayp[i]; 3973*0Sstevel@tonic-gate /* 3974*0Sstevel@tonic-gate * chek none of the index handles were still loaded 3975*0Sstevel@tonic-gate */ 3976*0Sstevel@tonic-gate if (hp->type != BOFI_NULL) 3977*0Sstevel@tonic-gate panic("driver releasing loaded dvma"); 3978*0Sstevel@tonic-gate /* 3979*0Sstevel@tonic-gate * remove from dhash and inuse lists 3980*0Sstevel@tonic-gate */ 3981*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 3982*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 3983*0Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 3984*0Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 3985*0Sstevel@tonic-gate hp->next->prev = hp->prev; 3986*0Sstevel@tonic-gate hp->prev->next = hp->next; 3987*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 3988*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 3989*0Sstevel@tonic-gate 3990*0Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 3991*0Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 3992*0Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 3993*0Sstevel@tonic-gate } 3994*0Sstevel@tonic-gate kmem_free(dummyhp->hparrayp, dummyhp->len * 3995*0Sstevel@tonic-gate sizeof (struct bofi_shadow *)); 3996*0Sstevel@tonic-gate kmem_free(dummyhp, sizeof (struct bofi_shadow)); 3997*0Sstevel@tonic-gate return (retval); 3998*0Sstevel@tonic-gate case DDI_DMA_FREE: 3999*0Sstevel@tonic-gate /* 4000*0Sstevel@tonic-gate * ddi_dma_free case - remove from dhash, hhash and inuse lists 4001*0Sstevel@tonic-gate */ 4002*0Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 4003*0Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 4004*0Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 4005*0Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 4006*0Sstevel@tonic-gate hp->next->prev = hp->prev; 4007*0Sstevel@tonic-gate hp->prev->next = hp->next; 4008*0Sstevel@tonic-gate /* 4009*0Sstevel@tonic-gate * free any errdef link structures tagged on to this 4010*0Sstevel@tonic-gate * shadow handle 4011*0Sstevel@tonic-gate */ 4012*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 4013*0Sstevel@tonic-gate next_lp = lp->link; 4014*0Sstevel@tonic-gate /* 4015*0Sstevel@tonic-gate * there is an implicit sync_for_cpu on free - 4016*0Sstevel@tonic-gate * may need to corrupt 4017*0Sstevel@tonic-gate */ 4018*0Sstevel@tonic-gate ep = lp->errentp; 4019*0Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_R) && 4020*0Sstevel@tonic-gate (hp->flags & DDI_DMA_READ) && 4021*0Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 4022*0Sstevel@tonic-gate do_dma_corrupt(hp, ep, DDI_DMA_SYNC_FORCPU, 4023*0Sstevel@tonic-gate 0, hp->len); 4024*0Sstevel@tonic-gate } 4025*0Sstevel@tonic-gate lp->link = bofi_link_freelist; 4026*0Sstevel@tonic-gate bofi_link_freelist = lp; 4027*0Sstevel@tonic-gate lp = next_lp; 4028*0Sstevel@tonic-gate } 4029*0Sstevel@tonic-gate hp->link = NULL; 4030*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4031*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4032*0Sstevel@tonic-gate 4033*0Sstevel@tonic-gate if (bofi_sync_check && (hp->flags & DDI_DMA_READ)) 4034*0Sstevel@tonic-gate if (hp->allocaddr) 4035*0Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 4036*0Sstevel@tonic-gate ddi_dmareq_mapout(hp->mapaddr, hp->len); 4037*0Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) 4038*0Sstevel@tonic-gate ddi_umem_free(hp->umem_cookie); 4039*0Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 4040*0Sstevel@tonic-gate return (retval); 4041*0Sstevel@tonic-gate case DDI_DMA_MOVWIN: 4042*0Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 4043*0Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 4044*0Sstevel@tonic-gate break; 4045*0Sstevel@tonic-gate case DDI_DMA_NEXTWIN: 4046*0Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 4047*0Sstevel@tonic-gate mp->dmai_rflags &= ~DMP_NOSYNC; 4048*0Sstevel@tonic-gate break; 4049*0Sstevel@tonic-gate default: 4050*0Sstevel@tonic-gate break; 4051*0Sstevel@tonic-gate } 4052*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4053*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4054*0Sstevel@tonic-gate return (retval); 4055*0Sstevel@tonic-gate } 4056*0Sstevel@tonic-gate 4057*0Sstevel@tonic-gate #if defined(__sparc) 4058*0Sstevel@tonic-gate /* 4059*0Sstevel@tonic-gate * dvma reserve case from bofi_dma_ctl() 4060*0Sstevel@tonic-gate */ 4061*0Sstevel@tonic-gate static void 4062*0Sstevel@tonic-gate bofi_dvma_reserve(dev_info_t *rdip, ddi_dma_handle_t handle) 4063*0Sstevel@tonic-gate { 4064*0Sstevel@tonic-gate struct bofi_shadow *hp; 4065*0Sstevel@tonic-gate struct bofi_shadow *dummyhp; 4066*0Sstevel@tonic-gate struct bofi_shadow *dhashp; 4067*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 4068*0Sstevel@tonic-gate ddi_dma_impl_t *mp; 4069*0Sstevel@tonic-gate struct fast_dvma *nexus_private; 4070*0Sstevel@tonic-gate int i, count; 4071*0Sstevel@tonic-gate 4072*0Sstevel@tonic-gate mp = (ddi_dma_impl_t *)handle; 4073*0Sstevel@tonic-gate count = mp->dmai_ndvmapages; 4074*0Sstevel@tonic-gate /* 4075*0Sstevel@tonic-gate * allocate dummy shadow handle structure 4076*0Sstevel@tonic-gate */ 4077*0Sstevel@tonic-gate dummyhp = kmem_zalloc(sizeof (*dummyhp), KM_SLEEP); 4078*0Sstevel@tonic-gate if (mp->dmai_rflags & DMP_BYPASSNEXUS) { 4079*0Sstevel@tonic-gate /* 4080*0Sstevel@tonic-gate * overlay our routines over the nexus's dvma routines 4081*0Sstevel@tonic-gate */ 4082*0Sstevel@tonic-gate nexus_private = (struct fast_dvma *)mp->dmai_nexus_private; 4083*0Sstevel@tonic-gate dummyhp->save.dvma_ops = *(nexus_private->ops); 4084*0Sstevel@tonic-gate nexus_private->ops = &bofi_dvma_ops; 4085*0Sstevel@tonic-gate } 4086*0Sstevel@tonic-gate /* 4087*0Sstevel@tonic-gate * now fill in the dummy handle. This just gets put on hhash queue 4088*0Sstevel@tonic-gate * so our dvma routines can find and index off to the handle they 4089*0Sstevel@tonic-gate * really want. 4090*0Sstevel@tonic-gate */ 4091*0Sstevel@tonic-gate (void) strncpy(dummyhp->name, ddi_get_name(rdip), NAMESIZE); 4092*0Sstevel@tonic-gate dummyhp->instance = ddi_get_instance(rdip); 4093*0Sstevel@tonic-gate dummyhp->rnumber = -1; 4094*0Sstevel@tonic-gate dummyhp->dip = rdip; 4095*0Sstevel@tonic-gate dummyhp->len = count; 4096*0Sstevel@tonic-gate dummyhp->hdl.dma_handle = handle; 4097*0Sstevel@tonic-gate dummyhp->link = NULL; 4098*0Sstevel@tonic-gate dummyhp->type = BOFI_NULL; 4099*0Sstevel@tonic-gate /* 4100*0Sstevel@tonic-gate * allocate space for real handles 4101*0Sstevel@tonic-gate */ 4102*0Sstevel@tonic-gate dummyhp->hparrayp = kmem_alloc(count * 4103*0Sstevel@tonic-gate sizeof (struct bofi_shadow *), KM_SLEEP); 4104*0Sstevel@tonic-gate for (i = 0; i < count; i++) { 4105*0Sstevel@tonic-gate /* 4106*0Sstevel@tonic-gate * allocate shadow handle structures and fill them in 4107*0Sstevel@tonic-gate */ 4108*0Sstevel@tonic-gate hp = kmem_zalloc(sizeof (*hp), KM_SLEEP); 4109*0Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 4110*0Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 4111*0Sstevel@tonic-gate hp->rnumber = -1; 4112*0Sstevel@tonic-gate hp->dip = rdip; 4113*0Sstevel@tonic-gate hp->hdl.dma_handle = 0; 4114*0Sstevel@tonic-gate hp->link = NULL; 4115*0Sstevel@tonic-gate hp->type = BOFI_NULL; 4116*0Sstevel@tonic-gate if (bofi_sync_check) { 4117*0Sstevel@tonic-gate unsigned long pagemask = ddi_ptob(rdip, 1) - 1; 4118*0Sstevel@tonic-gate /* 4119*0Sstevel@tonic-gate * Take a copy and set this to be hp->addr 4120*0Sstevel@tonic-gate * Data will be copied to and from the original on 4121*0Sstevel@tonic-gate * explicit and implicit ddi_dma_sync() 4122*0Sstevel@tonic-gate * 4123*0Sstevel@tonic-gate * - maintain page alignment because some devices 4124*0Sstevel@tonic-gate * assume it. 4125*0Sstevel@tonic-gate */ 4126*0Sstevel@tonic-gate hp->allocaddr = ddi_umem_alloc( 4127*0Sstevel@tonic-gate ((int)hp->addr & pagemask) + pagemask + 1, 4128*0Sstevel@tonic-gate KM_SLEEP, &hp->umem_cookie); 4129*0Sstevel@tonic-gate hp->addr = hp->allocaddr + ((int)hp->addr & pagemask); 4130*0Sstevel@tonic-gate } 4131*0Sstevel@tonic-gate /* 4132*0Sstevel@tonic-gate * add to dhash and inuse lists. 4133*0Sstevel@tonic-gate * these don't go on hhash queue. 4134*0Sstevel@tonic-gate */ 4135*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 4136*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4137*0Sstevel@tonic-gate hp->next = shadow_list.next; 4138*0Sstevel@tonic-gate shadow_list.next->prev = hp; 4139*0Sstevel@tonic-gate hp->prev = &shadow_list; 4140*0Sstevel@tonic-gate shadow_list.next = hp; 4141*0Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 4142*0Sstevel@tonic-gate hp->dnext = dhashp->dnext; 4143*0Sstevel@tonic-gate dhashp->dnext->dprev = hp; 4144*0Sstevel@tonic-gate hp->dprev = dhashp; 4145*0Sstevel@tonic-gate dhashp->dnext = hp; 4146*0Sstevel@tonic-gate dummyhp->hparrayp[i] = hp; 4147*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4148*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4149*0Sstevel@tonic-gate } 4150*0Sstevel@tonic-gate /* 4151*0Sstevel@tonic-gate * add dummy handle to hhash list only 4152*0Sstevel@tonic-gate */ 4153*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 4154*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4155*0Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 4156*0Sstevel@tonic-gate dummyhp->hnext = hhashp->hnext; 4157*0Sstevel@tonic-gate hhashp->hnext->hprev = dummyhp; 4158*0Sstevel@tonic-gate dummyhp->hprev = hhashp; 4159*0Sstevel@tonic-gate hhashp->hnext = dummyhp; 4160*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4161*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4162*0Sstevel@tonic-gate } 4163*0Sstevel@tonic-gate 4164*0Sstevel@tonic-gate /* 4165*0Sstevel@tonic-gate * our dvma_kaddr_load() 4166*0Sstevel@tonic-gate */ 4167*0Sstevel@tonic-gate static void 4168*0Sstevel@tonic-gate bofi_dvma_kaddr_load(ddi_dma_handle_t h, caddr_t a, uint_t len, uint_t index, 4169*0Sstevel@tonic-gate ddi_dma_cookie_t *cp) 4170*0Sstevel@tonic-gate { 4171*0Sstevel@tonic-gate struct bofi_shadow *dummyhp; 4172*0Sstevel@tonic-gate struct bofi_shadow *hp; 4173*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 4174*0Sstevel@tonic-gate struct bofi_errent *ep; 4175*0Sstevel@tonic-gate struct bofi_link *lp; 4176*0Sstevel@tonic-gate 4177*0Sstevel@tonic-gate /* 4178*0Sstevel@tonic-gate * check we really have a dummy shadow for this handle 4179*0Sstevel@tonic-gate */ 4180*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 4181*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4182*0Sstevel@tonic-gate hhashp = HDL_HHASH(h); 4183*0Sstevel@tonic-gate for (dummyhp = hhashp->hnext; dummyhp != hhashp; 4184*0Sstevel@tonic-gate dummyhp = dummyhp->hnext) 4185*0Sstevel@tonic-gate if (dummyhp->hdl.dma_handle == h) 4186*0Sstevel@tonic-gate break; 4187*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4188*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4189*0Sstevel@tonic-gate if (dummyhp == hhashp) { 4190*0Sstevel@tonic-gate /* 4191*0Sstevel@tonic-gate * no dummy shadow - panic 4192*0Sstevel@tonic-gate */ 4193*0Sstevel@tonic-gate panic("driver dvma_kaddr_load with no reserve"); 4194*0Sstevel@tonic-gate } 4195*0Sstevel@tonic-gate 4196*0Sstevel@tonic-gate /* 4197*0Sstevel@tonic-gate * find real hp 4198*0Sstevel@tonic-gate */ 4199*0Sstevel@tonic-gate hp = dummyhp->hparrayp[index]; 4200*0Sstevel@tonic-gate /* 4201*0Sstevel@tonic-gate * check its not already loaded 4202*0Sstevel@tonic-gate */ 4203*0Sstevel@tonic-gate if (hp->type != BOFI_NULL) 4204*0Sstevel@tonic-gate panic("driver loading loaded dvma"); 4205*0Sstevel@tonic-gate /* 4206*0Sstevel@tonic-gate * if were doing copying, just need to change origaddr and get 4207*0Sstevel@tonic-gate * nexus to map hp->addr again 4208*0Sstevel@tonic-gate * if not, set hp->addr to new address. 4209*0Sstevel@tonic-gate * - note these are always kernel virtual addresses - no need to map 4210*0Sstevel@tonic-gate */ 4211*0Sstevel@tonic-gate if (bofi_sync_check && hp->allocaddr) { 4212*0Sstevel@tonic-gate hp->origaddr = a; 4213*0Sstevel@tonic-gate a = hp->addr; 4214*0Sstevel@tonic-gate } else 4215*0Sstevel@tonic-gate hp->addr = a; 4216*0Sstevel@tonic-gate hp->len = len; 4217*0Sstevel@tonic-gate /* 4218*0Sstevel@tonic-gate * get nexus to do the real work 4219*0Sstevel@tonic-gate */ 4220*0Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_kaddr_load(h, a, len, index, cp); 4221*0Sstevel@tonic-gate /* 4222*0Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this dma_handle 4223*0Sstevel@tonic-gate * no need to corrupt - there's no implicit dma_sync on this one 4224*0Sstevel@tonic-gate */ 4225*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 4226*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4227*0Sstevel@tonic-gate hp->type = BOFI_DMA_HDL; 4228*0Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 4229*0Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 4230*0Sstevel@tonic-gate ddi_name_to_major(ep->name) && 4231*0Sstevel@tonic-gate hp->instance == ep->errdef.instance && 4232*0Sstevel@tonic-gate (ep->errdef.rnumber == -1 || 4233*0Sstevel@tonic-gate hp->rnumber == ep->errdef.rnumber) && 4234*0Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_RW) && 4235*0Sstevel@tonic-gate (((uintptr_t)(hp->addr + ep->errdef.offset + 4236*0Sstevel@tonic-gate ep->errdef.len) & ~LLSZMASK) > 4237*0Sstevel@tonic-gate ((uintptr_t)((hp->addr + ep->errdef.offset) + 4238*0Sstevel@tonic-gate LLSZMASK) & ~LLSZMASK)))) { 4239*0Sstevel@tonic-gate lp = bofi_link_freelist; 4240*0Sstevel@tonic-gate if (lp != NULL) { 4241*0Sstevel@tonic-gate bofi_link_freelist = lp->link; 4242*0Sstevel@tonic-gate lp->errentp = ep; 4243*0Sstevel@tonic-gate lp->link = hp->link; 4244*0Sstevel@tonic-gate hp->link = lp; 4245*0Sstevel@tonic-gate } 4246*0Sstevel@tonic-gate } 4247*0Sstevel@tonic-gate } 4248*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4249*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4250*0Sstevel@tonic-gate } 4251*0Sstevel@tonic-gate 4252*0Sstevel@tonic-gate /* 4253*0Sstevel@tonic-gate * our dvma_unload() 4254*0Sstevel@tonic-gate */ 4255*0Sstevel@tonic-gate static void 4256*0Sstevel@tonic-gate bofi_dvma_unload(ddi_dma_handle_t h, uint_t index, uint_t view) 4257*0Sstevel@tonic-gate { 4258*0Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 4259*0Sstevel@tonic-gate struct bofi_errent *ep; 4260*0Sstevel@tonic-gate struct bofi_shadow *dummyhp; 4261*0Sstevel@tonic-gate struct bofi_shadow *hp; 4262*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 4263*0Sstevel@tonic-gate 4264*0Sstevel@tonic-gate /* 4265*0Sstevel@tonic-gate * check we really have a dummy shadow for this handle 4266*0Sstevel@tonic-gate */ 4267*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 4268*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4269*0Sstevel@tonic-gate hhashp = HDL_HHASH(h); 4270*0Sstevel@tonic-gate for (dummyhp = hhashp->hnext; dummyhp != hhashp; 4271*0Sstevel@tonic-gate dummyhp = dummyhp->hnext) 4272*0Sstevel@tonic-gate if (dummyhp->hdl.dma_handle == h) 4273*0Sstevel@tonic-gate break; 4274*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4275*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4276*0Sstevel@tonic-gate if (dummyhp == hhashp) { 4277*0Sstevel@tonic-gate /* 4278*0Sstevel@tonic-gate * no dummy shadow - panic 4279*0Sstevel@tonic-gate */ 4280*0Sstevel@tonic-gate panic("driver dvma_unload with no reserve"); 4281*0Sstevel@tonic-gate } 4282*0Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_unload(h, index, view); 4283*0Sstevel@tonic-gate /* 4284*0Sstevel@tonic-gate * find real hp 4285*0Sstevel@tonic-gate */ 4286*0Sstevel@tonic-gate hp = dummyhp->hparrayp[index]; 4287*0Sstevel@tonic-gate /* 4288*0Sstevel@tonic-gate * check its not already unloaded 4289*0Sstevel@tonic-gate */ 4290*0Sstevel@tonic-gate if (hp->type == BOFI_NULL) 4291*0Sstevel@tonic-gate panic("driver unloading unloaded dvma"); 4292*0Sstevel@tonic-gate /* 4293*0Sstevel@tonic-gate * free any errdef link structures tagged on to this 4294*0Sstevel@tonic-gate * shadow handle - do corruption if necessary 4295*0Sstevel@tonic-gate */ 4296*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 4297*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4298*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 4299*0Sstevel@tonic-gate next_lp = lp->link; 4300*0Sstevel@tonic-gate ep = lp->errentp; 4301*0Sstevel@tonic-gate if ((ep->errdef.access_type & BOFI_DMA_R) && 4302*0Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || 4303*0Sstevel@tonic-gate view == DDI_DMA_SYNC_FORKERNEL) && 4304*0Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 4305*0Sstevel@tonic-gate do_dma_corrupt(hp, ep, view, 0, hp->len); 4306*0Sstevel@tonic-gate } 4307*0Sstevel@tonic-gate lp->link = bofi_link_freelist; 4308*0Sstevel@tonic-gate bofi_link_freelist = lp; 4309*0Sstevel@tonic-gate lp = next_lp; 4310*0Sstevel@tonic-gate } 4311*0Sstevel@tonic-gate hp->link = NULL; 4312*0Sstevel@tonic-gate hp->type = BOFI_NULL; 4313*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4314*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4315*0Sstevel@tonic-gate /* 4316*0Sstevel@tonic-gate * if there is an explicit sync_for_cpu, then do copy to original 4317*0Sstevel@tonic-gate */ 4318*0Sstevel@tonic-gate if (bofi_sync_check && 4319*0Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL)) 4320*0Sstevel@tonic-gate if (hp->allocaddr) 4321*0Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 4322*0Sstevel@tonic-gate } 4323*0Sstevel@tonic-gate 4324*0Sstevel@tonic-gate /* 4325*0Sstevel@tonic-gate * our dvma_unload() 4326*0Sstevel@tonic-gate */ 4327*0Sstevel@tonic-gate static void 4328*0Sstevel@tonic-gate bofi_dvma_sync(ddi_dma_handle_t h, uint_t index, uint_t view) 4329*0Sstevel@tonic-gate { 4330*0Sstevel@tonic-gate struct bofi_link *lp; 4331*0Sstevel@tonic-gate struct bofi_errent *ep; 4332*0Sstevel@tonic-gate struct bofi_shadow *hp; 4333*0Sstevel@tonic-gate struct bofi_shadow *dummyhp; 4334*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 4335*0Sstevel@tonic-gate 4336*0Sstevel@tonic-gate /* 4337*0Sstevel@tonic-gate * check we really have a dummy shadow for this handle 4338*0Sstevel@tonic-gate */ 4339*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 4340*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4341*0Sstevel@tonic-gate hhashp = HDL_HHASH(h); 4342*0Sstevel@tonic-gate for (dummyhp = hhashp->hnext; dummyhp != hhashp; 4343*0Sstevel@tonic-gate dummyhp = dummyhp->hnext) 4344*0Sstevel@tonic-gate if (dummyhp->hdl.dma_handle == h) 4345*0Sstevel@tonic-gate break; 4346*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4347*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4348*0Sstevel@tonic-gate if (dummyhp == hhashp) { 4349*0Sstevel@tonic-gate /* 4350*0Sstevel@tonic-gate * no dummy shadow - panic 4351*0Sstevel@tonic-gate */ 4352*0Sstevel@tonic-gate panic("driver dvma_sync with no reserve"); 4353*0Sstevel@tonic-gate } 4354*0Sstevel@tonic-gate /* 4355*0Sstevel@tonic-gate * find real hp 4356*0Sstevel@tonic-gate */ 4357*0Sstevel@tonic-gate hp = dummyhp->hparrayp[index]; 4358*0Sstevel@tonic-gate /* 4359*0Sstevel@tonic-gate * check its already loaded 4360*0Sstevel@tonic-gate */ 4361*0Sstevel@tonic-gate if (hp->type == BOFI_NULL) 4362*0Sstevel@tonic-gate panic("driver syncing unloaded dvma"); 4363*0Sstevel@tonic-gate if (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL) 4364*0Sstevel@tonic-gate /* 4365*0Sstevel@tonic-gate * in this case do sync first 4366*0Sstevel@tonic-gate */ 4367*0Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_sync(h, index, view); 4368*0Sstevel@tonic-gate /* 4369*0Sstevel@tonic-gate * if there is an explicit sync_for_dev, then do copy from original 4370*0Sstevel@tonic-gate */ 4371*0Sstevel@tonic-gate if (bofi_sync_check && view == DDI_DMA_SYNC_FORDEV) { 4372*0Sstevel@tonic-gate if (hp->allocaddr) 4373*0Sstevel@tonic-gate xbcopy(hp->origaddr, hp->addr, hp->len); 4374*0Sstevel@tonic-gate } 4375*0Sstevel@tonic-gate /* 4376*0Sstevel@tonic-gate * do corruption if necessary 4377*0Sstevel@tonic-gate */ 4378*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 4379*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4380*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 4381*0Sstevel@tonic-gate ep = lp->errentp; 4382*0Sstevel@tonic-gate if ((((ep->errdef.access_type & BOFI_DMA_R) && 4383*0Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || 4384*0Sstevel@tonic-gate view == DDI_DMA_SYNC_FORKERNEL)) || 4385*0Sstevel@tonic-gate ((ep->errdef.access_type & BOFI_DMA_W) && 4386*0Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORDEV))) && 4387*0Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 4388*0Sstevel@tonic-gate do_dma_corrupt(hp, ep, view, 0, hp->len); 4389*0Sstevel@tonic-gate } 4390*0Sstevel@tonic-gate } 4391*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4392*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4393*0Sstevel@tonic-gate /* 4394*0Sstevel@tonic-gate * if there is an explicit sync_for_cpu, then do copy to original 4395*0Sstevel@tonic-gate */ 4396*0Sstevel@tonic-gate if (bofi_sync_check && 4397*0Sstevel@tonic-gate (view == DDI_DMA_SYNC_FORCPU || view == DDI_DMA_SYNC_FORKERNEL)) { 4398*0Sstevel@tonic-gate if (hp->allocaddr) 4399*0Sstevel@tonic-gate xbcopy(hp->addr, hp->origaddr, hp->len); 4400*0Sstevel@tonic-gate } 4401*0Sstevel@tonic-gate if (view == DDI_DMA_SYNC_FORDEV) 4402*0Sstevel@tonic-gate /* 4403*0Sstevel@tonic-gate * in this case do sync last 4404*0Sstevel@tonic-gate */ 4405*0Sstevel@tonic-gate dummyhp->save.dvma_ops.dvma_sync(h, index, view); 4406*0Sstevel@tonic-gate } 4407*0Sstevel@tonic-gate #endif 4408*0Sstevel@tonic-gate 4409*0Sstevel@tonic-gate /* 4410*0Sstevel@tonic-gate * bofi intercept routine - gets called instead of users interrupt routine 4411*0Sstevel@tonic-gate */ 4412*0Sstevel@tonic-gate static uint_t 4413*0Sstevel@tonic-gate bofi_intercept_intr(caddr_t xp) 4414*0Sstevel@tonic-gate { 4415*0Sstevel@tonic-gate struct bofi_errent *ep; 4416*0Sstevel@tonic-gate struct bofi_link *lp; 4417*0Sstevel@tonic-gate struct bofi_shadow *hp; 4418*0Sstevel@tonic-gate int intr_count = 1; 4419*0Sstevel@tonic-gate int i; 4420*0Sstevel@tonic-gate uint_t retval = DDI_INTR_UNCLAIMED; 4421*0Sstevel@tonic-gate uint_t result; 4422*0Sstevel@tonic-gate int unclaimed_counter = 0; 4423*0Sstevel@tonic-gate int jabber_detected = 0; 4424*0Sstevel@tonic-gate 4425*0Sstevel@tonic-gate hp = (struct bofi_shadow *)xp; 4426*0Sstevel@tonic-gate /* 4427*0Sstevel@tonic-gate * check if nothing to do 4428*0Sstevel@tonic-gate */ 4429*0Sstevel@tonic-gate if (hp->link == NULL) 4430*0Sstevel@tonic-gate return (hp->save.intr.int_handler 4431*0Sstevel@tonic-gate (hp->save.intr.int_handler_arg1, NULL)); 4432*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4433*0Sstevel@tonic-gate /* 4434*0Sstevel@tonic-gate * look for any errdefs 4435*0Sstevel@tonic-gate */ 4436*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 4437*0Sstevel@tonic-gate ep = lp->errentp; 4438*0Sstevel@tonic-gate if (ep->state & BOFI_DEV_ACTIVE) { 4439*0Sstevel@tonic-gate /* 4440*0Sstevel@tonic-gate * got one 4441*0Sstevel@tonic-gate */ 4442*0Sstevel@tonic-gate if ((ep->errdef.access_count || 4443*0Sstevel@tonic-gate ep->errdef.fail_count) && 4444*0Sstevel@tonic-gate (ep->errdef.access_type & BOFI_LOG)) 4445*0Sstevel@tonic-gate log_acc_event(ep, BOFI_INTR, 0, 0, 1, 0); 4446*0Sstevel@tonic-gate if (ep->errdef.access_count > 1) { 4447*0Sstevel@tonic-gate ep->errdef.access_count--; 4448*0Sstevel@tonic-gate } else if (ep->errdef.fail_count > 0) { 4449*0Sstevel@tonic-gate ep->errdef.fail_count--; 4450*0Sstevel@tonic-gate ep->errdef.access_count = 0; 4451*0Sstevel@tonic-gate /* 4452*0Sstevel@tonic-gate * OK do "corruption" 4453*0Sstevel@tonic-gate */ 4454*0Sstevel@tonic-gate if (ep->errstate.fail_time == 0) 4455*0Sstevel@tonic-gate ep->errstate.fail_time = bofi_gettime(); 4456*0Sstevel@tonic-gate switch (ep->errdef.optype) { 4457*0Sstevel@tonic-gate case BOFI_DELAY_INTR: 4458*0Sstevel@tonic-gate if (!hp->hilevel) { 4459*0Sstevel@tonic-gate drv_usecwait 4460*0Sstevel@tonic-gate (ep->errdef.operand); 4461*0Sstevel@tonic-gate } 4462*0Sstevel@tonic-gate break; 4463*0Sstevel@tonic-gate case BOFI_LOSE_INTR: 4464*0Sstevel@tonic-gate intr_count = 0; 4465*0Sstevel@tonic-gate break; 4466*0Sstevel@tonic-gate case BOFI_EXTRA_INTR: 4467*0Sstevel@tonic-gate intr_count += ep->errdef.operand; 4468*0Sstevel@tonic-gate break; 4469*0Sstevel@tonic-gate default: 4470*0Sstevel@tonic-gate break; 4471*0Sstevel@tonic-gate } 4472*0Sstevel@tonic-gate } 4473*0Sstevel@tonic-gate } 4474*0Sstevel@tonic-gate } 4475*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4476*0Sstevel@tonic-gate /* 4477*0Sstevel@tonic-gate * send extra or fewer interrupts as requested 4478*0Sstevel@tonic-gate */ 4479*0Sstevel@tonic-gate for (i = 0; i < intr_count; i++) { 4480*0Sstevel@tonic-gate result = hp->save.intr.int_handler 4481*0Sstevel@tonic-gate (hp->save.intr.int_handler_arg1, NULL); 4482*0Sstevel@tonic-gate if (result == DDI_INTR_CLAIMED) 4483*0Sstevel@tonic-gate unclaimed_counter >>= 1; 4484*0Sstevel@tonic-gate else if (++unclaimed_counter >= 20) 4485*0Sstevel@tonic-gate jabber_detected = 1; 4486*0Sstevel@tonic-gate if (i == 0) 4487*0Sstevel@tonic-gate retval = result; 4488*0Sstevel@tonic-gate } 4489*0Sstevel@tonic-gate /* 4490*0Sstevel@tonic-gate * if more than 1000 spurious interrupts requested and 4491*0Sstevel@tonic-gate * jabber not detected - give warning 4492*0Sstevel@tonic-gate */ 4493*0Sstevel@tonic-gate if (intr_count > 1000 && !jabber_detected) 4494*0Sstevel@tonic-gate panic("undetected interrupt jabber: %s%d", 4495*0Sstevel@tonic-gate hp->name, hp->instance); 4496*0Sstevel@tonic-gate /* 4497*0Sstevel@tonic-gate * return first response - or "unclaimed" if none 4498*0Sstevel@tonic-gate */ 4499*0Sstevel@tonic-gate return (retval); 4500*0Sstevel@tonic-gate } 4501*0Sstevel@tonic-gate 4502*0Sstevel@tonic-gate 4503*0Sstevel@tonic-gate /* 4504*0Sstevel@tonic-gate * our ddi_check_acc_hdl 4505*0Sstevel@tonic-gate */ 4506*0Sstevel@tonic-gate /* ARGSUSED */ 4507*0Sstevel@tonic-gate static int 4508*0Sstevel@tonic-gate bofi_check_acc_hdl(ddi_acc_impl_t *handle) 4509*0Sstevel@tonic-gate { 4510*0Sstevel@tonic-gate struct bofi_shadow *hp; 4511*0Sstevel@tonic-gate struct bofi_link *lp; 4512*0Sstevel@tonic-gate uint_t result = 0; 4513*0Sstevel@tonic-gate 4514*0Sstevel@tonic-gate hp = handle->ahi_common.ah_bus_private; 4515*0Sstevel@tonic-gate if (!hp->link || !mutex_tryenter(&bofi_mutex)) { 4516*0Sstevel@tonic-gate return (0); 4517*0Sstevel@tonic-gate } 4518*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 4519*0Sstevel@tonic-gate /* 4520*0Sstevel@tonic-gate * OR in error state from all associated 4521*0Sstevel@tonic-gate * errdef structures 4522*0Sstevel@tonic-gate */ 4523*0Sstevel@tonic-gate if (lp->errentp->errdef.access_count == 0 && 4524*0Sstevel@tonic-gate (lp->errentp->state & BOFI_DEV_ACTIVE)) { 4525*0Sstevel@tonic-gate result = (lp->errentp->errdef.acc_chk & 1); 4526*0Sstevel@tonic-gate } 4527*0Sstevel@tonic-gate } 4528*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4529*0Sstevel@tonic-gate return (result); 4530*0Sstevel@tonic-gate } 4531*0Sstevel@tonic-gate 4532*0Sstevel@tonic-gate /* 4533*0Sstevel@tonic-gate * our ddi_check_dma_hdl 4534*0Sstevel@tonic-gate */ 4535*0Sstevel@tonic-gate /* ARGSUSED */ 4536*0Sstevel@tonic-gate static int 4537*0Sstevel@tonic-gate bofi_check_dma_hdl(ddi_dma_impl_t *handle) 4538*0Sstevel@tonic-gate { 4539*0Sstevel@tonic-gate struct bofi_shadow *hp; 4540*0Sstevel@tonic-gate struct bofi_link *lp; 4541*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 4542*0Sstevel@tonic-gate uint_t result = 0; 4543*0Sstevel@tonic-gate 4544*0Sstevel@tonic-gate if (!mutex_tryenter(&bofi_mutex)) { 4545*0Sstevel@tonic-gate return (0); 4546*0Sstevel@tonic-gate } 4547*0Sstevel@tonic-gate hhashp = HDL_HHASH(handle); 4548*0Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) 4549*0Sstevel@tonic-gate if (hp->hdl.dma_handle == (ddi_dma_handle_t)handle) 4550*0Sstevel@tonic-gate break; 4551*0Sstevel@tonic-gate if (hp == hhashp) { 4552*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4553*0Sstevel@tonic-gate return (0); 4554*0Sstevel@tonic-gate } 4555*0Sstevel@tonic-gate if (!hp->link) { 4556*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4557*0Sstevel@tonic-gate return (0); 4558*0Sstevel@tonic-gate } 4559*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 4560*0Sstevel@tonic-gate /* 4561*0Sstevel@tonic-gate * OR in error state from all associated 4562*0Sstevel@tonic-gate * errdef structures 4563*0Sstevel@tonic-gate */ 4564*0Sstevel@tonic-gate if (lp->errentp->errdef.access_count == 0 && 4565*0Sstevel@tonic-gate (lp->errentp->state & BOFI_DEV_ACTIVE)) { 4566*0Sstevel@tonic-gate result = ((lp->errentp->errdef.acc_chk & 2) ? 1 : 0); 4567*0Sstevel@tonic-gate } 4568*0Sstevel@tonic-gate } 4569*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4570*0Sstevel@tonic-gate return (result); 4571*0Sstevel@tonic-gate } 4572*0Sstevel@tonic-gate 4573*0Sstevel@tonic-gate 4574*0Sstevel@tonic-gate /* ARGSUSED */ 4575*0Sstevel@tonic-gate static int 4576*0Sstevel@tonic-gate bofi_post_event(dev_info_t *dip, dev_info_t *rdip, 4577*0Sstevel@tonic-gate ddi_eventcookie_t eventhdl, void *impl_data) 4578*0Sstevel@tonic-gate { 4579*0Sstevel@tonic-gate ddi_eventcookie_t ec; 4580*0Sstevel@tonic-gate struct ddi_fault_event_data *arg; 4581*0Sstevel@tonic-gate struct bofi_errent *ep; 4582*0Sstevel@tonic-gate struct bofi_shadow *hp; 4583*0Sstevel@tonic-gate struct bofi_shadow *dhashp; 4584*0Sstevel@tonic-gate struct bofi_link *lp; 4585*0Sstevel@tonic-gate 4586*0Sstevel@tonic-gate ASSERT(eventhdl); 4587*0Sstevel@tonic-gate if (ddi_get_eventcookie(dip, DDI_DEVI_FAULT_EVENT, &ec) != DDI_SUCCESS) 4588*0Sstevel@tonic-gate return (DDI_FAILURE); 4589*0Sstevel@tonic-gate 4590*0Sstevel@tonic-gate if (ec != eventhdl) 4591*0Sstevel@tonic-gate return (save_bus_ops.bus_post_event(dip, rdip, eventhdl, 4592*0Sstevel@tonic-gate impl_data)); 4593*0Sstevel@tonic-gate 4594*0Sstevel@tonic-gate arg = (struct ddi_fault_event_data *)impl_data; 4595*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4596*0Sstevel@tonic-gate /* 4597*0Sstevel@tonic-gate * find shadow handles with appropriate dev_infos 4598*0Sstevel@tonic-gate * and set error reported on all associated errdef structures 4599*0Sstevel@tonic-gate */ 4600*0Sstevel@tonic-gate dhashp = HDL_DHASH(arg->f_dip); 4601*0Sstevel@tonic-gate for (hp = dhashp->dnext; hp != dhashp; hp = hp->dnext) { 4602*0Sstevel@tonic-gate if (hp->dip == arg->f_dip) { 4603*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; lp = lp->link) { 4604*0Sstevel@tonic-gate ep = lp->errentp; 4605*0Sstevel@tonic-gate ep->errstate.errmsg_count++; 4606*0Sstevel@tonic-gate if ((ep->errstate.msg_time == NULL || 4607*0Sstevel@tonic-gate ep->errstate.severity > arg->f_impact) && 4608*0Sstevel@tonic-gate (ep->state & BOFI_DEV_ACTIVE)) { 4609*0Sstevel@tonic-gate ep->errstate.msg_time = bofi_gettime(); 4610*0Sstevel@tonic-gate ep->errstate.severity = arg->f_impact; 4611*0Sstevel@tonic-gate (void) strncpy(ep->errstate.buffer, 4612*0Sstevel@tonic-gate arg->f_message, ERRMSGSIZE); 4613*0Sstevel@tonic-gate ddi_trigger_softintr(ep->softintr_id); 4614*0Sstevel@tonic-gate } 4615*0Sstevel@tonic-gate } 4616*0Sstevel@tonic-gate } 4617*0Sstevel@tonic-gate } 4618*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4619*0Sstevel@tonic-gate return (save_bus_ops.bus_post_event(dip, rdip, eventhdl, impl_data)); 4620*0Sstevel@tonic-gate } 4621*0Sstevel@tonic-gate 4622*0Sstevel@tonic-gate /* 4623*0Sstevel@tonic-gate * our intr_ops routine 4624*0Sstevel@tonic-gate */ 4625*0Sstevel@tonic-gate static int 4626*0Sstevel@tonic-gate bofi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 4627*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 4628*0Sstevel@tonic-gate { 4629*0Sstevel@tonic-gate int retval; 4630*0Sstevel@tonic-gate struct bofi_shadow *hp; 4631*0Sstevel@tonic-gate struct bofi_shadow *dhashp; 4632*0Sstevel@tonic-gate struct bofi_shadow *hhashp; 4633*0Sstevel@tonic-gate struct bofi_errent *ep; 4634*0Sstevel@tonic-gate struct bofi_link *lp, *next_lp; 4635*0Sstevel@tonic-gate 4636*0Sstevel@tonic-gate switch (intr_op) { 4637*0Sstevel@tonic-gate case DDI_INTROP_ADDISR: 4638*0Sstevel@tonic-gate /* 4639*0Sstevel@tonic-gate * if driver_list is set, only intercept those drivers 4640*0Sstevel@tonic-gate */ 4641*0Sstevel@tonic-gate if (!driver_under_test(rdip)) 4642*0Sstevel@tonic-gate return (save_bus_ops.bus_intr_op(dip, rdip, 4643*0Sstevel@tonic-gate intr_op, hdlp, result)); 4644*0Sstevel@tonic-gate /* 4645*0Sstevel@tonic-gate * allocate shadow handle structure and fill in 4646*0Sstevel@tonic-gate */ 4647*0Sstevel@tonic-gate hp = kmem_zalloc(sizeof (struct bofi_shadow), KM_SLEEP); 4648*0Sstevel@tonic-gate (void) strncpy(hp->name, ddi_get_name(rdip), NAMESIZE); 4649*0Sstevel@tonic-gate hp->instance = ddi_get_instance(rdip); 4650*0Sstevel@tonic-gate hp->save.intr.int_handler = hdlp->ih_cb_func; 4651*0Sstevel@tonic-gate hp->save.intr.int_handler_arg1 = hdlp->ih_cb_arg1; 4652*0Sstevel@tonic-gate hdlp->ih_cb_func = (ddi_intr_handler_t *)bofi_intercept_intr; 4653*0Sstevel@tonic-gate hdlp->ih_cb_arg1 = (caddr_t)hp; 4654*0Sstevel@tonic-gate hp->bofi_inum = hdlp->ih_inum; 4655*0Sstevel@tonic-gate hp->dip = rdip; 4656*0Sstevel@tonic-gate hp->link = NULL; 4657*0Sstevel@tonic-gate hp->type = BOFI_INT_HDL; 4658*0Sstevel@tonic-gate /* 4659*0Sstevel@tonic-gate * save whether hilevel or not 4660*0Sstevel@tonic-gate */ 4661*0Sstevel@tonic-gate 4662*0Sstevel@tonic-gate if (hdlp->ih_pri >= ddi_intr_get_hilevel_pri()) 4663*0Sstevel@tonic-gate hp->hilevel = 1; 4664*0Sstevel@tonic-gate else 4665*0Sstevel@tonic-gate hp->hilevel = 0; 4666*0Sstevel@tonic-gate 4667*0Sstevel@tonic-gate /* 4668*0Sstevel@tonic-gate * call nexus to do real work, but specifying our handler, and 4669*0Sstevel@tonic-gate * our shadow handle as argument 4670*0Sstevel@tonic-gate */ 4671*0Sstevel@tonic-gate retval = save_bus_ops.bus_intr_op(dip, rdip, 4672*0Sstevel@tonic-gate intr_op, hdlp, result); 4673*0Sstevel@tonic-gate if (retval != DDI_SUCCESS) { 4674*0Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 4675*0Sstevel@tonic-gate return (retval); 4676*0Sstevel@tonic-gate } 4677*0Sstevel@tonic-gate /* 4678*0Sstevel@tonic-gate * add to dhash, hhash and inuse lists 4679*0Sstevel@tonic-gate */ 4680*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 4681*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4682*0Sstevel@tonic-gate hp->next = shadow_list.next; 4683*0Sstevel@tonic-gate shadow_list.next->prev = hp; 4684*0Sstevel@tonic-gate hp->prev = &shadow_list; 4685*0Sstevel@tonic-gate shadow_list.next = hp; 4686*0Sstevel@tonic-gate hhashp = HDL_HHASH(hdlp->ih_inum); 4687*0Sstevel@tonic-gate hp->hnext = hhashp->hnext; 4688*0Sstevel@tonic-gate hhashp->hnext->hprev = hp; 4689*0Sstevel@tonic-gate hp->hprev = hhashp; 4690*0Sstevel@tonic-gate hhashp->hnext = hp; 4691*0Sstevel@tonic-gate dhashp = HDL_DHASH(hp->dip); 4692*0Sstevel@tonic-gate hp->dnext = dhashp->dnext; 4693*0Sstevel@tonic-gate dhashp->dnext->dprev = hp; 4694*0Sstevel@tonic-gate hp->dprev = dhashp; 4695*0Sstevel@tonic-gate dhashp->dnext = hp; 4696*0Sstevel@tonic-gate /* 4697*0Sstevel@tonic-gate * chain on any pre-existing errdefs that apply to this 4698*0Sstevel@tonic-gate * acc_handle 4699*0Sstevel@tonic-gate */ 4700*0Sstevel@tonic-gate for (ep = errent_listp; ep != NULL; ep = ep->next) { 4701*0Sstevel@tonic-gate if (ddi_name_to_major(hp->name) == 4702*0Sstevel@tonic-gate ddi_name_to_major(ep->name) && 4703*0Sstevel@tonic-gate hp->instance == ep->errdef.instance && 4704*0Sstevel@tonic-gate (ep->errdef.access_type & BOFI_INTR)) { 4705*0Sstevel@tonic-gate lp = bofi_link_freelist; 4706*0Sstevel@tonic-gate if (lp != NULL) { 4707*0Sstevel@tonic-gate bofi_link_freelist = lp->link; 4708*0Sstevel@tonic-gate lp->errentp = ep; 4709*0Sstevel@tonic-gate lp->link = hp->link; 4710*0Sstevel@tonic-gate hp->link = lp; 4711*0Sstevel@tonic-gate } 4712*0Sstevel@tonic-gate } 4713*0Sstevel@tonic-gate } 4714*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4715*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4716*0Sstevel@tonic-gate return (retval); 4717*0Sstevel@tonic-gate case DDI_INTROP_REMISR: 4718*0Sstevel@tonic-gate /* 4719*0Sstevel@tonic-gate * call nexus routine first 4720*0Sstevel@tonic-gate */ 4721*0Sstevel@tonic-gate retval = save_bus_ops.bus_intr_op(dip, rdip, 4722*0Sstevel@tonic-gate intr_op, hdlp, result); 4723*0Sstevel@tonic-gate /* 4724*0Sstevel@tonic-gate * find shadow handle 4725*0Sstevel@tonic-gate */ 4726*0Sstevel@tonic-gate mutex_enter(&bofi_low_mutex); 4727*0Sstevel@tonic-gate mutex_enter(&bofi_mutex); 4728*0Sstevel@tonic-gate hhashp = HDL_HHASH(hdlp->ih_inum); 4729*0Sstevel@tonic-gate for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) { 4730*0Sstevel@tonic-gate if (hp->dip == rdip && 4731*0Sstevel@tonic-gate hp->type == BOFI_INT_HDL && 4732*0Sstevel@tonic-gate hp->bofi_inum == hdlp->ih_inum) { 4733*0Sstevel@tonic-gate break; 4734*0Sstevel@tonic-gate } 4735*0Sstevel@tonic-gate } 4736*0Sstevel@tonic-gate if (hp == hhashp) { 4737*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4738*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4739*0Sstevel@tonic-gate return (retval); 4740*0Sstevel@tonic-gate } 4741*0Sstevel@tonic-gate /* 4742*0Sstevel@tonic-gate * found one - remove from dhash, hhash and inuse lists 4743*0Sstevel@tonic-gate */ 4744*0Sstevel@tonic-gate hp->hnext->hprev = hp->hprev; 4745*0Sstevel@tonic-gate hp->hprev->hnext = hp->hnext; 4746*0Sstevel@tonic-gate hp->dnext->dprev = hp->dprev; 4747*0Sstevel@tonic-gate hp->dprev->dnext = hp->dnext; 4748*0Sstevel@tonic-gate hp->next->prev = hp->prev; 4749*0Sstevel@tonic-gate hp->prev->next = hp->next; 4750*0Sstevel@tonic-gate /* 4751*0Sstevel@tonic-gate * free any errdef link structures 4752*0Sstevel@tonic-gate * tagged on to this shadow handle 4753*0Sstevel@tonic-gate */ 4754*0Sstevel@tonic-gate for (lp = hp->link; lp != NULL; ) { 4755*0Sstevel@tonic-gate next_lp = lp->link; 4756*0Sstevel@tonic-gate lp->link = bofi_link_freelist; 4757*0Sstevel@tonic-gate bofi_link_freelist = lp; 4758*0Sstevel@tonic-gate lp = next_lp; 4759*0Sstevel@tonic-gate } 4760*0Sstevel@tonic-gate hp->link = NULL; 4761*0Sstevel@tonic-gate mutex_exit(&bofi_mutex); 4762*0Sstevel@tonic-gate mutex_exit(&bofi_low_mutex); 4763*0Sstevel@tonic-gate kmem_free(hp, sizeof (struct bofi_shadow)); 4764*0Sstevel@tonic-gate return (retval); 4765*0Sstevel@tonic-gate default: 4766*0Sstevel@tonic-gate return (save_bus_ops.bus_intr_op(dip, rdip, 4767*0Sstevel@tonic-gate intr_op, hdlp, result)); 4768*0Sstevel@tonic-gate } 4769*0Sstevel@tonic-gate } 4770