1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/modhash.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/open.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/mode.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/ddi_implfuncs.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/hwconf.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/thread.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/consdev.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate extern struct dev_ops nodev_ops; 61*7c478bd9Sstevel@tonic-gate extern struct dev_ops mod_nodev_ops; 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate struct mod_noload { 64*7c478bd9Sstevel@tonic-gate struct mod_noload *mn_next; 65*7c478bd9Sstevel@tonic-gate char *mn_name; 66*7c478bd9Sstevel@tonic-gate }; 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate /* 69*7c478bd9Sstevel@tonic-gate * Function prototypes 70*7c478bd9Sstevel@tonic-gate */ 71*7c478bd9Sstevel@tonic-gate static int init_stubs(struct modctl *, struct mod_modinfo *); 72*7c478bd9Sstevel@tonic-gate static int nm_hash(char *); 73*7c478bd9Sstevel@tonic-gate static void make_syscallname(char *, int); 74*7c478bd9Sstevel@tonic-gate static void hwc_hash_init(); 75*7c478bd9Sstevel@tonic-gate static void hwc_hash(struct hwc_spec *, major_t); 76*7c478bd9Sstevel@tonic-gate static void hwc_unhash(struct hwc_spec *); 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate struct dev_ops * 79*7c478bd9Sstevel@tonic-gate mod_hold_dev_by_major(major_t major) 80*7c478bd9Sstevel@tonic-gate { 81*7c478bd9Sstevel@tonic-gate struct dev_ops **devopspp, *ops; 82*7c478bd9Sstevel@tonic-gate int loaded; 83*7c478bd9Sstevel@tonic-gate char *drvname; 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate if (major >= devcnt) 86*7c478bd9Sstevel@tonic-gate return (NULL); 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&(devnamesp[major].dn_lock)); 89*7c478bd9Sstevel@tonic-gate devopspp = &devopsp[major]; 90*7c478bd9Sstevel@tonic-gate loaded = 1; 91*7c478bd9Sstevel@tonic-gate while (loaded && !CB_DRV_INSTALLED(*devopspp)) { 92*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&(devnamesp[major].dn_lock)); 93*7c478bd9Sstevel@tonic-gate drvname = mod_major_to_name(major); 94*7c478bd9Sstevel@tonic-gate if (drvname == NULL) 95*7c478bd9Sstevel@tonic-gate return (NULL); 96*7c478bd9Sstevel@tonic-gate loaded = (modload("drv", drvname) != -1); 97*7c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&(devnamesp[major].dn_lock)); 98*7c478bd9Sstevel@tonic-gate } 99*7c478bd9Sstevel@tonic-gate if (loaded) { 100*7c478bd9Sstevel@tonic-gate INCR_DEV_OPS_REF(*devopspp); 101*7c478bd9Sstevel@tonic-gate ops = *devopspp; 102*7c478bd9Sstevel@tonic-gate } else { 103*7c478bd9Sstevel@tonic-gate ops = NULL; 104*7c478bd9Sstevel@tonic-gate } 105*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&(devnamesp[major].dn_lock)); 106*7c478bd9Sstevel@tonic-gate return (ops); 107*7c478bd9Sstevel@tonic-gate } 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate #ifdef DEBUG_RELE 110*7c478bd9Sstevel@tonic-gate static int mod_rele_pause = DEBUG_RELE; 111*7c478bd9Sstevel@tonic-gate #endif /* DEBUG_RELE */ 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate void 114*7c478bd9Sstevel@tonic-gate mod_rele_dev_by_major(major_t major) 115*7c478bd9Sstevel@tonic-gate { 116*7c478bd9Sstevel@tonic-gate struct dev_ops *ops; 117*7c478bd9Sstevel@tonic-gate struct devnames *dnp; 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate if (major >= devcnt) 120*7c478bd9Sstevel@tonic-gate return; 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate dnp = &devnamesp[major]; 123*7c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 124*7c478bd9Sstevel@tonic-gate ops = devopsp[major]; 125*7c478bd9Sstevel@tonic-gate ASSERT(CB_DRV_INSTALLED(ops)); 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate #ifdef DEBUG_RELE 128*7c478bd9Sstevel@tonic-gate if (!DEV_OPS_HELD(ops)) { 129*7c478bd9Sstevel@tonic-gate char *s; 130*7c478bd9Sstevel@tonic-gate static char *msg = "mod_rele_dev_by_major: unheld driver!"; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate printf("mod_rele_dev_by_major: Major dev <%u>, name <%s>\n", 133*7c478bd9Sstevel@tonic-gate (uint_t)major, 134*7c478bd9Sstevel@tonic-gate (s = mod_major_to_name(major)) ? s : "unknown"); 135*7c478bd9Sstevel@tonic-gate if (mod_rele_pause) 136*7c478bd9Sstevel@tonic-gate debug_enter(msg); 137*7c478bd9Sstevel@tonic-gate else 138*7c478bd9Sstevel@tonic-gate printf("%s\n", msg); 139*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 140*7c478bd9Sstevel@tonic-gate return; /* XXX: Note changed behavior */ 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate #endif /* DEBUG_RELE */ 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate if (!DEV_OPS_HELD(ops)) { 146*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, 147*7c478bd9Sstevel@tonic-gate "mod_rele_dev_by_major: Unheld driver: major number <%u>", 148*7c478bd9Sstevel@tonic-gate (uint_t)major); 149*7c478bd9Sstevel@tonic-gate } 150*7c478bd9Sstevel@tonic-gate DECR_DEV_OPS_REF(ops); 151*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 152*7c478bd9Sstevel@tonic-gate } 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate struct dev_ops * 155*7c478bd9Sstevel@tonic-gate mod_hold_dev_by_devi(dev_info_t *devi) 156*7c478bd9Sstevel@tonic-gate { 157*7c478bd9Sstevel@tonic-gate major_t major; 158*7c478bd9Sstevel@tonic-gate char *name; 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate name = ddi_get_name(devi); 161*7c478bd9Sstevel@tonic-gate if ((major = mod_name_to_major(name)) == (major_t)-1) 162*7c478bd9Sstevel@tonic-gate return (NULL); 163*7c478bd9Sstevel@tonic-gate return (mod_hold_dev_by_major(major)); 164*7c478bd9Sstevel@tonic-gate } 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate void 167*7c478bd9Sstevel@tonic-gate mod_rele_dev_by_devi(dev_info_t *devi) 168*7c478bd9Sstevel@tonic-gate { 169*7c478bd9Sstevel@tonic-gate major_t major; 170*7c478bd9Sstevel@tonic-gate char *name; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate name = ddi_get_name(devi); 173*7c478bd9Sstevel@tonic-gate if ((major = mod_name_to_major(name)) == (major_t)-1) 174*7c478bd9Sstevel@tonic-gate return; 175*7c478bd9Sstevel@tonic-gate mod_rele_dev_by_major(major); 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate int 179*7c478bd9Sstevel@tonic-gate nomod_zero() 180*7c478bd9Sstevel@tonic-gate { 181*7c478bd9Sstevel@tonic-gate return (0); 182*7c478bd9Sstevel@tonic-gate } 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate int 185*7c478bd9Sstevel@tonic-gate nomod_minus_one() 186*7c478bd9Sstevel@tonic-gate { 187*7c478bd9Sstevel@tonic-gate return (-1); 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate int 191*7c478bd9Sstevel@tonic-gate nomod_einval() 192*7c478bd9Sstevel@tonic-gate { 193*7c478bd9Sstevel@tonic-gate return (EINVAL); 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate void 197*7c478bd9Sstevel@tonic-gate nomod_void() 198*7c478bd9Sstevel@tonic-gate { 199*7c478bd9Sstevel@tonic-gate /* nothing */ 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * Install all the stubs for a module. 204*7c478bd9Sstevel@tonic-gate * Return zero if there were no errors or an errno value. 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate int 207*7c478bd9Sstevel@tonic-gate install_stubs_by_name(struct modctl *modp, char *name) 208*7c478bd9Sstevel@tonic-gate { 209*7c478bd9Sstevel@tonic-gate char *p; 210*7c478bd9Sstevel@tonic-gate char *filenamep; 211*7c478bd9Sstevel@tonic-gate char namebuf[MODMAXNAMELEN + 12]; 212*7c478bd9Sstevel@tonic-gate struct mod_modinfo *mp; 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate p = name; 215*7c478bd9Sstevel@tonic-gate filenamep = name; 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate while (*p) 218*7c478bd9Sstevel@tonic-gate if (*p++ == '/') 219*7c478bd9Sstevel@tonic-gate filenamep = p; 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* 222*7c478bd9Sstevel@tonic-gate * Concatenate "name" with "_modname" then look up this symbol 223*7c478bd9Sstevel@tonic-gate * in the kernel. If not found, we're done. 224*7c478bd9Sstevel@tonic-gate * If found, then find the "mod" info structure and call init_stubs(). 225*7c478bd9Sstevel@tonic-gate */ 226*7c478bd9Sstevel@tonic-gate p = namebuf; 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate while (*filenamep && *filenamep != '.') 229*7c478bd9Sstevel@tonic-gate *p++ = *filenamep++; 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate (void) strcpy(p, "_modinfo"); 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate if ((mp = (struct mod_modinfo *)modgetsymvalue(namebuf, 1)) != 0) 234*7c478bd9Sstevel@tonic-gate return (init_stubs(modp, mp)); 235*7c478bd9Sstevel@tonic-gate else 236*7c478bd9Sstevel@tonic-gate return (0); 237*7c478bd9Sstevel@tonic-gate } 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate static int 240*7c478bd9Sstevel@tonic-gate init_stubs(struct modctl *modp, struct mod_modinfo *mp) 241*7c478bd9Sstevel@tonic-gate { 242*7c478bd9Sstevel@tonic-gate struct mod_stub_info *sp; 243*7c478bd9Sstevel@tonic-gate int i; 244*7c478bd9Sstevel@tonic-gate ulong_t offset; 245*7c478bd9Sstevel@tonic-gate uintptr_t funcadr; 246*7c478bd9Sstevel@tonic-gate char *funcname; 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate modp->mod_modinfo = mp; 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate /* 251*7c478bd9Sstevel@tonic-gate * Fill in all stubs for this module. We can't be lazy, since 252*7c478bd9Sstevel@tonic-gate * some calls could come in from interrupt level, and we 253*7c478bd9Sstevel@tonic-gate * can't modlookup then (symbols may be paged out). 254*7c478bd9Sstevel@tonic-gate */ 255*7c478bd9Sstevel@tonic-gate sp = mp->modm_stubs; 256*7c478bd9Sstevel@tonic-gate for (i = 0; sp->mods_func_adr; i++, sp++) { 257*7c478bd9Sstevel@tonic-gate funcname = modgetsymname(sp->mods_stub_adr, &offset); 258*7c478bd9Sstevel@tonic-gate if (funcname == NULL) { 259*7c478bd9Sstevel@tonic-gate printf("init_stubs: couldn't find symbol in module %s\n", 260*7c478bd9Sstevel@tonic-gate mp->modm_module_name); 261*7c478bd9Sstevel@tonic-gate return (EFAULT); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate funcadr = kobj_lookup(modp->mod_mp, funcname); 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate if (kobj_addrcheck(modp->mod_mp, (caddr_t)funcadr)) { 266*7c478bd9Sstevel@tonic-gate printf("%s:%s() not defined properly\n", 267*7c478bd9Sstevel@tonic-gate mp->modm_module_name, funcname); 268*7c478bd9Sstevel@tonic-gate return (EFAULT); 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate sp->mods_func_adr = funcadr; 271*7c478bd9Sstevel@tonic-gate } 272*7c478bd9Sstevel@tonic-gate mp->mp = modp; 273*7c478bd9Sstevel@tonic-gate return (0); 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate /* 277*7c478bd9Sstevel@tonic-gate * modp->mod_modinfo has to be checked in these functions before 278*7c478bd9Sstevel@tonic-gate * mod_stub_info is accessed because it's not guranteed that all 279*7c478bd9Sstevel@tonic-gate * modules define mod_stub_info structures. 280*7c478bd9Sstevel@tonic-gate */ 281*7c478bd9Sstevel@tonic-gate void 282*7c478bd9Sstevel@tonic-gate install_stubs(struct modctl *modp) 283*7c478bd9Sstevel@tonic-gate { 284*7c478bd9Sstevel@tonic-gate struct mod_stub_info *stub; 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate if (modp->mod_modinfo) { 287*7c478bd9Sstevel@tonic-gate membar_producer(); 288*7c478bd9Sstevel@tonic-gate for (stub = modp->mod_modinfo->modm_stubs; 289*7c478bd9Sstevel@tonic-gate stub->mods_func_adr; stub++) { 290*7c478bd9Sstevel@tonic-gate stub->mods_flag |= MODS_INSTALLED; 291*7c478bd9Sstevel@tonic-gate } 292*7c478bd9Sstevel@tonic-gate membar_producer(); 293*7c478bd9Sstevel@tonic-gate } 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate void 297*7c478bd9Sstevel@tonic-gate uninstall_stubs(struct modctl *modp) 298*7c478bd9Sstevel@tonic-gate { 299*7c478bd9Sstevel@tonic-gate struct mod_stub_info *stub; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate if (modp->mod_modinfo) { 302*7c478bd9Sstevel@tonic-gate membar_producer(); 303*7c478bd9Sstevel@tonic-gate for (stub = modp->mod_modinfo->modm_stubs; 304*7c478bd9Sstevel@tonic-gate stub->mods_func_adr; stub++) { 305*7c478bd9Sstevel@tonic-gate stub->mods_flag &= ~MODS_INSTALLED; 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate membar_producer(); 308*7c478bd9Sstevel@tonic-gate } 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate void 312*7c478bd9Sstevel@tonic-gate reset_stubs(struct modctl *modp) 313*7c478bd9Sstevel@tonic-gate { 314*7c478bd9Sstevel@tonic-gate struct mod_stub_info *stub; 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate if (modp->mod_modinfo) { 317*7c478bd9Sstevel@tonic-gate for (stub = modp->mod_modinfo->modm_stubs; 318*7c478bd9Sstevel@tonic-gate stub->mods_func_adr; stub++) { 319*7c478bd9Sstevel@tonic-gate if (stub->mods_flag & (MODS_WEAK | MODS_NOUNLOAD)) 320*7c478bd9Sstevel@tonic-gate stub->mods_func_adr = 321*7c478bd9Sstevel@tonic-gate (uintptr_t)stub->mods_errfcn; 322*7c478bd9Sstevel@tonic-gate else 323*7c478bd9Sstevel@tonic-gate stub->mods_func_adr = 324*7c478bd9Sstevel@tonic-gate (uintptr_t)mod_hold_stub; 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate modp->mod_modinfo->mp = NULL; 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate struct modctl * 331*7c478bd9Sstevel@tonic-gate mod_getctl(struct modlinkage *modlp) 332*7c478bd9Sstevel@tonic-gate { 333*7c478bd9Sstevel@tonic-gate struct modctl *modp; 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 336*7c478bd9Sstevel@tonic-gate modp = &modules; 337*7c478bd9Sstevel@tonic-gate do { 338*7c478bd9Sstevel@tonic-gate if (modp->mod_linkage == modlp) { 339*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 340*7c478bd9Sstevel@tonic-gate return (modp); 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules); 343*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 344*7c478bd9Sstevel@tonic-gate return (NULL); 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate /* 349*7c478bd9Sstevel@tonic-gate * Attach driver.conf info to devnames for a driver 350*7c478bd9Sstevel@tonic-gate */ 351*7c478bd9Sstevel@tonic-gate struct par_list * 352*7c478bd9Sstevel@tonic-gate impl_make_parlist(major_t major) 353*7c478bd9Sstevel@tonic-gate { 354*7c478bd9Sstevel@tonic-gate int err; 355*7c478bd9Sstevel@tonic-gate struct par_list *pl = NULL, *tmp; 356*7c478bd9Sstevel@tonic-gate ddi_prop_t *props = NULL; 357*7c478bd9Sstevel@tonic-gate char *confname, *drvname; 358*7c478bd9Sstevel@tonic-gate struct devnames *dnp; 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate dnp = &devnamesp[major]; 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&dnp->dn_lock)); 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate /* 365*7c478bd9Sstevel@tonic-gate * If .conf file already parsed or driver removed, just return. 366*7c478bd9Sstevel@tonic-gate * May return NULL. 367*7c478bd9Sstevel@tonic-gate */ 368*7c478bd9Sstevel@tonic-gate if (dnp->dn_flags & (DN_CONF_PARSED | DN_DRIVER_REMOVED)) 369*7c478bd9Sstevel@tonic-gate return (dnp->dn_pl); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate drvname = mod_major_to_name(major); 372*7c478bd9Sstevel@tonic-gate if (drvname == NULL) 373*7c478bd9Sstevel@tonic-gate return (NULL); 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate confname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 376*7c478bd9Sstevel@tonic-gate (void) snprintf(confname, MAXNAMELEN, "drv/%s.conf", drvname); 377*7c478bd9Sstevel@tonic-gate err = hwc_parse(confname, &pl, &props); 378*7c478bd9Sstevel@tonic-gate kmem_free(confname, MAXNAMELEN); 379*7c478bd9Sstevel@tonic-gate if (err) /* file doesn't exist */ 380*7c478bd9Sstevel@tonic-gate return (NULL); 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate /* 383*7c478bd9Sstevel@tonic-gate * If there are global properties, reference it from dnp. 384*7c478bd9Sstevel@tonic-gate */ 385*7c478bd9Sstevel@tonic-gate if (props) 386*7c478bd9Sstevel@tonic-gate dnp->dn_global_prop_ptr = i_ddi_prop_list_create(props); 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate /* 389*7c478bd9Sstevel@tonic-gate * Hash specs to be looked up by nexus drivers 390*7c478bd9Sstevel@tonic-gate */ 391*7c478bd9Sstevel@tonic-gate tmp = pl; 392*7c478bd9Sstevel@tonic-gate while (tmp) { 393*7c478bd9Sstevel@tonic-gate (void) hwc_hash(tmp->par_specs, major); 394*7c478bd9Sstevel@tonic-gate tmp = tmp->par_next; 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate if (!i_ddi_io_initialized()) { 398*7c478bd9Sstevel@tonic-gate if (i_ddi_prop_search(DDI_DEV_T_ANY, DDI_FORCEATTACH, 399*7c478bd9Sstevel@tonic-gate DDI_PROP_TYPE_INT, &props)) 400*7c478bd9Sstevel@tonic-gate dnp->dn_flags |= DN_FORCE_ATTACH; 401*7c478bd9Sstevel@tonic-gate } 402*7c478bd9Sstevel@tonic-gate dnp->dn_flags |= DN_CONF_PARSED; 403*7c478bd9Sstevel@tonic-gate dnp->dn_pl = pl; 404*7c478bd9Sstevel@tonic-gate return (pl); 405*7c478bd9Sstevel@tonic-gate } 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate /* 408*7c478bd9Sstevel@tonic-gate * Destroy driver.conf info in devnames array for a driver 409*7c478bd9Sstevel@tonic-gate */ 410*7c478bd9Sstevel@tonic-gate int 411*7c478bd9Sstevel@tonic-gate impl_free_parlist(major_t major) 412*7c478bd9Sstevel@tonic-gate { 413*7c478bd9Sstevel@tonic-gate struct par_list *pl; 414*7c478bd9Sstevel@tonic-gate struct devnames *dnp = &devnamesp[major]; 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate /* 417*7c478bd9Sstevel@tonic-gate * Unref driver global property list. Don't destroy it 418*7c478bd9Sstevel@tonic-gate * because some instances may still be referencing it. 419*7c478bd9Sstevel@tonic-gate * The property list will be freed when the last ref 420*7c478bd9Sstevel@tonic-gate * goes away. 421*7c478bd9Sstevel@tonic-gate */ 422*7c478bd9Sstevel@tonic-gate if (dnp->dn_global_prop_ptr) { 423*7c478bd9Sstevel@tonic-gate i_ddi_prop_list_rele(dnp->dn_global_prop_ptr, dnp); 424*7c478bd9Sstevel@tonic-gate dnp->dn_global_prop_ptr = NULL; 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate /* 428*7c478bd9Sstevel@tonic-gate * remove specs from hash table 429*7c478bd9Sstevel@tonic-gate */ 430*7c478bd9Sstevel@tonic-gate for (pl = dnp->dn_pl; pl; pl = pl->par_next) 431*7c478bd9Sstevel@tonic-gate hwc_unhash(pl->par_specs); 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate impl_delete_par_list(dnp->dn_pl); 434*7c478bd9Sstevel@tonic-gate dnp->dn_pl = NULL; 435*7c478bd9Sstevel@tonic-gate dnp->dn_flags &= ~DN_CONF_PARSED; 436*7c478bd9Sstevel@tonic-gate return (0); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate struct bind *mb_hashtab[MOD_BIND_HASHSIZE]; 440*7c478bd9Sstevel@tonic-gate struct bind *sb_hashtab[MOD_BIND_HASHSIZE]; 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate static int 443*7c478bd9Sstevel@tonic-gate nm_hash(char *name) 444*7c478bd9Sstevel@tonic-gate { 445*7c478bd9Sstevel@tonic-gate char c; 446*7c478bd9Sstevel@tonic-gate int hash = 0; 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate for (c = *name++; c; c = *name++) 449*7c478bd9Sstevel@tonic-gate hash ^= c; 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate return (hash & MOD_BIND_HASHMASK); 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate void 455*7c478bd9Sstevel@tonic-gate clear_binding_hash(struct bind **bhash) 456*7c478bd9Sstevel@tonic-gate { 457*7c478bd9Sstevel@tonic-gate int i; 458*7c478bd9Sstevel@tonic-gate struct bind *bp, *bp1; 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate for (i = 0; i < MOD_BIND_HASHSIZE; i++) { 461*7c478bd9Sstevel@tonic-gate bp = bhash[i]; 462*7c478bd9Sstevel@tonic-gate while (bp != NULL) { 463*7c478bd9Sstevel@tonic-gate kmem_free(bp->b_name, strlen(bp->b_name) + 1); 464*7c478bd9Sstevel@tonic-gate if (bp->b_bind_name) { 465*7c478bd9Sstevel@tonic-gate kmem_free(bp->b_bind_name, 466*7c478bd9Sstevel@tonic-gate strlen(bp->b_bind_name) + 1); 467*7c478bd9Sstevel@tonic-gate } 468*7c478bd9Sstevel@tonic-gate bp1 = bp; 469*7c478bd9Sstevel@tonic-gate bp = bp->b_next; 470*7c478bd9Sstevel@tonic-gate kmem_free(bp1, sizeof (struct bind)); 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate bhash[i] = NULL; 473*7c478bd9Sstevel@tonic-gate } 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate static struct bind * 477*7c478bd9Sstevel@tonic-gate find_mbind(char *name, struct bind **hashtab) 478*7c478bd9Sstevel@tonic-gate { 479*7c478bd9Sstevel@tonic-gate int hashndx; 480*7c478bd9Sstevel@tonic-gate struct bind *mb; 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate hashndx = nm_hash(name); 483*7c478bd9Sstevel@tonic-gate for (mb = hashtab[hashndx]; mb; mb = mb->b_next) { 484*7c478bd9Sstevel@tonic-gate if (strcmp(name, mb->b_name) == 0) 485*7c478bd9Sstevel@tonic-gate break; 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate return (mb); 489*7c478bd9Sstevel@tonic-gate } 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate /* 492*7c478bd9Sstevel@tonic-gate * Create an entry for the given (name, major, bind_name) tuple in the 493*7c478bd9Sstevel@tonic-gate * hash table supplied. Reject the attempt to do so if 'name' is already 494*7c478bd9Sstevel@tonic-gate * in the hash table. 495*7c478bd9Sstevel@tonic-gate * 496*7c478bd9Sstevel@tonic-gate * Does not provide synchronization, so use only during boot or with 497*7c478bd9Sstevel@tonic-gate * externally provided locking. 498*7c478bd9Sstevel@tonic-gate */ 499*7c478bd9Sstevel@tonic-gate int 500*7c478bd9Sstevel@tonic-gate make_mbind(char *name, int major, char *bind_name, struct bind **hashtab) 501*7c478bd9Sstevel@tonic-gate { 502*7c478bd9Sstevel@tonic-gate struct bind *bp; 503*7c478bd9Sstevel@tonic-gate int hashndx; 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate ASSERT(hashtab != NULL); 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate /* 508*7c478bd9Sstevel@tonic-gate * Fail if the key being added is already in the hash table 509*7c478bd9Sstevel@tonic-gate */ 510*7c478bd9Sstevel@tonic-gate if (find_mbind(name, hashtab) != NULL) 511*7c478bd9Sstevel@tonic-gate return (-1); 512*7c478bd9Sstevel@tonic-gate 513*7c478bd9Sstevel@tonic-gate bp = kmem_zalloc(sizeof (struct bind), KM_SLEEP); 514*7c478bd9Sstevel@tonic-gate bp->b_name = kmem_alloc(strlen(name) + 1, KM_SLEEP); 515*7c478bd9Sstevel@tonic-gate (void) strcpy(bp->b_name, name); 516*7c478bd9Sstevel@tonic-gate bp->b_num = major; 517*7c478bd9Sstevel@tonic-gate if (bind_name != NULL) { 518*7c478bd9Sstevel@tonic-gate bp->b_bind_name = kmem_alloc(strlen(bind_name) + 1, KM_SLEEP); 519*7c478bd9Sstevel@tonic-gate (void) strcpy(bp->b_bind_name, bind_name); 520*7c478bd9Sstevel@tonic-gate } 521*7c478bd9Sstevel@tonic-gate hashndx = nm_hash(name); 522*7c478bd9Sstevel@tonic-gate bp->b_next = hashtab[hashndx]; 523*7c478bd9Sstevel@tonic-gate hashtab[hashndx] = bp; 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate return (0); 526*7c478bd9Sstevel@tonic-gate } 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate /* 529*7c478bd9Sstevel@tonic-gate * Delete a binding from a binding-hash. 530*7c478bd9Sstevel@tonic-gate * 531*7c478bd9Sstevel@tonic-gate * Does not provide synchronization, so use only during boot or with 532*7c478bd9Sstevel@tonic-gate * externally provided locking. 533*7c478bd9Sstevel@tonic-gate */ 534*7c478bd9Sstevel@tonic-gate void 535*7c478bd9Sstevel@tonic-gate delete_mbind(char *name, struct bind **hashtab) 536*7c478bd9Sstevel@tonic-gate { 537*7c478bd9Sstevel@tonic-gate int hashndx; 538*7c478bd9Sstevel@tonic-gate struct bind *b, *bparent = NULL; 539*7c478bd9Sstevel@tonic-gate struct bind *t = NULL; /* target to delete */ 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate hashndx = nm_hash(name); 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate if (hashtab[hashndx] == NULL) 544*7c478bd9Sstevel@tonic-gate return; 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate b = hashtab[hashndx]; 547*7c478bd9Sstevel@tonic-gate if (strcmp(name, b->b_name) == 0) { /* special case first elem. */ 548*7c478bd9Sstevel@tonic-gate hashtab[hashndx] = b->b_next; 549*7c478bd9Sstevel@tonic-gate t = b; 550*7c478bd9Sstevel@tonic-gate } else { 551*7c478bd9Sstevel@tonic-gate for (b = hashtab[hashndx]; b; b = b->b_next) { 552*7c478bd9Sstevel@tonic-gate if (strcmp(name, b->b_name) == 0) { 553*7c478bd9Sstevel@tonic-gate ASSERT(bparent); 554*7c478bd9Sstevel@tonic-gate t = b; 555*7c478bd9Sstevel@tonic-gate bparent->b_next = b->b_next; 556*7c478bd9Sstevel@tonic-gate break; 557*7c478bd9Sstevel@tonic-gate } 558*7c478bd9Sstevel@tonic-gate bparent = b; 559*7c478bd9Sstevel@tonic-gate } 560*7c478bd9Sstevel@tonic-gate } 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate if (t != NULL) { /* delete the target */ 563*7c478bd9Sstevel@tonic-gate ASSERT(t->b_name); 564*7c478bd9Sstevel@tonic-gate kmem_free(t->b_name, strlen(t->b_name) + 1); 565*7c478bd9Sstevel@tonic-gate if (t->b_bind_name) 566*7c478bd9Sstevel@tonic-gate kmem_free(t->b_bind_name, strlen(t->b_bind_name) + 1); 567*7c478bd9Sstevel@tonic-gate kmem_free(t, sizeof (struct bind)); 568*7c478bd9Sstevel@tonic-gate } 569*7c478bd9Sstevel@tonic-gate } 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate major_t 573*7c478bd9Sstevel@tonic-gate mod_name_to_major(char *name) 574*7c478bd9Sstevel@tonic-gate { 575*7c478bd9Sstevel@tonic-gate struct bind *mbind; 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate if ((mbind = find_mbind(name, mb_hashtab)) != NULL) 578*7c478bd9Sstevel@tonic-gate return ((major_t)mbind->b_num); 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate return ((major_t)-1); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate char * 584*7c478bd9Sstevel@tonic-gate mod_major_to_name(major_t major) 585*7c478bd9Sstevel@tonic-gate { 586*7c478bd9Sstevel@tonic-gate if (major >= devcnt) 587*7c478bd9Sstevel@tonic-gate return (NULL); 588*7c478bd9Sstevel@tonic-gate return ((&devnamesp[major])->dn_name); 589*7c478bd9Sstevel@tonic-gate } 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate /* 592*7c478bd9Sstevel@tonic-gate * Set up the devnames array. Error check for duplicate entries. 593*7c478bd9Sstevel@tonic-gate */ 594*7c478bd9Sstevel@tonic-gate void 595*7c478bd9Sstevel@tonic-gate init_devnamesp(int size) 596*7c478bd9Sstevel@tonic-gate { 597*7c478bd9Sstevel@tonic-gate int hshndx; 598*7c478bd9Sstevel@tonic-gate struct bind *bp; 599*7c478bd9Sstevel@tonic-gate static char dupwarn[] = 600*7c478bd9Sstevel@tonic-gate "!Device entry \"%s %d\" conflicts with previous entry \"%s %d\" " 601*7c478bd9Sstevel@tonic-gate "in /etc/name_to_major."; 602*7c478bd9Sstevel@tonic-gate static char badmaj[] = "The major number %u is invalid."; 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate ASSERT(size <= L_MAXMAJ32 && size > 0); 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate /* 607*7c478bd9Sstevel@tonic-gate * Allocate the devnames array. All mutexes and cv's will be 608*7c478bd9Sstevel@tonic-gate * automagically initialized. 609*7c478bd9Sstevel@tonic-gate */ 610*7c478bd9Sstevel@tonic-gate devnamesp = kobj_zalloc(size * sizeof (struct devnames), KM_SLEEP); 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate /* 613*7c478bd9Sstevel@tonic-gate * Stick the contents of mb_hashtab into the devnames array. Warn if 614*7c478bd9Sstevel@tonic-gate * two hash entries correspond to the same major number, or if a 615*7c478bd9Sstevel@tonic-gate * major number is out of range. 616*7c478bd9Sstevel@tonic-gate */ 617*7c478bd9Sstevel@tonic-gate for (hshndx = 0; hshndx < MOD_BIND_HASHSIZE; hshndx++) { 618*7c478bd9Sstevel@tonic-gate for (bp = mb_hashtab[hshndx]; bp; bp = bp->b_next) { 619*7c478bd9Sstevel@tonic-gate if (make_devname(bp->b_name, (major_t)bp->b_num) != 0) { 620*7c478bd9Sstevel@tonic-gate /* 621*7c478bd9Sstevel@tonic-gate * If there is not an entry at b_num already, 622*7c478bd9Sstevel@tonic-gate * then this must be a bad major number. 623*7c478bd9Sstevel@tonic-gate */ 624*7c478bd9Sstevel@tonic-gate char *nm = mod_major_to_name(bp->b_num); 625*7c478bd9Sstevel@tonic-gate if (nm == NULL) { 626*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, badmaj, 627*7c478bd9Sstevel@tonic-gate (uint_t)bp->b_num); 628*7c478bd9Sstevel@tonic-gate } else { 629*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, dupwarn, bp->b_name, 630*7c478bd9Sstevel@tonic-gate bp->b_num, nm, bp->b_num); 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate /* Initialize hash table for hwc_spec's */ 637*7c478bd9Sstevel@tonic-gate hwc_hash_init(); 638*7c478bd9Sstevel@tonic-gate } 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate int 641*7c478bd9Sstevel@tonic-gate make_devname(char *name, major_t major) 642*7c478bd9Sstevel@tonic-gate { 643*7c478bd9Sstevel@tonic-gate struct devnames *dnp; 644*7c478bd9Sstevel@tonic-gate char *copy; 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate /* 647*7c478bd9Sstevel@tonic-gate * Until on-disk support for major nums > 14 bits arrives, fail 648*7c478bd9Sstevel@tonic-gate * any major numbers that are too big. 649*7c478bd9Sstevel@tonic-gate */ 650*7c478bd9Sstevel@tonic-gate if (major > L_MAXMAJ32) 651*7c478bd9Sstevel@tonic-gate return (EINVAL); 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate dnp = &devnamesp[major]; 654*7c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 655*7c478bd9Sstevel@tonic-gate if (dnp->dn_name) { 656*7c478bd9Sstevel@tonic-gate if (strcmp(dnp->dn_name, name) != 0) { 657*7c478bd9Sstevel@tonic-gate /* Another driver already here */ 658*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 659*7c478bd9Sstevel@tonic-gate return (EINVAL); 660*7c478bd9Sstevel@tonic-gate } 661*7c478bd9Sstevel@tonic-gate /* Adding back a removed driver */ 662*7c478bd9Sstevel@tonic-gate dnp->dn_flags &= ~DN_DRIVER_REMOVED; 663*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 664*7c478bd9Sstevel@tonic-gate return (0); 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate /* 668*7c478bd9Sstevel@tonic-gate * Check if flag is taken by getudev() 669*7c478bd9Sstevel@tonic-gate */ 670*7c478bd9Sstevel@tonic-gate if (dnp->dn_flags & DN_TAKEN_GETUDEV) { 671*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 672*7c478bd9Sstevel@tonic-gate return (EINVAL); 673*7c478bd9Sstevel@tonic-gate } 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate copy = kmem_alloc(strlen(name) + 1, KM_SLEEP); 676*7c478bd9Sstevel@tonic-gate (void) strcpy(copy, name); 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate /* Make sure string is copied before setting dn_name */ 679*7c478bd9Sstevel@tonic-gate membar_producer(); 680*7c478bd9Sstevel@tonic-gate dnp->dn_name = copy; 681*7c478bd9Sstevel@tonic-gate dnp->dn_flags = 0; 682*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 683*7c478bd9Sstevel@tonic-gate return (0); 684*7c478bd9Sstevel@tonic-gate } 685*7c478bd9Sstevel@tonic-gate 686*7c478bd9Sstevel@tonic-gate /* 687*7c478bd9Sstevel@tonic-gate * Set up the syscallnames array. 688*7c478bd9Sstevel@tonic-gate */ 689*7c478bd9Sstevel@tonic-gate void 690*7c478bd9Sstevel@tonic-gate init_syscallnames(int size) 691*7c478bd9Sstevel@tonic-gate { 692*7c478bd9Sstevel@tonic-gate int hshndx; 693*7c478bd9Sstevel@tonic-gate struct bind *bp; 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate syscallnames = kobj_zalloc(size * sizeof (char *), KM_SLEEP); 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate for (hshndx = 0; hshndx < MOD_BIND_HASHSIZE; hshndx++) { 698*7c478bd9Sstevel@tonic-gate for (bp = sb_hashtab[hshndx]; bp; bp = bp->b_next) { 699*7c478bd9Sstevel@tonic-gate make_syscallname(bp->b_name, bp->b_num); 700*7c478bd9Sstevel@tonic-gate } 701*7c478bd9Sstevel@tonic-gate } 702*7c478bd9Sstevel@tonic-gate } 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate static void 705*7c478bd9Sstevel@tonic-gate make_syscallname(char *name, int sysno) 706*7c478bd9Sstevel@tonic-gate { 707*7c478bd9Sstevel@tonic-gate char **cp = &syscallnames[sysno]; 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate if (*cp != NULL) { 710*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!Couldn't add system call \"%s %d\". " 711*7c478bd9Sstevel@tonic-gate "It conflicts with \"%s %d\" in /etc/name_to_sysnum.", 712*7c478bd9Sstevel@tonic-gate name, sysno, *cp, sysno); 713*7c478bd9Sstevel@tonic-gate return; 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate *cp = kmem_alloc(strlen(name) + 1, KM_SLEEP); 716*7c478bd9Sstevel@tonic-gate (void) strcpy(*cp, name); 717*7c478bd9Sstevel@tonic-gate } 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate /* 720*7c478bd9Sstevel@tonic-gate * Given a system call name, get its number. 721*7c478bd9Sstevel@tonic-gate */ 722*7c478bd9Sstevel@tonic-gate int 723*7c478bd9Sstevel@tonic-gate mod_getsysnum(char *name) 724*7c478bd9Sstevel@tonic-gate { 725*7c478bd9Sstevel@tonic-gate struct bind *mbind; 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate if ((mbind = find_mbind(name, sb_hashtab)) != NULL) 728*7c478bd9Sstevel@tonic-gate return (mbind->b_num); 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate return (-1); 731*7c478bd9Sstevel@tonic-gate } 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate /* 734*7c478bd9Sstevel@tonic-gate * Given a system call number, get the system call name. 735*7c478bd9Sstevel@tonic-gate */ 736*7c478bd9Sstevel@tonic-gate char * 737*7c478bd9Sstevel@tonic-gate mod_getsysname(int sysnum) 738*7c478bd9Sstevel@tonic-gate { 739*7c478bd9Sstevel@tonic-gate return (syscallnames[sysnum]); 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate /* 743*7c478bd9Sstevel@tonic-gate * Find the name of the module containing the specified pc. 744*7c478bd9Sstevel@tonic-gate * Returns the name on success, "<unknown>" on failure. 745*7c478bd9Sstevel@tonic-gate * No mod_lock locking is required because things are never deleted from 746*7c478bd9Sstevel@tonic-gate * the &modules list. 747*7c478bd9Sstevel@tonic-gate */ 748*7c478bd9Sstevel@tonic-gate char * 749*7c478bd9Sstevel@tonic-gate mod_containing_pc(caddr_t pc) 750*7c478bd9Sstevel@tonic-gate { 751*7c478bd9Sstevel@tonic-gate struct modctl *mcp = &modules; 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate do { 754*7c478bd9Sstevel@tonic-gate if (mcp->mod_mp != NULL && 755*7c478bd9Sstevel@tonic-gate (size_t)pc - (size_t)mcp->mod_text < mcp->mod_text_size) 756*7c478bd9Sstevel@tonic-gate return (mcp->mod_modname); 757*7c478bd9Sstevel@tonic-gate } while ((mcp = mcp->mod_next) != &modules); 758*7c478bd9Sstevel@tonic-gate return ("<unknown>"); 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate /* 762*7c478bd9Sstevel@tonic-gate * Hash tables for hwc_spec 763*7c478bd9Sstevel@tonic-gate * 764*7c478bd9Sstevel@tonic-gate * The purpose of these hash tables are to allow the framework to discover 765*7c478bd9Sstevel@tonic-gate * all possible .conf children for a given nexus. There are two hash tables. 766*7c478bd9Sstevel@tonic-gate * One is hashed based on parent name, the on the class name. Each 767*7c478bd9Sstevel@tonic-gate * driver.conf file translates to a list of hwc_spec's. Adding and 768*7c478bd9Sstevel@tonic-gate * removing the entire list is an atomic operation, protected by 769*7c478bd9Sstevel@tonic-gate * the hwc_hash_lock. 770*7c478bd9Sstevel@tonic-gate * 771*7c478bd9Sstevel@tonic-gate * What we get from all the hashing is the function hwc_get_child_spec(). 772*7c478bd9Sstevel@tonic-gate */ 773*7c478bd9Sstevel@tonic-gate #define HWC_SPEC_HASHSIZE (1 << 6) /* 64 */ 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate static mod_hash_t *hwc_par_hash; /* hash by parent name */ 776*7c478bd9Sstevel@tonic-gate static mod_hash_t *hwc_class_hash; /* hash by class name */ 777*7c478bd9Sstevel@tonic-gate static kmutex_t hwc_hash_lock; /* lock protecting hwc hashes */ 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate /* 780*7c478bd9Sstevel@tonic-gate * Initialize hash tables for parent and class specs 781*7c478bd9Sstevel@tonic-gate */ 782*7c478bd9Sstevel@tonic-gate static void 783*7c478bd9Sstevel@tonic-gate hwc_hash_init() 784*7c478bd9Sstevel@tonic-gate { 785*7c478bd9Sstevel@tonic-gate hwc_par_hash = mod_hash_create_strhash("hwc parent spec hash", 786*7c478bd9Sstevel@tonic-gate HWC_SPEC_HASHSIZE, mod_hash_null_valdtor); 787*7c478bd9Sstevel@tonic-gate hwc_class_hash = mod_hash_create_strhash("hwc class spec hash", 788*7c478bd9Sstevel@tonic-gate HWC_SPEC_HASHSIZE, mod_hash_null_valdtor); 789*7c478bd9Sstevel@tonic-gate } 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate /* 792*7c478bd9Sstevel@tonic-gate * Insert a spec into hash table. hwc_hash_lock must be held 793*7c478bd9Sstevel@tonic-gate */ 794*7c478bd9Sstevel@tonic-gate static void 795*7c478bd9Sstevel@tonic-gate hwc_hash_insert(struct hwc_spec *spec, char *name, mod_hash_t *hash) 796*7c478bd9Sstevel@tonic-gate { 797*7c478bd9Sstevel@tonic-gate mod_hash_key_t key; 798*7c478bd9Sstevel@tonic-gate struct hwc_spec *entry = NULL; 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate ASSERT(name != NULL); 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate if (mod_hash_find(hash, (mod_hash_key_t)name, 803*7c478bd9Sstevel@tonic-gate (mod_hash_val_t)&entry) != 0) { 804*7c478bd9Sstevel@tonic-gate /* Name doesn't exist, insert a new key */ 805*7c478bd9Sstevel@tonic-gate key = kmem_alloc(strlen(name) + 1, KM_SLEEP); 806*7c478bd9Sstevel@tonic-gate (void) strcpy((char *)key, name); 807*7c478bd9Sstevel@tonic-gate if (mod_hash_insert(hash, key, (mod_hash_val_t)spec) != 0) { 808*7c478bd9Sstevel@tonic-gate kmem_free(key, strlen(name) + 1); 809*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "hwc hash state inconsistent"); 810*7c478bd9Sstevel@tonic-gate } 811*7c478bd9Sstevel@tonic-gate return; 812*7c478bd9Sstevel@tonic-gate } 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate /* 815*7c478bd9Sstevel@tonic-gate * Name is already present, append spec to the list. 816*7c478bd9Sstevel@tonic-gate * This is the case when driver.conf specifies multiple 817*7c478bd9Sstevel@tonic-gate * nodes under a single parent or class. 818*7c478bd9Sstevel@tonic-gate */ 819*7c478bd9Sstevel@tonic-gate while (entry->hwc_hash_next) 820*7c478bd9Sstevel@tonic-gate entry = entry->hwc_hash_next; 821*7c478bd9Sstevel@tonic-gate entry->hwc_hash_next = spec; 822*7c478bd9Sstevel@tonic-gate } 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate /* 825*7c478bd9Sstevel@tonic-gate * Remove a spec entry from spec hash table, the spec itself is 826*7c478bd9Sstevel@tonic-gate * destroyed external to this function. 827*7c478bd9Sstevel@tonic-gate */ 828*7c478bd9Sstevel@tonic-gate static void 829*7c478bd9Sstevel@tonic-gate hwc_hash_remove(struct hwc_spec *spec, char *name, mod_hash_t *hash) 830*7c478bd9Sstevel@tonic-gate { 831*7c478bd9Sstevel@tonic-gate char *key; 832*7c478bd9Sstevel@tonic-gate struct hwc_spec *entry; 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate ASSERT(name != NULL); 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate if (mod_hash_find(hash, (mod_hash_key_t)name, 837*7c478bd9Sstevel@tonic-gate (mod_hash_val_t)&entry) != 0) { 838*7c478bd9Sstevel@tonic-gate return; /* name not found in hash */ 839*7c478bd9Sstevel@tonic-gate } 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate /* 842*7c478bd9Sstevel@tonic-gate * If the head is the spec to be removed, either destroy the 843*7c478bd9Sstevel@tonic-gate * entry or replace it with the remaining list. 844*7c478bd9Sstevel@tonic-gate */ 845*7c478bd9Sstevel@tonic-gate if (entry == spec) { 846*7c478bd9Sstevel@tonic-gate if (spec->hwc_hash_next == NULL) { 847*7c478bd9Sstevel@tonic-gate (void) mod_hash_destroy(hash, (mod_hash_key_t)name); 848*7c478bd9Sstevel@tonic-gate return; 849*7c478bd9Sstevel@tonic-gate } 850*7c478bd9Sstevel@tonic-gate key = kmem_alloc(strlen(name) + 1, KM_SLEEP); 851*7c478bd9Sstevel@tonic-gate (void) strcpy(key, name); 852*7c478bd9Sstevel@tonic-gate (void) mod_hash_replace(hash, (mod_hash_key_t)key, 853*7c478bd9Sstevel@tonic-gate (mod_hash_val_t)spec->hwc_hash_next); 854*7c478bd9Sstevel@tonic-gate spec->hwc_hash_next = NULL; 855*7c478bd9Sstevel@tonic-gate return; 856*7c478bd9Sstevel@tonic-gate } 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate /* 859*7c478bd9Sstevel@tonic-gate * If the head is not the one, look for the spec in the 860*7c478bd9Sstevel@tonic-gate * hwc_hash_next linkage. 861*7c478bd9Sstevel@tonic-gate */ 862*7c478bd9Sstevel@tonic-gate while (entry->hwc_hash_next && (entry->hwc_hash_next != spec)) 863*7c478bd9Sstevel@tonic-gate entry = entry->hwc_hash_next; 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate if (entry->hwc_hash_next) { 866*7c478bd9Sstevel@tonic-gate entry->hwc_hash_next = spec->hwc_hash_next; 867*7c478bd9Sstevel@tonic-gate spec->hwc_hash_next = NULL; 868*7c478bd9Sstevel@tonic-gate } 869*7c478bd9Sstevel@tonic-gate } 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate /* 872*7c478bd9Sstevel@tonic-gate * Hash a list of specs based on either parent name or class name 873*7c478bd9Sstevel@tonic-gate */ 874*7c478bd9Sstevel@tonic-gate static void 875*7c478bd9Sstevel@tonic-gate hwc_hash(struct hwc_spec *spec_list, major_t major) 876*7c478bd9Sstevel@tonic-gate { 877*7c478bd9Sstevel@tonic-gate struct hwc_spec *spec = spec_list; 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate mutex_enter(&hwc_hash_lock); 880*7c478bd9Sstevel@tonic-gate while (spec) { 881*7c478bd9Sstevel@tonic-gate /* Put driver major here so parent can find it */ 882*7c478bd9Sstevel@tonic-gate spec->hwc_major = major; 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate if (spec->hwc_parent_name != NULL) { 885*7c478bd9Sstevel@tonic-gate hwc_hash_insert(spec, spec->hwc_parent_name, 886*7c478bd9Sstevel@tonic-gate hwc_par_hash); 887*7c478bd9Sstevel@tonic-gate } else if (spec->hwc_class_name != NULL) { 888*7c478bd9Sstevel@tonic-gate hwc_hash_insert(spec, spec->hwc_class_name, 889*7c478bd9Sstevel@tonic-gate hwc_class_hash); 890*7c478bd9Sstevel@tonic-gate } else { 891*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 892*7c478bd9Sstevel@tonic-gate "hwc_hash: No class or parent specified"); 893*7c478bd9Sstevel@tonic-gate } 894*7c478bd9Sstevel@tonic-gate spec = spec->hwc_next; 895*7c478bd9Sstevel@tonic-gate } 896*7c478bd9Sstevel@tonic-gate mutex_exit(&hwc_hash_lock); 897*7c478bd9Sstevel@tonic-gate } 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate /* 900*7c478bd9Sstevel@tonic-gate * Remove a list of specs from hash tables. Don't destroy the specs yet. 901*7c478bd9Sstevel@tonic-gate */ 902*7c478bd9Sstevel@tonic-gate static void 903*7c478bd9Sstevel@tonic-gate hwc_unhash(struct hwc_spec *spec_list) 904*7c478bd9Sstevel@tonic-gate { 905*7c478bd9Sstevel@tonic-gate struct hwc_spec *spec = spec_list; 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate mutex_enter(&hwc_hash_lock); 908*7c478bd9Sstevel@tonic-gate while (spec) { 909*7c478bd9Sstevel@tonic-gate if (spec->hwc_parent_name != NULL) { 910*7c478bd9Sstevel@tonic-gate hwc_hash_remove(spec, spec->hwc_parent_name, 911*7c478bd9Sstevel@tonic-gate hwc_par_hash); 912*7c478bd9Sstevel@tonic-gate } else if (spec->hwc_class_name != NULL) { 913*7c478bd9Sstevel@tonic-gate hwc_hash_remove(spec, spec->hwc_class_name, 914*7c478bd9Sstevel@tonic-gate hwc_class_hash); 915*7c478bd9Sstevel@tonic-gate } else { 916*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 917*7c478bd9Sstevel@tonic-gate "hwc_unhash: No class or parent specified"); 918*7c478bd9Sstevel@tonic-gate } 919*7c478bd9Sstevel@tonic-gate spec = spec->hwc_next; 920*7c478bd9Sstevel@tonic-gate } 921*7c478bd9Sstevel@tonic-gate mutex_exit(&hwc_hash_lock); 922*7c478bd9Sstevel@tonic-gate } 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate /* 925*7c478bd9Sstevel@tonic-gate * Make a copy of specs in a hash entry and add to the end of listp. 926*7c478bd9Sstevel@tonic-gate * Called by nexus to locate a list of child specs. 927*7c478bd9Sstevel@tonic-gate * 928*7c478bd9Sstevel@tonic-gate * entry is a list of hwc_spec chained together with hwc_hash_next. 929*7c478bd9Sstevel@tonic-gate * listp points to list chained together with hwc_next. 930*7c478bd9Sstevel@tonic-gate */ 931*7c478bd9Sstevel@tonic-gate static void 932*7c478bd9Sstevel@tonic-gate hwc_spec_add(struct hwc_spec **listp, struct hwc_spec *entry, 933*7c478bd9Sstevel@tonic-gate major_t match_major) 934*7c478bd9Sstevel@tonic-gate { 935*7c478bd9Sstevel@tonic-gate /* Find the tail of the list */ 936*7c478bd9Sstevel@tonic-gate while (*listp) 937*7c478bd9Sstevel@tonic-gate listp = &(*listp)->hwc_next; 938*7c478bd9Sstevel@tonic-gate 939*7c478bd9Sstevel@tonic-gate while (entry) { 940*7c478bd9Sstevel@tonic-gate struct hwc_spec *spec; 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate if ((match_major != (major_t)-1) && 943*7c478bd9Sstevel@tonic-gate (match_major != entry->hwc_major)) { 944*7c478bd9Sstevel@tonic-gate entry = entry->hwc_hash_next; 945*7c478bd9Sstevel@tonic-gate continue; 946*7c478bd9Sstevel@tonic-gate } 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate /* 949*7c478bd9Sstevel@tonic-gate * Allocate spec and copy the content of entry. 950*7c478bd9Sstevel@tonic-gate * No need to copy class/parent name since caller 951*7c478bd9Sstevel@tonic-gate * already knows the parent dip. 952*7c478bd9Sstevel@tonic-gate */ 953*7c478bd9Sstevel@tonic-gate spec = kmem_zalloc(sizeof (*spec), KM_SLEEP); 954*7c478bd9Sstevel@tonic-gate spec->hwc_devi_name = i_ddi_strdup( 955*7c478bd9Sstevel@tonic-gate entry->hwc_devi_name, KM_SLEEP); 956*7c478bd9Sstevel@tonic-gate spec->hwc_major = entry->hwc_major; 957*7c478bd9Sstevel@tonic-gate spec->hwc_devi_sys_prop_ptr = i_ddi_prop_list_dup( 958*7c478bd9Sstevel@tonic-gate entry->hwc_devi_sys_prop_ptr, KM_SLEEP); 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate *listp = spec; 961*7c478bd9Sstevel@tonic-gate listp = &spec->hwc_next; 962*7c478bd9Sstevel@tonic-gate entry = entry->hwc_hash_next; 963*7c478bd9Sstevel@tonic-gate } 964*7c478bd9Sstevel@tonic-gate } 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate /* 967*7c478bd9Sstevel@tonic-gate * Given a dip, find the list of child .conf specs from most specific 968*7c478bd9Sstevel@tonic-gate * (parent pathname) to least specific (class name). 969*7c478bd9Sstevel@tonic-gate * 970*7c478bd9Sstevel@tonic-gate * This function allows top-down loading to be implemented without 971*7c478bd9Sstevel@tonic-gate * changing the format of driver.conf file. 972*7c478bd9Sstevel@tonic-gate */ 973*7c478bd9Sstevel@tonic-gate struct hwc_spec * 974*7c478bd9Sstevel@tonic-gate hwc_get_child_spec(dev_info_t *dip, major_t match_major) 975*7c478bd9Sstevel@tonic-gate { 976*7c478bd9Sstevel@tonic-gate extern char *i_ddi_parname(dev_info_t *, char *); 977*7c478bd9Sstevel@tonic-gate extern int i_ddi_get_exported_classes(dev_info_t *, char ***); 978*7c478bd9Sstevel@tonic-gate extern void i_ddi_free_exported_classes(char **, int); 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate int i, nclass; 981*7c478bd9Sstevel@tonic-gate char **classes; 982*7c478bd9Sstevel@tonic-gate struct hwc_spec *list = NULL; 983*7c478bd9Sstevel@tonic-gate mod_hash_val_t val; 984*7c478bd9Sstevel@tonic-gate char *parname, *parname_buf; 985*7c478bd9Sstevel@tonic-gate char *deviname, *deviname_buf; 986*7c478bd9Sstevel@tonic-gate char *pathname, *pathname_buf; 987*7c478bd9Sstevel@tonic-gate char *bindname; 988*7c478bd9Sstevel@tonic-gate char *drvname; 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate pathname_buf = kmem_alloc(3 * MAXPATHLEN, KM_SLEEP); 991*7c478bd9Sstevel@tonic-gate deviname_buf = pathname_buf + MAXPATHLEN; 992*7c478bd9Sstevel@tonic-gate parname_buf = pathname_buf + (2 * MAXPATHLEN); 993*7c478bd9Sstevel@tonic-gate 994*7c478bd9Sstevel@tonic-gate mutex_enter(&hwc_hash_lock); 995*7c478bd9Sstevel@tonic-gate 996*7c478bd9Sstevel@tonic-gate /* 997*7c478bd9Sstevel@tonic-gate * Lookup based on full path. 998*7c478bd9Sstevel@tonic-gate * In the case of root node, ddi_pathname would return 999*7c478bd9Sstevel@tonic-gate * null string so just skip calling it. 1000*7c478bd9Sstevel@tonic-gate * As the pathname always begins with /, no simpler 1001*7c478bd9Sstevel@tonic-gate * name can duplicate it. 1002*7c478bd9Sstevel@tonic-gate */ 1003*7c478bd9Sstevel@tonic-gate pathname = (dip == ddi_root_node()) ? "/" : 1004*7c478bd9Sstevel@tonic-gate ddi_pathname(dip, pathname_buf); 1005*7c478bd9Sstevel@tonic-gate ASSERT(pathname != NULL); 1006*7c478bd9Sstevel@tonic-gate ASSERT(*pathname == '/'); 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate if (mod_hash_find(hwc_par_hash, (mod_hash_key_t)pathname, &val) == 0) { 1009*7c478bd9Sstevel@tonic-gate hwc_spec_add(&list, (struct hwc_spec *)val, match_major); 1010*7c478bd9Sstevel@tonic-gate } 1011*7c478bd9Sstevel@tonic-gate 1012*7c478bd9Sstevel@tonic-gate /* 1013*7c478bd9Sstevel@tonic-gate * Lookup nodename@address. 1014*7c478bd9Sstevel@tonic-gate * Note deviname cannot match pathname. 1015*7c478bd9Sstevel@tonic-gate */ 1016*7c478bd9Sstevel@tonic-gate deviname = ddi_deviname(dip, deviname_buf); 1017*7c478bd9Sstevel@tonic-gate if (*deviname != '\0') { 1018*7c478bd9Sstevel@tonic-gate /* 1019*7c478bd9Sstevel@tonic-gate * Skip leading / returned by ddi_deviname. 1020*7c478bd9Sstevel@tonic-gate */ 1021*7c478bd9Sstevel@tonic-gate ASSERT(*deviname == '/'); 1022*7c478bd9Sstevel@tonic-gate deviname++; 1023*7c478bd9Sstevel@tonic-gate if ((*deviname != '\0') && 1024*7c478bd9Sstevel@tonic-gate (mod_hash_find(hwc_par_hash, 1025*7c478bd9Sstevel@tonic-gate (mod_hash_key_t)deviname, &val) == 0)) 1026*7c478bd9Sstevel@tonic-gate hwc_spec_add(&list, 1027*7c478bd9Sstevel@tonic-gate (struct hwc_spec *)val, match_major); 1028*7c478bd9Sstevel@tonic-gate } 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate /* 1031*7c478bd9Sstevel@tonic-gate * Lookup bindingname@address. 1032*7c478bd9Sstevel@tonic-gate * Take care not to perform duplicate lookups. 1033*7c478bd9Sstevel@tonic-gate */ 1034*7c478bd9Sstevel@tonic-gate parname = i_ddi_parname(dip, parname_buf); 1035*7c478bd9Sstevel@tonic-gate if (*parname != '\0') { 1036*7c478bd9Sstevel@tonic-gate ASSERT(*parname != '/'); 1037*7c478bd9Sstevel@tonic-gate if ((strcmp(parname, deviname) != 0) && 1038*7c478bd9Sstevel@tonic-gate (mod_hash_find(hwc_par_hash, 1039*7c478bd9Sstevel@tonic-gate (mod_hash_key_t)parname, &val) == 0)) { 1040*7c478bd9Sstevel@tonic-gate hwc_spec_add(&list, 1041*7c478bd9Sstevel@tonic-gate (struct hwc_spec *)val, match_major); 1042*7c478bd9Sstevel@tonic-gate } 1043*7c478bd9Sstevel@tonic-gate } 1044*7c478bd9Sstevel@tonic-gate 1045*7c478bd9Sstevel@tonic-gate /* 1046*7c478bd9Sstevel@tonic-gate * Lookup driver binding name 1047*7c478bd9Sstevel@tonic-gate */ 1048*7c478bd9Sstevel@tonic-gate bindname = ddi_binding_name(dip); 1049*7c478bd9Sstevel@tonic-gate ASSERT(*bindname != '/'); 1050*7c478bd9Sstevel@tonic-gate if ((strcmp(bindname, parname) != 0) && 1051*7c478bd9Sstevel@tonic-gate (strcmp(bindname, deviname) != 0) && 1052*7c478bd9Sstevel@tonic-gate (mod_hash_find(hwc_par_hash, (mod_hash_key_t)bindname, &val) == 0)) 1053*7c478bd9Sstevel@tonic-gate hwc_spec_add(&list, (struct hwc_spec *)val, match_major); 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate /* 1056*7c478bd9Sstevel@tonic-gate * Lookup driver name 1057*7c478bd9Sstevel@tonic-gate */ 1058*7c478bd9Sstevel@tonic-gate drvname = (char *)ddi_driver_name(dip); 1059*7c478bd9Sstevel@tonic-gate ASSERT(*drvname != '/'); 1060*7c478bd9Sstevel@tonic-gate if ((strcmp(drvname, bindname) != 0) && 1061*7c478bd9Sstevel@tonic-gate (strcmp(drvname, parname) != 0) && 1062*7c478bd9Sstevel@tonic-gate (strcmp(drvname, deviname) != 0) && 1063*7c478bd9Sstevel@tonic-gate (mod_hash_find(hwc_par_hash, (mod_hash_key_t)drvname, &val) == 0)) 1064*7c478bd9Sstevel@tonic-gate hwc_spec_add(&list, (struct hwc_spec *)val, match_major); 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate kmem_free(pathname_buf, 3 * MAXPATHLEN); 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate /* 1069*7c478bd9Sstevel@tonic-gate * Lookup classes exported by this node and lookup the 1070*7c478bd9Sstevel@tonic-gate * class hash table for all .conf specs 1071*7c478bd9Sstevel@tonic-gate */ 1072*7c478bd9Sstevel@tonic-gate nclass = i_ddi_get_exported_classes(dip, &classes); 1073*7c478bd9Sstevel@tonic-gate for (i = 0; i < nclass; i++) { 1074*7c478bd9Sstevel@tonic-gate if (mod_hash_find(hwc_class_hash, (mod_hash_key_t)classes[i], 1075*7c478bd9Sstevel@tonic-gate &val) == 0) 1076*7c478bd9Sstevel@tonic-gate hwc_spec_add(&list, (struct hwc_spec *)val, 1077*7c478bd9Sstevel@tonic-gate match_major); 1078*7c478bd9Sstevel@tonic-gate } 1079*7c478bd9Sstevel@tonic-gate i_ddi_free_exported_classes(classes, nclass); 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate mutex_exit(&hwc_hash_lock); 1082*7c478bd9Sstevel@tonic-gate return (list); 1083*7c478bd9Sstevel@tonic-gate } 1084