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