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