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