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