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.
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.
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]
22 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/param.h>
26 #include <sys/modctl.h>
27 #include <sys/modhash.h>
30 #include <sys/errno.h>
31 #include <sys/sysmacros.h>
33 #include <sys/cmn_err.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>
46 #include <sys/varargs.h>
47 #include <sys/thread.h>
49 #include <sys/autoconf.h>
51 #include <sys/consdev.h>
52 #include <sys/systm.h>
53 #include <sys/debug.h>
54 #include <sys/atomic.h>
56 extern struct dev_ops nodev_ops
;
57 extern struct dev_ops mod_nodev_ops
;
60 struct mod_noload
*mn_next
;
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
*);
75 major_valid(major_t major
)
77 return (major
!= DDI_MAJOR_T_NONE
&&
78 (major
>= 0 && major
< devcnt
));
82 driver_installed(major_t major
)
84 return (major_valid(major
) && devnamesp
[major
].dn_name
!= NULL
);
88 driver_active(major_t major
)
90 return (driver_installed(major
) && !(devnamesp
[major
].dn_flags
&
91 (DN_DRIVER_REMOVED
|DN_DRIVER_INACTIVE
)));
95 mod_hold_dev_by_major(major_t major
)
97 struct dev_ops
**devopspp
, *ops
;
101 if (!driver_active(major
))
104 LOCK_DEV_OPS(&(devnamesp
[major
].dn_lock
));
105 devopspp
= &devopsp
[major
];
107 while (loaded
&& !CB_DRV_INSTALLED(*devopspp
)) {
108 UNLOCK_DEV_OPS(&(devnamesp
[major
].dn_lock
));
109 drvname
= mod_major_to_name(major
);
112 loaded
= (modload("drv", drvname
) != -1);
113 LOCK_DEV_OPS(&(devnamesp
[major
].dn_lock
));
116 INCR_DEV_OPS_REF(*devopspp
);
121 UNLOCK_DEV_OPS(&(devnamesp
[major
].dn_lock
));
126 static int mod_rele_pause
= DEBUG_RELE
;
127 #endif /* DEBUG_RELE */
130 mod_rele_dev_by_major(major_t major
)
133 struct devnames
*dnp
;
135 if (!driver_active(major
))
138 dnp
= &devnamesp
[major
];
139 LOCK_DEV_OPS(&dnp
->dn_lock
);
140 ops
= devopsp
[major
];
141 ASSERT(CB_DRV_INSTALLED(ops
));
144 if (!DEV_OPS_HELD(ops
)) {
146 static char *msg
= "mod_rele_dev_by_major: unheld driver!";
148 printf("mod_rele_dev_by_major: Major dev <%u>, name <%s>\n",
150 (s
= mod_major_to_name(major
)) ? s
: "unknown");
155 UNLOCK_DEV_OPS(&dnp
->dn_lock
);
156 return; /* XXX: Note changed behavior */
159 #endif /* DEBUG_RELE */
161 if (!DEV_OPS_HELD(ops
)) {
163 "mod_rele_dev_by_major: Unheld driver: major number <%u>",
166 DECR_DEV_OPS_REF(ops
);
167 UNLOCK_DEV_OPS(&dnp
->dn_lock
);
171 mod_hold_dev_by_devi(dev_info_t
*devi
)
176 name
= ddi_get_name(devi
);
177 if ((major
= mod_name_to_major(name
)) == DDI_MAJOR_T_NONE
)
179 return (mod_hold_dev_by_major(major
));
183 mod_rele_dev_by_devi(dev_info_t
*devi
)
188 name
= ddi_get_name(devi
);
189 if ((major
= mod_name_to_major(name
)) == DDI_MAJOR_T_NONE
)
191 mod_rele_dev_by_major(major
);
219 * Install all the stubs for a module.
220 * Return zero if there were no errors or an errno value.
223 install_stubs_by_name(struct modctl
*modp
, char *name
)
227 char namebuf
[MODMAXNAMELEN
+ 12];
228 struct mod_modinfo
*mp
;
238 * Concatenate "name" with "_modname" then look up this symbol
239 * in the kernel. If not found, we're done.
240 * If found, then find the "mod" info structure and call init_stubs().
244 while (*filenamep
&& *filenamep
!= '.')
247 (void) strcpy(p
, "_modinfo");
249 if ((mp
= (struct mod_modinfo
*)modgetsymvalue(namebuf
, 1)) != 0)
250 return (init_stubs(modp
, mp
));
256 init_stubs(struct modctl
*modp
, struct mod_modinfo
*mp
)
258 struct mod_stub_info
*sp
;
264 modp
->mod_modinfo
= mp
;
267 * Fill in all stubs for this module. We can't be lazy, since
268 * some calls could come in from interrupt level, and we
269 * can't modlookup then (symbols may be paged out).
272 for (i
= 0; sp
->mods_func_adr
; i
++, sp
++) {
273 funcname
= modgetsymname(sp
->mods_stub_adr
, &offset
);
274 if (funcname
== NULL
) {
275 printf("init_stubs: couldn't find symbol "
276 "in module %s\n", mp
->modm_module_name
);
279 funcadr
= kobj_lookup(modp
->mod_mp
, funcname
);
281 if (kobj_addrcheck(modp
->mod_mp
, (caddr_t
)funcadr
)) {
282 printf("%s:%s() not defined properly\n",
283 mp
->modm_module_name
, funcname
);
286 sp
->mods_func_adr
= funcadr
;
293 * modp->mod_modinfo has to be checked in these functions before
294 * mod_stub_info is accessed because it's not guranteed that all
295 * modules define mod_stub_info structures.
298 install_stubs(struct modctl
*modp
)
300 struct mod_stub_info
*stub
;
302 if (modp
->mod_modinfo
) {
304 for (stub
= modp
->mod_modinfo
->modm_stubs
;
305 stub
->mods_func_adr
; stub
++) {
306 stub
->mods_flag
|= MODS_INSTALLED
;
313 uninstall_stubs(struct modctl
*modp
)
315 struct mod_stub_info
*stub
;
317 if (modp
->mod_modinfo
) {
319 for (stub
= modp
->mod_modinfo
->modm_stubs
;
320 stub
->mods_func_adr
; stub
++) {
321 stub
->mods_flag
&= ~MODS_INSTALLED
;
328 reset_stubs(struct modctl
*modp
)
330 struct mod_stub_info
*stub
;
332 if (modp
->mod_modinfo
) {
333 for (stub
= modp
->mod_modinfo
->modm_stubs
;
334 stub
->mods_func_adr
; stub
++) {
335 if (stub
->mods_flag
& (MODS_WEAK
| MODS_NOUNLOAD
))
336 stub
->mods_func_adr
=
337 (uintptr_t)stub
->mods_errfcn
;
339 stub
->mods_func_adr
=
340 (uintptr_t)mod_hold_stub
;
342 modp
->mod_modinfo
->mp
= NULL
;
347 mod_getctl(struct modlinkage
*modlp
)
351 mutex_enter(&mod_lock
);
354 if (modp
->mod_linkage
== modlp
) {
355 mutex_exit(&mod_lock
);
358 } while ((modp
= modp
->mod_next
) != &modules
);
359 mutex_exit(&mod_lock
);
365 * Attach driver.conf info to devnames for a driver
368 impl_make_parlist(major_t major
)
371 struct par_list
*pl
= NULL
, *tmp
;
372 ddi_prop_t
*props
= NULL
;
373 char *confname
, *drvname
;
374 struct devnames
*dnp
;
376 dnp
= &devnamesp
[major
];
378 ASSERT(mutex_owned(&dnp
->dn_lock
));
381 * If .conf file already parsed or driver removed, just return.
384 if (dnp
->dn_flags
& (DN_CONF_PARSED
| DN_DRIVER_REMOVED
))
387 drvname
= mod_major_to_name(major
);
391 confname
= kmem_alloc(MAXNAMELEN
, KM_SLEEP
);
392 (void) snprintf(confname
, MAXNAMELEN
, "drv/%s.conf", drvname
);
393 err
= hwc_parse(confname
, &pl
, &props
);
394 kmem_free(confname
, MAXNAMELEN
);
395 if (err
) /* file doesn't exist */
399 * If there are global properties, reference it from dnp.
402 dnp
->dn_global_prop_ptr
= i_ddi_prop_list_create(props
);
405 * Hash specs to be looked up by nexus drivers
409 (void) hwc_hash(tmp
->par_specs
, major
);
413 if (!i_ddi_io_initialized()) {
414 if (i_ddi_prop_search(DDI_DEV_T_ANY
, DDI_FORCEATTACH
,
415 DDI_PROP_TYPE_INT
, &props
))
416 dnp
->dn_flags
|= DN_FORCE_ATTACH
;
417 if (i_ddi_prop_search(DDI_DEV_T_ANY
, DDI_OPEN_RETURNS_EINTR
,
418 DDI_PROP_TYPE_INT
, &props
))
419 dnp
->dn_flags
|= DN_OPEN_RETURNS_EINTR
;
420 if (i_ddi_prop_search(DDI_DEV_T_ANY
, "scsi-size-clean",
421 DDI_PROP_TYPE_INT
, &props
))
422 dnp
->dn_flags
|= DN_SCSI_SIZE_CLEAN
;
425 if (i_ddi_prop_search(DDI_DEV_T_ANY
, DDI_VHCI_CLASS
,
426 DDI_PROP_TYPE_STRING
, &props
))
427 dnp
->dn_flags
|= DN_PHCI_DRIVER
;
429 if (i_ddi_prop_search(DDI_DEV_T_ANY
, DDI_DEVID_REGISTRANT
,
430 DDI_PROP_TYPE_INT
, &props
)) {
431 dnp
->dn_flags
|= DN_DEVID_REGISTRANT
;
434 dnp
->dn_flags
|= DN_CONF_PARSED
;
440 * Destroy driver.conf info in devnames array for a driver
443 impl_free_parlist(major_t major
)
446 struct devnames
*dnp
= &devnamesp
[major
];
449 * Unref driver global property list. Don't destroy it
450 * because some instances may still be referencing it.
451 * The property list will be freed when the last ref
454 if (dnp
->dn_global_prop_ptr
) {
455 i_ddi_prop_list_rele(dnp
->dn_global_prop_ptr
, dnp
);
456 dnp
->dn_global_prop_ptr
= NULL
;
460 * remove specs from hash table
462 for (pl
= dnp
->dn_pl
; pl
; pl
= pl
->par_next
)
463 hwc_unhash(pl
->par_specs
);
465 impl_delete_par_list(dnp
->dn_pl
);
467 dnp
->dn_flags
&= ~DN_CONF_PARSED
;
471 struct bind
*mb_hashtab
[MOD_BIND_HASHSIZE
];
472 struct bind
*sb_hashtab
[MOD_BIND_HASHSIZE
];
480 for (c
= *name
++; c
; c
= *name
++)
483 return (hash
& MOD_BIND_HASHMASK
);
487 clear_binding_hash(struct bind
**bhash
)
490 struct bind
*bp
, *bp1
;
492 for (i
= 0; i
< MOD_BIND_HASHSIZE
; i
++) {
495 kmem_free(bp
->b_name
, strlen(bp
->b_name
) + 1);
496 if (bp
->b_bind_name
) {
497 kmem_free(bp
->b_bind_name
,
498 strlen(bp
->b_bind_name
) + 1);
502 kmem_free(bp1
, sizeof (struct bind
));
508 /* Find an mbind by name match (caller can ask for deleted match) */
510 find_mbind(char *name
, struct bind
**hashtab
, int deleted
)
514 for (mb
= hashtab
[nm_hash(name
)]; mb
; mb
= mb
->b_next
) {
515 if (deleted
&& (mb
->b_num
>= 0))
516 continue; /* skip active */
517 if (!deleted
&& (mb
->b_num
< 0))
518 continue; /* skip deleted */
520 /* return if name matches */
521 if (strcmp(name
, mb
->b_name
) == 0) {
529 * Create an entry for the given (name, major, bind_name) tuple in the
530 * hash table supplied. Reject the attempt to do so if 'name' is already
533 * Does not provide synchronization, so use only during boot or with
534 * externally provided locking.
537 make_mbind(char *name
, int num
, char *bind_name
, struct bind
**hashtab
)
542 ASSERT(hashtab
!= NULL
);
545 /* Fail if the key being added is already established */
546 if (find_mbind(name
, hashtab
, 0) != NULL
)
549 /* Allocate new mbind */
550 mb
= kmem_zalloc(sizeof (struct bind
), KM_SLEEP
);
551 mb
->b_name
= i_ddi_strdup(name
, KM_SLEEP
);
553 if (bind_name
!= NULL
)
554 mb
->b_bind_name
= i_ddi_strdup(bind_name
, KM_SLEEP
);
556 /* Insert at head of hash */
557 pmb
= &hashtab
[nm_hash(name
)];
564 * Delete a binding from a binding-hash. Since there is no locking we
565 * delete an mbind by making its b_num negative. We also support find_mbind
566 * of deleted entries, so we still need deleted items on the list.
569 delete_mbind(char *name
, struct bind
**hashtab
)
573 for (mb
= hashtab
[nm_hash(name
)]; mb
; mb
= mb
->b_next
) {
574 if ((mb
->b_num
>= 0) && (strcmp(name
, mb
->b_name
) == 0)) {
575 /* delete by making b_num negative */
576 if (moddebug
& MODDEBUG_BINDING
) {
577 cmn_err(CE_CONT
, "mbind: %s %d deleted\n",
580 mb
->b_num
= -mb
->b_num
;
587 * Delete all items in an mbind associated with specified num.
588 * An example would be rem_drv deleting all aliases associated with a
589 * driver major number.
592 purge_mbind(int num
, struct bind
**hashtab
)
597 /* search all hash lists for items that associated with 'num' */
598 for (i
= 0; i
< MOD_BIND_HASHSIZE
; i
++) {
599 for (mb
= hashtab
[i
]; mb
; mb
= mb
->b_next
) {
600 if (mb
->b_num
== num
) {
601 if (moddebug
& MODDEBUG_BINDING
)
603 "mbind: %s %d purged\n",
605 /* purge by changing the sign */
613 mod_name_to_major(char *name
)
618 /* Search for non-deleted match. */
619 if ((mbind
= find_mbind(name
, mb_hashtab
, 0)) != NULL
) {
620 if (moddebug
& MODDEBUG_BINDING
) {
621 if (find_mbind(name
, mb_hashtab
, 1))
623 "'%s' has deleted match too\n", name
);
625 return ((major_t
)mbind
->b_num
);
629 * Search for deleted match: We may find that we have dependencies
630 * on drivers that have been deleted (but the old driver may still
631 * be bound to a node). These callers should be converted to use
632 * ddi_driver_major(i.e. devi_major).
634 if (moddebug
& MODDEBUG_BINDING
) {
635 if ((mbind
= find_mbind(name
, mb_hashtab
, 1)) != NULL
) {
636 maj
= (major_t
)(-(mbind
->b_num
));
637 cmn_err(CE_CONT
, "Reference to deleted alias '%s' %d\n",
642 return (DDI_MAJOR_T_NONE
);
646 mod_major_to_name(major_t major
)
648 if (!driver_installed(major
))
650 return ((&devnamesp
[major
])->dn_name
);
654 * Set up the devnames array. Error check for duplicate entries.
657 init_devnamesp(int size
)
661 static char dupwarn
[] =
662 "!Device entry \"%s %d\" conflicts with previous entry \"%s %d\" "
663 "in /etc/name_to_major.";
664 static char badmaj
[] = "The major number %u is invalid.";
666 ASSERT(size
<= L_MAXMAJ32
&& size
> 0);
669 * Allocate the devnames array. All mutexes and cv's will be
670 * automagically initialized.
672 devnamesp
= kobj_zalloc(size
* sizeof (struct devnames
), KM_SLEEP
);
675 * Stick the contents of mb_hashtab into the devnames array. Warn if
676 * two hash entries correspond to the same major number, or if a
677 * major number is out of range.
679 for (hshndx
= 0; hshndx
< MOD_BIND_HASHSIZE
; hshndx
++) {
680 for (bp
= mb_hashtab
[hshndx
]; bp
; bp
= bp
->b_next
) {
681 if (make_devname(bp
->b_name
,
682 (major_t
)bp
->b_num
, 0) != 0) {
684 * If there is not an entry at b_num already,
685 * then this must be a bad major number.
687 char *nm
= mod_major_to_name(bp
->b_num
);
689 cmn_err(CE_WARN
, badmaj
,
692 cmn_err(CE_WARN
, dupwarn
, bp
->b_name
,
693 bp
->b_num
, nm
, bp
->b_num
);
699 /* Initialize hash table for hwc_spec's */
704 make_devname(char *name
, major_t major
, int dn_flags
)
706 struct devnames
*dnp
;
710 * Until on-disk support for major nums > 14 bits arrives, fail
711 * any major numbers that are too big.
713 if (major
> L_MAXMAJ32
)
716 dnp
= &devnamesp
[major
];
717 LOCK_DEV_OPS(&dnp
->dn_lock
);
719 if (strcmp(dnp
->dn_name
, name
) != 0) {
720 /* Another driver already here */
721 UNLOCK_DEV_OPS(&dnp
->dn_lock
);
724 /* Adding back a removed driver */
725 dnp
->dn_flags
&= ~DN_DRIVER_REMOVED
;
726 dnp
->dn_flags
|= dn_flags
;
727 UNLOCK_DEV_OPS(&dnp
->dn_lock
);
732 * Check if flag is taken by getudev()
734 if (dnp
->dn_flags
& DN_TAKEN_GETUDEV
) {
735 UNLOCK_DEV_OPS(&dnp
->dn_lock
);
739 copy
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
740 (void) strcpy(copy
, name
);
742 /* Make sure string is copied before setting dn_name */
745 dnp
->dn_flags
= dn_flags
;
746 UNLOCK_DEV_OPS(&dnp
->dn_lock
);
751 * Set up the syscallnames array.
754 init_syscallnames(int size
)
759 syscallnames
= kobj_zalloc(size
* sizeof (char *), KM_SLEEP
);
761 for (hshndx
= 0; hshndx
< MOD_BIND_HASHSIZE
; hshndx
++) {
762 for (bp
= sb_hashtab
[hshndx
]; bp
; bp
= bp
->b_next
) {
763 if (bp
->b_num
< 0 || bp
->b_num
>= size
) {
765 "!Couldn't add system call \"%s %d\". "
766 "Value out of range (0..%d) in "
767 "/etc/name_to_sysnum.",
768 bp
->b_name
, bp
->b_num
, size
- 1);
771 make_syscallname(bp
->b_name
, bp
->b_num
);
777 make_syscallname(char *name
, int sysno
)
779 char **cp
= &syscallnames
[sysno
];
782 cmn_err(CE_WARN
, "!Couldn't add system call \"%s %d\". "
783 "It conflicts with \"%s %d\" in /etc/name_to_sysnum.",
784 name
, sysno
, *cp
, sysno
);
787 *cp
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
788 (void) strcpy(*cp
, name
);
792 * Given a system call name, get its number.
795 mod_getsysnum(char *name
)
799 if ((mbind
= find_mbind(name
, sb_hashtab
, 0)) != NULL
)
800 return (mbind
->b_num
);
806 * Given a system call number, get the system call name.
809 mod_getsysname(int sysnum
)
811 return (syscallnames
[sysnum
]);
815 * Find the name of the module containing the specified pc.
816 * Returns the name on success, "<unknown>" on failure.
817 * No mod_lock locking is required because things are never deleted from
821 mod_containing_pc(caddr_t pc
)
823 struct modctl
*mcp
= &modules
;
826 if (mcp
->mod_mp
!= NULL
&&
827 (size_t)pc
- (size_t)mcp
->mod_text
< mcp
->mod_text_size
)
828 return (mcp
->mod_modname
);
829 } while ((mcp
= mcp
->mod_next
) != &modules
);
830 return ("<unknown>");
834 * Hash tables for hwc_spec
836 * The purpose of these hash tables are to allow the framework to discover
837 * all possible .conf children for a given nexus. There are two hash tables.
838 * One is hashed based on parent name, the on the class name. Each
839 * driver.conf file translates to a list of hwc_spec's. Adding and
840 * removing the entire list is an atomic operation, protected by
843 * What we get from all the hashing is the function hwc_get_child_spec().
845 #define HWC_SPEC_HASHSIZE (1 << 6) /* 64 */
847 static mod_hash_t
*hwc_par_hash
; /* hash by parent name */
848 static mod_hash_t
*hwc_class_hash
; /* hash by class name */
849 static kmutex_t hwc_hash_lock
; /* lock protecting hwc hashes */
852 * Initialize hash tables for parent and class specs
857 hwc_par_hash
= mod_hash_create_strhash("hwc parent spec hash",
858 HWC_SPEC_HASHSIZE
, mod_hash_null_valdtor
);
859 hwc_class_hash
= mod_hash_create_strhash("hwc class spec hash",
860 HWC_SPEC_HASHSIZE
, mod_hash_null_valdtor
);
864 * Insert a spec into hash table. hwc_hash_lock must be held
867 hwc_hash_insert(struct hwc_spec
*spec
, char *name
, mod_hash_t
*hash
)
870 struct hwc_spec
*entry
= NULL
;
872 ASSERT(name
!= NULL
);
874 if (mod_hash_find(hash
, (mod_hash_key_t
)name
,
875 (mod_hash_val_t
)&entry
) != 0) {
876 /* Name doesn't exist, insert a new key */
877 key
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
878 (void) strcpy((char *)key
, name
);
879 if (mod_hash_insert(hash
, key
, (mod_hash_val_t
)spec
) != 0) {
880 kmem_free(key
, strlen(name
) + 1);
881 cmn_err(CE_WARN
, "hwc hash state inconsistent");
887 * Name is already present, append spec to the list.
888 * This is the case when driver.conf specifies multiple
889 * nodes under a single parent or class.
891 while (entry
->hwc_hash_next
)
892 entry
= entry
->hwc_hash_next
;
893 entry
->hwc_hash_next
= spec
;
897 * Remove a spec entry from spec hash table, the spec itself is
898 * destroyed external to this function.
901 hwc_hash_remove(struct hwc_spec
*spec
, char *name
, mod_hash_t
*hash
)
904 struct hwc_spec
*entry
;
906 ASSERT(name
!= NULL
);
908 if (mod_hash_find(hash
, (mod_hash_key_t
)name
,
909 (mod_hash_val_t
)&entry
) != 0) {
910 return; /* name not found in hash */
914 * If the head is the spec to be removed, either destroy the
915 * entry or replace it with the remaining list.
918 if (spec
->hwc_hash_next
== NULL
) {
919 (void) mod_hash_destroy(hash
, (mod_hash_key_t
)name
);
922 key
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
923 (void) strcpy(key
, name
);
924 (void) mod_hash_replace(hash
, (mod_hash_key_t
)key
,
925 (mod_hash_val_t
)spec
->hwc_hash_next
);
926 spec
->hwc_hash_next
= NULL
;
931 * If the head is not the one, look for the spec in the
932 * hwc_hash_next linkage.
934 while (entry
->hwc_hash_next
&& (entry
->hwc_hash_next
!= spec
))
935 entry
= entry
->hwc_hash_next
;
937 if (entry
->hwc_hash_next
) {
938 entry
->hwc_hash_next
= spec
->hwc_hash_next
;
939 spec
->hwc_hash_next
= NULL
;
944 * Hash a list of specs based on either parent name or class name
947 hwc_hash(struct hwc_spec
*spec_list
, major_t major
)
949 struct hwc_spec
*spec
= spec_list
;
951 mutex_enter(&hwc_hash_lock
);
953 /* Put driver major here so parent can find it */
954 spec
->hwc_major
= major
;
956 if (spec
->hwc_parent_name
!= NULL
) {
957 hwc_hash_insert(spec
, spec
->hwc_parent_name
,
959 } else if (spec
->hwc_class_name
!= NULL
) {
960 hwc_hash_insert(spec
, spec
->hwc_class_name
,
964 "hwc_hash: No class or parent specified");
966 spec
= spec
->hwc_next
;
968 mutex_exit(&hwc_hash_lock
);
972 * Remove a list of specs from hash tables. Don't destroy the specs yet.
975 hwc_unhash(struct hwc_spec
*spec_list
)
977 struct hwc_spec
*spec
= spec_list
;
979 mutex_enter(&hwc_hash_lock
);
981 if (spec
->hwc_parent_name
!= NULL
) {
982 hwc_hash_remove(spec
, spec
->hwc_parent_name
,
984 } else if (spec
->hwc_class_name
!= NULL
) {
985 hwc_hash_remove(spec
, spec
->hwc_class_name
,
989 "hwc_unhash: No class or parent specified");
991 spec
= spec
->hwc_next
;
993 mutex_exit(&hwc_hash_lock
);
997 * Make a copy of specs in a hash entry and add to the end of listp.
998 * Called by nexus to locate a list of child specs.
1000 * entry is a list of hwc_spec chained together with hwc_hash_next.
1001 * listp points to list chained together with hwc_next.
1004 hwc_spec_add(struct hwc_spec
**listp
, struct hwc_spec
*entry
,
1005 major_t match_major
)
1007 /* Find the tail of the list */
1009 listp
= &(*listp
)->hwc_next
;
1012 struct hwc_spec
*spec
;
1014 if ((match_major
!= DDI_MAJOR_T_NONE
) &&
1015 (match_major
!= entry
->hwc_major
)) {
1016 entry
= entry
->hwc_hash_next
;
1021 * Allocate spec and copy the content of entry.
1022 * No need to copy class/parent name since caller
1023 * already knows the parent dip.
1025 spec
= kmem_zalloc(sizeof (*spec
), KM_SLEEP
);
1026 spec
->hwc_devi_name
= i_ddi_strdup(
1027 entry
->hwc_devi_name
, KM_SLEEP
);
1028 spec
->hwc_major
= entry
->hwc_major
;
1029 spec
->hwc_devi_sys_prop_ptr
= i_ddi_prop_list_dup(
1030 entry
->hwc_devi_sys_prop_ptr
, KM_SLEEP
);
1033 listp
= &spec
->hwc_next
;
1034 entry
= entry
->hwc_hash_next
;
1039 * Given a dip, find the list of child .conf specs from most specific
1040 * (parent pathname) to least specific (class name).
1042 * This function allows top-down loading to be implemented without
1043 * changing the format of driver.conf file.
1046 hwc_get_child_spec(dev_info_t
*dip
, major_t match_major
)
1048 extern char *i_ddi_parname(dev_info_t
*, char *);
1049 extern int i_ddi_get_exported_classes(dev_info_t
*, char ***);
1050 extern void i_ddi_free_exported_classes(char **, int);
1054 struct hwc_spec
*list
= NULL
;
1056 char *parname
, *parname_buf
;
1057 char *deviname
, *deviname_buf
;
1058 char *pathname
, *pathname_buf
;
1062 pathname_buf
= kmem_alloc(3 * MAXPATHLEN
, KM_SLEEP
);
1063 deviname_buf
= pathname_buf
+ MAXPATHLEN
;
1064 parname_buf
= pathname_buf
+ (2 * MAXPATHLEN
);
1066 mutex_enter(&hwc_hash_lock
);
1069 * Lookup based on full path.
1070 * In the case of root node, ddi_pathname would return
1071 * null string so just skip calling it.
1072 * As the pathname always begins with /, no simpler
1073 * name can duplicate it.
1075 pathname
= (dip
== ddi_root_node()) ? "/" :
1076 ddi_pathname(dip
, pathname_buf
);
1077 ASSERT(pathname
!= NULL
);
1078 ASSERT(*pathname
== '/');
1080 if (mod_hash_find(hwc_par_hash
, (mod_hash_key_t
)pathname
, &val
) == 0) {
1081 hwc_spec_add(&list
, (struct hwc_spec
*)val
, match_major
);
1085 * Lookup nodename@address.
1086 * Note deviname cannot match pathname.
1088 deviname
= ddi_deviname(dip
, deviname_buf
);
1089 if (*deviname
!= '\0') {
1091 * Skip leading / returned by ddi_deviname.
1093 ASSERT(*deviname
== '/');
1095 if ((*deviname
!= '\0') && (mod_hash_find(hwc_par_hash
,
1096 (mod_hash_key_t
)deviname
, &val
) == 0))
1098 (struct hwc_spec
*)val
, match_major
);
1102 * Lookup bindingname@address.
1103 * Take care not to perform duplicate lookups.
1105 parname
= i_ddi_parname(dip
, parname_buf
);
1106 if (*parname
!= '\0') {
1107 ASSERT(*parname
!= '/');
1108 if ((strcmp(parname
, deviname
) != 0) &&
1109 (mod_hash_find(hwc_par_hash
,
1110 (mod_hash_key_t
)parname
, &val
) == 0)) {
1112 (struct hwc_spec
*)val
, match_major
);
1117 * Lookup driver binding name
1119 bindname
= ddi_binding_name(dip
);
1120 ASSERT(*bindname
!= '/');
1121 if ((strcmp(bindname
, parname
) != 0) &&
1122 (strcmp(bindname
, deviname
) != 0) &&
1123 (mod_hash_find(hwc_par_hash
, (mod_hash_key_t
)bindname
, &val
) == 0))
1124 hwc_spec_add(&list
, (struct hwc_spec
*)val
, match_major
);
1127 * Lookup driver name
1129 drvname
= (char *)ddi_driver_name(dip
);
1130 ASSERT(*drvname
!= '/');
1131 if ((strcmp(drvname
, bindname
) != 0) &&
1132 (strcmp(drvname
, parname
) != 0) &&
1133 (strcmp(drvname
, deviname
) != 0) &&
1134 (mod_hash_find(hwc_par_hash
, (mod_hash_key_t
)drvname
, &val
) == 0))
1135 hwc_spec_add(&list
, (struct hwc_spec
*)val
, match_major
);
1137 kmem_free(pathname_buf
, 3 * MAXPATHLEN
);
1140 * Lookup classes exported by this node and lookup the
1141 * class hash table for all .conf specs
1143 nclass
= i_ddi_get_exported_classes(dip
, &classes
);
1144 for (i
= 0; i
< nclass
; i
++) {
1145 if (mod_hash_find(hwc_class_hash
, (mod_hash_key_t
)classes
[i
],
1147 hwc_spec_add(&list
, (struct hwc_spec
*)val
,
1150 i_ddi_free_exported_classes(classes
, nclass
);
1152 mutex_exit(&hwc_hash_lock
);