xref: /titanic_44/usr/src/lib/libdiskmgt/common/cache.c (revision 82d71480b3c112fa91f04032225eda15dfe22e17)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
233e1bd7a2Ssjelinek  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <fcntl.h>
307c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
34*82d71480Ssjelinek #include <libintl.h>
357c478bd9Sstevel@tonic-gate #include <synch.h>
367c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <libgen.h>
39*82d71480Ssjelinek #include <syslog.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include "libdiskmgt.h"
427c478bd9Sstevel@tonic-gate #include "disks_private.h"
437c478bd9Sstevel@tonic-gate #include "partition.h"
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #define	ALIASES		0
467c478bd9Sstevel@tonic-gate #define	DEVPATHS	1
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  * Set DM_LIBDISKMGT_DEBUG in the environment.  Two levels of debugging:
507c478bd9Sstevel@tonic-gate  *    1 - errors, warnings and minimal tracing information
517c478bd9Sstevel@tonic-gate  *    2 - verbose information
527c478bd9Sstevel@tonic-gate  * All output prints on stderr.
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate int dm_debug = 0;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /* Lock protecting the cached data */
577c478bd9Sstevel@tonic-gate static rwlock_t		cache_lock = DEFAULTRWLOCK;
587c478bd9Sstevel@tonic-gate static disk_t		*disk_listp = NULL;
597c478bd9Sstevel@tonic-gate static controller_t	*controller_listp = NULL;
607c478bd9Sstevel@tonic-gate static bus_t		*bus_listp = NULL;
617c478bd9Sstevel@tonic-gate static int		cache_loaded = 0;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate descriptor_t		*desc_listp = NULL;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static void		clear_descriptors(void *gp);
667c478bd9Sstevel@tonic-gate static void		clr_ctrl_disk_ptr(controller_t *cp, disk_t *dp);
677c478bd9Sstevel@tonic-gate static void		clr_path_disk_ptr(path_t *pp, disk_t *dp);
687c478bd9Sstevel@tonic-gate static void		del_drive(disk_t *dp);
697c478bd9Sstevel@tonic-gate static void		del_drive_by_name(char *name);
707c478bd9Sstevel@tonic-gate static descriptor_t	*have_desc(int type, void *gp, char *name, char *mname);
717c478bd9Sstevel@tonic-gate static int		initialize();
727c478bd9Sstevel@tonic-gate static int		make_descriptors(int type);
737c478bd9Sstevel@tonic-gate static int		match_disk(disk_t *oldp, disk_t *newp);
747c478bd9Sstevel@tonic-gate static int		match_aliases(disk_t *d1p, disk_t *d2p);
757c478bd9Sstevel@tonic-gate static int		match_alias(alias_t *ap, alias_t *listp);
767c478bd9Sstevel@tonic-gate static descriptor_t	*new_descriptor(dm_desc_type_t type, void *op,
777c478bd9Sstevel@tonic-gate 			    char *name, char *mname);
787c478bd9Sstevel@tonic-gate static void		rewalk_tree();
797c478bd9Sstevel@tonic-gate static void		update_desc(descriptor_t *descp, disk_t *newdisksp,
807c478bd9Sstevel@tonic-gate 			    controller_t *newctrlp, bus_t *newbusp);
817c478bd9Sstevel@tonic-gate static void		update_desc_busp(descriptor_t *descp, bus_t *busp);
827c478bd9Sstevel@tonic-gate static void		update_desc_ctrlp(descriptor_t *descp,
837c478bd9Sstevel@tonic-gate 			    controller_t *newstrlp);
847c478bd9Sstevel@tonic-gate static void		update_desc_diskp(descriptor_t *descp,
857c478bd9Sstevel@tonic-gate 			    disk_t *newdisksp);
867c478bd9Sstevel@tonic-gate static void		update_desc_pathp(descriptor_t *descp,
877c478bd9Sstevel@tonic-gate 			    controller_t *newctrlp);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate  * We only cache some of the data that we can obtain.  For much of the data
917c478bd9Sstevel@tonic-gate  * (e.g. slices & disks getting repartitioned) there are no events which would
927c478bd9Sstevel@tonic-gate  * enable us to cache.  As more events are added we can cache more information.
937c478bd9Sstevel@tonic-gate  *
947c478bd9Sstevel@tonic-gate  * Currently we cache the information we get from the dev tree walk.  This is
957c478bd9Sstevel@tonic-gate  * basically the information about the drives, aliases, devpaths, controllers
967c478bd9Sstevel@tonic-gate  * and paths.  We do not cache any information related to media, partitions
977c478bd9Sstevel@tonic-gate  * or slices.
987c478bd9Sstevel@tonic-gate  *
997c478bd9Sstevel@tonic-gate  * A fundamental part of the API design is that the application can hold on
1007c478bd9Sstevel@tonic-gate  * to a set of descriptors for an indeterminate amount of time.  Even if the
1017c478bd9Sstevel@tonic-gate  * application does not hold descriptors there is a window of time between the
1027c478bd9Sstevel@tonic-gate  * call that gets the descriptor and the use of the descriptor to get more
1037c478bd9Sstevel@tonic-gate  * information.  Because of this, the cache design must work even if the object
1047c478bd9Sstevel@tonic-gate  * that the descriptor refers to no longer exists.
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * Given this requirement, the code implements a two level cache.  The
1077c478bd9Sstevel@tonic-gate  * descriptors that the application gets are really pointers into the first
1087c478bd9Sstevel@tonic-gate  * level of the cache.  This first level contains the actual descriptors.
1097c478bd9Sstevel@tonic-gate  * These descriptors in turn refer to the objects we build from the dev tree
1107c478bd9Sstevel@tonic-gate  * walk which represent the drives and controllers.  This is the second level
1117c478bd9Sstevel@tonic-gate  * in the cache.
1127c478bd9Sstevel@tonic-gate  *
1137c478bd9Sstevel@tonic-gate  * When we update the second level of the cache (the drives and controllers)
1147c478bd9Sstevel@tonic-gate  * we go through the first level (the descriptors) and update the pointers
1157c478bd9Sstevel@tonic-gate  * in those descriptors to refer to the new objects in the second level.  If
1167c478bd9Sstevel@tonic-gate  * the object that the descriptor referred to is no longer in existence, we
1177c478bd9Sstevel@tonic-gate  * just null out the pointer in the descriptor.  In this way the code that
1187c478bd9Sstevel@tonic-gate  * uses the descriptors knows that the object referred to by the descriptor
1197c478bd9Sstevel@tonic-gate  * no longer exists.
1207c478bd9Sstevel@tonic-gate  *
1217c478bd9Sstevel@tonic-gate  * We keep a reference count in the descriptors.  This is incremented when
1227c478bd9Sstevel@tonic-gate  * we hand out a pointer to the descriptor and decremented when the application
1237c478bd9Sstevel@tonic-gate  * frees the descriptor it has.  When the reference count goes to 0 we garbage
1247c478bd9Sstevel@tonic-gate  * collect the descriptors.  In this way we only have to update active
1257c478bd9Sstevel@tonic-gate  * descriptors when we refresh the cache after an event.
1267c478bd9Sstevel@tonic-gate  *
1277c478bd9Sstevel@tonic-gate  * An example of the flow when we create descriptors:
1287c478bd9Sstevel@tonic-gate  *    dm_get_descriptors			libdiskmgt.c
1297c478bd9Sstevel@tonic-gate  *	drive_get_descriptors			drive.c
1307c478bd9Sstevel@tonic-gate  *	    cache_get_descriptors		cache.c
1317c478bd9Sstevel@tonic-gate  *		make_descriptors		cache.c
1327c478bd9Sstevel@tonic-gate  *		    drive_make_descriptors	drive.c
1337c478bd9Sstevel@tonic-gate  *			cache_load_desc		cache.c
1347c478bd9Sstevel@tonic-gate  *		{update refcnts on descriptors & return them}
1357c478bd9Sstevel@tonic-gate  *
1367c478bd9Sstevel@tonic-gate  * The idea behind cache_get_descriptors and cache_load_desc is that we
1377c478bd9Sstevel@tonic-gate  * seperate the act of making the descriptor within the cache (which requires
1387c478bd9Sstevel@tonic-gate  * us to call back out to one of the object functions - drive_make_descriptors)
1397c478bd9Sstevel@tonic-gate  * from the act of handing out the descriptor (which requires us to increment
1407c478bd9Sstevel@tonic-gate  * the refcnt).  In this way we keep all of the refcnt handling centralized
1417c478bd9Sstevel@tonic-gate  * in one function instead of forcing each object to ensure it replicates
1427c478bd9Sstevel@tonic-gate  * the refcnt handling correctly.
1437c478bd9Sstevel@tonic-gate  *
1447c478bd9Sstevel@tonic-gate  * Descriptors use two different kinds of indrection to refer to their
1457c478bd9Sstevel@tonic-gate  * corresponding object.  For objects we cache (controllers, paths & drives)
1467c478bd9Sstevel@tonic-gate  * the descriptor keeps a pointer to that object.  For objects that we
1477c478bd9Sstevel@tonic-gate  * dynamically build, the descriptor uses a combination of a pointer to the
1487c478bd9Sstevel@tonic-gate  * base object (usually the drive) along with a name (e.g. the media name or
1497c478bd9Sstevel@tonic-gate  * the alias).  For objects that are based on media (e.g. a slice) we actually
1507c478bd9Sstevel@tonic-gate  * have to maintain a pointer (to the disk) and two names (e.g. the slice name
1517c478bd9Sstevel@tonic-gate  * and the media name which is the secondary name).
1527c478bd9Sstevel@tonic-gate  */
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate void
1557c478bd9Sstevel@tonic-gate cache_free_alias(alias_t *aliasp)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate 	slice_t	*dp;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	free(aliasp->alias);
1607c478bd9Sstevel@tonic-gate 	free(aliasp->kstat_name);
1617c478bd9Sstevel@tonic-gate 	free(aliasp->wwn);
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	/* free devpaths */
1647c478bd9Sstevel@tonic-gate 	dp = aliasp->devpaths;
1657c478bd9Sstevel@tonic-gate 	while (dp != NULL) {
1667c478bd9Sstevel@tonic-gate 	    slice_t	*nextp;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	    nextp = dp->next;
1697c478bd9Sstevel@tonic-gate 	    free(dp->devpath);
1707c478bd9Sstevel@tonic-gate 	    free(dp);
1717c478bd9Sstevel@tonic-gate 	    dp = nextp;
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	/* free orig_paths */
1757c478bd9Sstevel@tonic-gate 	dp = aliasp->orig_paths;
1767c478bd9Sstevel@tonic-gate 	while (dp != NULL) {
1777c478bd9Sstevel@tonic-gate 	    slice_t	*nextp;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	    nextp = dp->next;
1807c478bd9Sstevel@tonic-gate 	    free(dp->devpath);
1817c478bd9Sstevel@tonic-gate 	    free(dp);
1827c478bd9Sstevel@tonic-gate 	    dp = nextp;
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	free(aliasp);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate void
1897c478bd9Sstevel@tonic-gate cache_free_bus(bus_t *bp)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 	free(bp->name);
1927c478bd9Sstevel@tonic-gate 	free(bp->btype);
1937c478bd9Sstevel@tonic-gate 	free(bp->kstat_name);
1947c478bd9Sstevel@tonic-gate 	free(bp->pname);
1957c478bd9Sstevel@tonic-gate 	free(bp->controllers);
1967c478bd9Sstevel@tonic-gate 	free(bp);
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate void
2007c478bd9Sstevel@tonic-gate cache_free_controller(controller_t *cp)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	free(cp->name);
2037c478bd9Sstevel@tonic-gate 	free(cp->kstat_name);
2047c478bd9Sstevel@tonic-gate 	free(cp->disks);
2057c478bd9Sstevel@tonic-gate 	if (cp->paths != NULL) {
2067c478bd9Sstevel@tonic-gate 	    int i;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	    for (i = 0; cp->paths[i]; i++) {
2097c478bd9Sstevel@tonic-gate 		/* free the path since it can't exist w/o the controller */
2107c478bd9Sstevel@tonic-gate 		cache_free_path(cp->paths[i]);
2117c478bd9Sstevel@tonic-gate 	    }
2127c478bd9Sstevel@tonic-gate 	    free(cp->paths);
2137c478bd9Sstevel@tonic-gate 	}
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	free(cp);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate void
2197c478bd9Sstevel@tonic-gate cache_free_descriptor(descriptor_t *desc)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	if (!cache_is_valid_desc(desc)) {
2227c478bd9Sstevel@tonic-gate 	    return;
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	desc->refcnt--;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	if (desc->refcnt <= 0) {
2287c478bd9Sstevel@tonic-gate 	    free(desc->name);
2297c478bd9Sstevel@tonic-gate 	    free(desc->secondary_name);
2307c478bd9Sstevel@tonic-gate 	    if (desc->prev == NULL) {
2317c478bd9Sstevel@tonic-gate 		/* this is the first descriptor, update head ptr */
2327c478bd9Sstevel@tonic-gate 		desc_listp = desc->next;
2337c478bd9Sstevel@tonic-gate 	    } else {
2347c478bd9Sstevel@tonic-gate 		desc->prev->next = desc->next;
2357c478bd9Sstevel@tonic-gate 	    }
2367c478bd9Sstevel@tonic-gate 	    if (desc->next != NULL) {
2377c478bd9Sstevel@tonic-gate 		desc->next->prev = desc->prev;
2387c478bd9Sstevel@tonic-gate 	    }
2397c478bd9Sstevel@tonic-gate 	    free(desc);
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate void
2447c478bd9Sstevel@tonic-gate cache_free_descriptors(descriptor_t **desc_list)
2457c478bd9Sstevel@tonic-gate {
2467c478bd9Sstevel@tonic-gate 	int i;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	for (i = 0; desc_list[i]; i++) {
2497c478bd9Sstevel@tonic-gate 	    cache_free_descriptor(desc_list[i]);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	free(desc_list);
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate void
2567c478bd9Sstevel@tonic-gate cache_free_disk(disk_t *dp)
2577c478bd9Sstevel@tonic-gate {
2587c478bd9Sstevel@tonic-gate 	alias_t	*ap;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	free(dp->device_id);
2617c478bd9Sstevel@tonic-gate 	if (dp->devid != NULL) {
2627c478bd9Sstevel@tonic-gate 	    devid_free(dp->devid);
2637c478bd9Sstevel@tonic-gate 	}
2647c478bd9Sstevel@tonic-gate 	free(dp->kernel_name);
2657c478bd9Sstevel@tonic-gate 	free(dp->product_id);
2667c478bd9Sstevel@tonic-gate 	free(dp->vendor_id);
2677c478bd9Sstevel@tonic-gate 	free(dp->controllers);
2687c478bd9Sstevel@tonic-gate 	/* the path objects are freed when we free the controller */
2697c478bd9Sstevel@tonic-gate 	free(dp->paths);
2707c478bd9Sstevel@tonic-gate 	ap = dp->aliases;
2717c478bd9Sstevel@tonic-gate 	while (ap != NULL) {
2727c478bd9Sstevel@tonic-gate 	    alias_t	*nextp;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	    nextp = ap->next;
2757c478bd9Sstevel@tonic-gate 	    cache_free_alias(ap);
2767c478bd9Sstevel@tonic-gate 	    ap = nextp;
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	free(dp);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate void
2837c478bd9Sstevel@tonic-gate cache_free_path(path_t *pp)
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate 	int i;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	free(pp->name);
2887c478bd9Sstevel@tonic-gate 	free(pp->disks);
2897c478bd9Sstevel@tonic-gate 	free(pp->states);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	for (i = 0; pp->wwns[i]; i++) {
2927c478bd9Sstevel@tonic-gate 	    free(pp->wwns[i]);
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 	free(pp->wwns);
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	free(pp);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate bus_t *
3007c478bd9Sstevel@tonic-gate cache_get_buslist()
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate 	if (initialize() != 0) {
3037c478bd9Sstevel@tonic-gate 	    return (NULL);
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	return (bus_listp);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate controller_t *
3107c478bd9Sstevel@tonic-gate cache_get_controllerlist()
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	if (initialize() != 0) {
3137c478bd9Sstevel@tonic-gate 	    return (NULL);
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	return (controller_listp);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate /*
3207c478bd9Sstevel@tonic-gate  * This routine will either get the existing descriptor from the descriptor
3217c478bd9Sstevel@tonic-gate  * cache or make make a new descriptor and put it in the descriptor cache and
3227c478bd9Sstevel@tonic-gate  * return a pointer to that descriptor.  We increment the refcnt when we hand
3237c478bd9Sstevel@tonic-gate  * out the descriptor.
3247c478bd9Sstevel@tonic-gate  */
3257c478bd9Sstevel@tonic-gate descriptor_t *
3267c478bd9Sstevel@tonic-gate cache_get_desc(int type, void *gp, char *name, char *secondary_name, int *errp)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	descriptor_t	*dp;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	*errp = 0;
3317c478bd9Sstevel@tonic-gate 	if ((dp = have_desc(type, gp, name, secondary_name)) == NULL) {
3327c478bd9Sstevel@tonic-gate 	    /* make a new desc */
3337c478bd9Sstevel@tonic-gate 	    if ((dp = new_descriptor(type, gp, name, secondary_name)) == NULL) {
3347c478bd9Sstevel@tonic-gate 		*errp = ENOMEM;
3357c478bd9Sstevel@tonic-gate 	    }
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	if (dp != NULL) {
3397c478bd9Sstevel@tonic-gate 	    dp->refcnt++;
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	return (dp);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate descriptor_t **
3467c478bd9Sstevel@tonic-gate cache_get_descriptors(int type, int *errp)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate 	descriptor_t	**descs;
3497c478bd9Sstevel@tonic-gate 	descriptor_t	*descp;
3507c478bd9Sstevel@tonic-gate 	int		cnt = 0;
3517c478bd9Sstevel@tonic-gate 	int		pos;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	if ((*errp = make_descriptors(type)) != 0) {
3547c478bd9Sstevel@tonic-gate 	    return (NULL);
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	/* count the number of active descriptors in the descriptor cache */
3587c478bd9Sstevel@tonic-gate 	descp = desc_listp;
3597c478bd9Sstevel@tonic-gate 	while (descp != NULL) {
3607c478bd9Sstevel@tonic-gate 	    if (descp->type == type && descp->p.generic != NULL) {
3617c478bd9Sstevel@tonic-gate 		cnt++;
3627c478bd9Sstevel@tonic-gate 	    }
3637c478bd9Sstevel@tonic-gate 	    descp = descp->next;
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	descs = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
3677c478bd9Sstevel@tonic-gate 	if (descs == NULL) {
3687c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
3697c478bd9Sstevel@tonic-gate 	    return (NULL);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	pos = 0;
3737c478bd9Sstevel@tonic-gate 	descp = desc_listp;
3747c478bd9Sstevel@tonic-gate 	while (descp != NULL) {
3757c478bd9Sstevel@tonic-gate 	    if (descp->type == type && descp->p.generic != NULL) {
3767c478bd9Sstevel@tonic-gate 		/* update refcnts before handing out the descriptors */
3777c478bd9Sstevel@tonic-gate 		descp->refcnt++;
3787c478bd9Sstevel@tonic-gate 		descs[pos++] = descp;
3797c478bd9Sstevel@tonic-gate 	    }
3807c478bd9Sstevel@tonic-gate 	    descp = descp->next;
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 	descs[pos] = NULL;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	*errp = 0;
3857c478bd9Sstevel@tonic-gate 	return (descs);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate disk_t *
3897c478bd9Sstevel@tonic-gate cache_get_disklist()
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	if (initialize() != 0) {
3927c478bd9Sstevel@tonic-gate 	    return (NULL);
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	return (disk_listp);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate int
3997c478bd9Sstevel@tonic-gate cache_is_valid_desc(descriptor_t *d)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate 	descriptor_t	*descp;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	for (descp = desc_listp; descp != NULL; descp = descp->next) {
4047c478bd9Sstevel@tonic-gate 	    if (descp == d) {
4057c478bd9Sstevel@tonic-gate 		return (1);
4067c478bd9Sstevel@tonic-gate 	    }
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	return (0);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate  * This function is called by the *_make_descriptors function
4147c478bd9Sstevel@tonic-gate  * (e.g. drive_make_descriptors) within each of the objects.  This function
4157c478bd9Sstevel@tonic-gate  * makes sure that the descriptor is built in the descriptor cache but
4167c478bd9Sstevel@tonic-gate  * it does not hand out the descriptors, so the refcnt is never incremented.
4177c478bd9Sstevel@tonic-gate  */
4187c478bd9Sstevel@tonic-gate void
4197c478bd9Sstevel@tonic-gate cache_load_desc(int type, void *gp, char *name, char *secondary_name, int *errp)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate 	*errp = 0;
4227c478bd9Sstevel@tonic-gate 	if (have_desc(type, gp, name, secondary_name) == NULL) {
4237c478bd9Sstevel@tonic-gate 	    /* make a new desc */
4247c478bd9Sstevel@tonic-gate 	    if (new_descriptor(type, gp, name, secondary_name) == NULL) {
4257c478bd9Sstevel@tonic-gate 		*errp = ENOMEM;
4267c478bd9Sstevel@tonic-gate 	    }
4277c478bd9Sstevel@tonic-gate 	}
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate void
4317c478bd9Sstevel@tonic-gate cache_rlock()
4327c478bd9Sstevel@tonic-gate {
4337c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&cache_lock);
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate void
4377c478bd9Sstevel@tonic-gate cache_unlock()
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&cache_lock);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate /*
4437c478bd9Sstevel@tonic-gate  * This function is called when we get a devtree event.  Type is either add
4447c478bd9Sstevel@tonic-gate  * or delete of a drive.
4457c478bd9Sstevel@tonic-gate  *
4467c478bd9Sstevel@tonic-gate  * For delete, we need to clean up the 2nd level structures and clean up
4477c478bd9Sstevel@tonic-gate  * the pointers between the them.  We also clear the descriptor ptr.
4487c478bd9Sstevel@tonic-gate  */
4497c478bd9Sstevel@tonic-gate void
4507c478bd9Sstevel@tonic-gate cache_update(dm_event_type_t ev_type, char *devname)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate 	char *orig_name;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	cache_wlock();
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	/* update the cache */
4577c478bd9Sstevel@tonic-gate 	switch (ev_type) {
4587c478bd9Sstevel@tonic-gate 	case DM_EV_DISK_ADD:
4597c478bd9Sstevel@tonic-gate 	    rewalk_tree();
4607c478bd9Sstevel@tonic-gate 	    events_new_event(devname, DM_DRIVE, DM_EV_TADD);
4617c478bd9Sstevel@tonic-gate 	    break;
4627c478bd9Sstevel@tonic-gate 	case DM_EV_DISK_DELETE:
4637c478bd9Sstevel@tonic-gate 	    orig_name = devname;
4647c478bd9Sstevel@tonic-gate 	    devname = basename(devname);
4657c478bd9Sstevel@tonic-gate 	    del_drive_by_name(devname);
4667c478bd9Sstevel@tonic-gate 	    events_new_event(orig_name, DM_DRIVE, DM_EV_TREMOVE);
4677c478bd9Sstevel@tonic-gate 	    break;
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	cache_unlock();
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate void
4747c478bd9Sstevel@tonic-gate cache_wlock()
4757c478bd9Sstevel@tonic-gate {
4767c478bd9Sstevel@tonic-gate 	(void) rw_wrlock(&cache_lock);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate  * Clear any descriptors that point at the specified cached object.
4817c478bd9Sstevel@tonic-gate  * We must go through the whole list since there can be multiple descriptors
4827c478bd9Sstevel@tonic-gate  * referencing the same object (i.e. drive/media/slice descriptors all point
4837c478bd9Sstevel@tonic-gate  * to the same drive object).  The list is usually small (0 size) so this
4847c478bd9Sstevel@tonic-gate  * is not a big deal.
4857c478bd9Sstevel@tonic-gate  */
4867c478bd9Sstevel@tonic-gate static void
4877c478bd9Sstevel@tonic-gate clear_descriptors(void *gp)
4887c478bd9Sstevel@tonic-gate {
4897c478bd9Sstevel@tonic-gate 	descriptor_t	*descp;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	for (descp = desc_listp; descp != NULL; descp = descp->next) {
4927c478bd9Sstevel@tonic-gate 	    if (descp->p.generic == gp) {
4937c478bd9Sstevel@tonic-gate 		/* clear descriptor */
4947c478bd9Sstevel@tonic-gate 		descp->p.generic = NULL;
4957c478bd9Sstevel@tonic-gate 	    }
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate /* remove the ptr from the controller to the specified disk */
5007c478bd9Sstevel@tonic-gate static void
5017c478bd9Sstevel@tonic-gate clr_ctrl_disk_ptr(controller_t *cp, disk_t *dp)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	int i;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	for (i = 0; cp->disks[i]; i++) {
5067c478bd9Sstevel@tonic-gate 	    if (dp == cp->disks[i]) {
5077c478bd9Sstevel@tonic-gate 		int j;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 		for (j = i; cp->disks[j]; j++) {
5107c478bd9Sstevel@tonic-gate 		    cp->disks[j] = cp->disks[j + 1];
5117c478bd9Sstevel@tonic-gate 		}
5127c478bd9Sstevel@tonic-gate 		return;
5137c478bd9Sstevel@tonic-gate 	    }
5147c478bd9Sstevel@tonic-gate 	}
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate /* remove the ptr from the path to the specified disk */
5187c478bd9Sstevel@tonic-gate static void
5197c478bd9Sstevel@tonic-gate clr_path_disk_ptr(path_t *pp, disk_t *dp)
5207c478bd9Sstevel@tonic-gate {
5217c478bd9Sstevel@tonic-gate 	int i;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	for (i = 0; pp->disks[i]; i++) {
5247c478bd9Sstevel@tonic-gate 	    if (dp == pp->disks[i]) {
5257c478bd9Sstevel@tonic-gate 		int j;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 		for (j = i; pp->disks[j]; j++) {
5287c478bd9Sstevel@tonic-gate 		    pp->disks[j] = pp->disks[j + 1];
5297c478bd9Sstevel@tonic-gate 		}
5307c478bd9Sstevel@tonic-gate 		return;
5317c478bd9Sstevel@tonic-gate 	    }
5327c478bd9Sstevel@tonic-gate 	}
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate static void
5367c478bd9Sstevel@tonic-gate del_drive(disk_t *dp)
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate 	int	i;
5397c478bd9Sstevel@tonic-gate 	disk_t	*listp;
5407c478bd9Sstevel@tonic-gate 	disk_t	*prev = NULL;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	clear_descriptors(dp);
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	/* clear any ptrs from controllers to this drive */
5457c478bd9Sstevel@tonic-gate 	if (dp->controllers != NULL) {
5467c478bd9Sstevel@tonic-gate 	    for (i = 0; dp->controllers[i]; i++) {
5477c478bd9Sstevel@tonic-gate 		clr_ctrl_disk_ptr(dp->controllers[i], dp);
5487c478bd9Sstevel@tonic-gate 	    }
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	/* clear any ptrs from paths to this drive */
5527c478bd9Sstevel@tonic-gate 	if (dp->paths != NULL) {
5537c478bd9Sstevel@tonic-gate 	    for (i = 0; dp->paths[i]; i++) {
5547c478bd9Sstevel@tonic-gate 		clr_path_disk_ptr(dp->paths[i], dp);
5557c478bd9Sstevel@tonic-gate 	    }
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	/* clear drive from disk list */
5597c478bd9Sstevel@tonic-gate 	for (listp = disk_listp; listp != NULL; listp = listp->next) {
5607c478bd9Sstevel@tonic-gate 	    if (dp == listp) {
5617c478bd9Sstevel@tonic-gate 		if (prev == NULL) {
5627c478bd9Sstevel@tonic-gate 		    disk_listp = dp->next;
5637c478bd9Sstevel@tonic-gate 		} else {
5647c478bd9Sstevel@tonic-gate 		    prev->next = dp->next;
5657c478bd9Sstevel@tonic-gate 		}
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 		break;
5687c478bd9Sstevel@tonic-gate 	    }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	    if (prev == NULL) {
5717c478bd9Sstevel@tonic-gate 		prev = disk_listp;
5727c478bd9Sstevel@tonic-gate 	    } else {
5737c478bd9Sstevel@tonic-gate 		prev = prev->next;
5747c478bd9Sstevel@tonic-gate 	    }
5757c478bd9Sstevel@tonic-gate 	}
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	cache_free_disk(dp);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate /*
5817c478bd9Sstevel@tonic-gate  * Delete cached drive info when we get a devtree drive delete event.
5827c478bd9Sstevel@tonic-gate  */
5837c478bd9Sstevel@tonic-gate static void
5847c478bd9Sstevel@tonic-gate del_drive_by_name(char *name)
5857c478bd9Sstevel@tonic-gate {
5867c478bd9Sstevel@tonic-gate 	disk_t	*listp;
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	for (listp = disk_listp; listp != NULL; listp = listp->next) {
5897c478bd9Sstevel@tonic-gate 	    alias_t	*ap;
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	    for (ap = listp->aliases; ap; ap = ap->next) {
5927c478bd9Sstevel@tonic-gate 		if (libdiskmgt_str_eq(name, ap->alias)) {
5937c478bd9Sstevel@tonic-gate 		    del_drive(listp);
5947c478bd9Sstevel@tonic-gate 		    return;
5957c478bd9Sstevel@tonic-gate 		}
5967c478bd9Sstevel@tonic-gate 	    }
5977c478bd9Sstevel@tonic-gate 	}
5987c478bd9Sstevel@tonic-gate }
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate static descriptor_t *
6017c478bd9Sstevel@tonic-gate have_desc(int type, void *gp, char *name, char *secondary_name)
6027c478bd9Sstevel@tonic-gate {
6037c478bd9Sstevel@tonic-gate 	descriptor_t	*descp;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	if (name != NULL && name[0] == 0) {
6067c478bd9Sstevel@tonic-gate 	    name = NULL;
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	if (secondary_name != NULL && secondary_name[0] == 0) {
6107c478bd9Sstevel@tonic-gate 	    secondary_name = NULL;
6117c478bd9Sstevel@tonic-gate 	}
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	descp = desc_listp;
6147c478bd9Sstevel@tonic-gate 	while (descp != NULL) {
6157c478bd9Sstevel@tonic-gate 	    if (descp->type == type && descp->p.generic == gp &&
6167c478bd9Sstevel@tonic-gate 		libdiskmgt_str_eq(descp->name, name)) {
6177c478bd9Sstevel@tonic-gate 		if (type == DM_SLICE || type == DM_PARTITION ||
6187c478bd9Sstevel@tonic-gate 		    type == DM_PATH) {
6197c478bd9Sstevel@tonic-gate 		    if (libdiskmgt_str_eq(descp->secondary_name,
6207c478bd9Sstevel@tonic-gate 			secondary_name)) {
6217c478bd9Sstevel@tonic-gate 			return (descp);
6227c478bd9Sstevel@tonic-gate 		    }
6237c478bd9Sstevel@tonic-gate 		} else {
6247c478bd9Sstevel@tonic-gate 		    return (descp);
6257c478bd9Sstevel@tonic-gate 		}
6267c478bd9Sstevel@tonic-gate 	    }
6277c478bd9Sstevel@tonic-gate 	    descp = descp->next;
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	return (NULL);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate static int
6347c478bd9Sstevel@tonic-gate initialize()
6357c478bd9Sstevel@tonic-gate {
6367c478bd9Sstevel@tonic-gate 	struct search_args	args;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	if (cache_loaded) {
6397c478bd9Sstevel@tonic-gate 		return (0);
6407c478bd9Sstevel@tonic-gate 	}
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	libdiskmgt_init_debug();
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	findevs(&args);
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	if (args.dev_walk_status != 0) {
6477c478bd9Sstevel@tonic-gate 		return (args.dev_walk_status);
6487c478bd9Sstevel@tonic-gate 	}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	disk_listp = args.disk_listp;
6517c478bd9Sstevel@tonic-gate 	controller_listp = args.controller_listp;
6527c478bd9Sstevel@tonic-gate 	bus_listp = args.bus_listp;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	cache_loaded = 1;
6557c478bd9Sstevel@tonic-gate 
6563e1bd7a2Ssjelinek 	/*
6573e1bd7a2Ssjelinek 	 * Only start the event thread if we are not doing an install
6583e1bd7a2Ssjelinek 	 */
6593e1bd7a2Ssjelinek 	if (getenv("_LIBDISKMGT_INSTALL") == NULL) {
660*82d71480Ssjelinek 		if (events_start_event_watcher() != 0) {
661*82d71480Ssjelinek 			/*
662*82d71480Ssjelinek 			 * Log a message about the failure to start
663*82d71480Ssjelinek 			 * sysevents and continue on.
664*82d71480Ssjelinek 			 */
665*82d71480Ssjelinek 			syslog(LOG_WARNING, dgettext(TEXT_DOMAIN,
666*82d71480Ssjelinek 			    "libdiskmgt: sysevent thread for cache "
667*82d71480Ssjelinek 			    "events failed to start\n"));
6687c478bd9Sstevel@tonic-gate 		}
6693e1bd7a2Ssjelinek 	}
6707c478bd9Sstevel@tonic-gate 	return (0);
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate static int
6747c478bd9Sstevel@tonic-gate make_descriptors(int type)
6757c478bd9Sstevel@tonic-gate {
6767c478bd9Sstevel@tonic-gate 	int	error;
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	if ((error = initialize()) != 0) {
6797c478bd9Sstevel@tonic-gate 	    return (error);
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	switch (type) {
6837c478bd9Sstevel@tonic-gate 	case DM_DRIVE:
6847c478bd9Sstevel@tonic-gate 	    error = drive_make_descriptors();
6857c478bd9Sstevel@tonic-gate 	    break;
6867c478bd9Sstevel@tonic-gate 	case DM_BUS:
6877c478bd9Sstevel@tonic-gate 	    error = bus_make_descriptors();
6887c478bd9Sstevel@tonic-gate 	    break;
6897c478bd9Sstevel@tonic-gate 	case DM_CONTROLLER:
6907c478bd9Sstevel@tonic-gate 	    error = controller_make_descriptors();
6917c478bd9Sstevel@tonic-gate 	    break;
6927c478bd9Sstevel@tonic-gate 	case DM_PATH:
6937c478bd9Sstevel@tonic-gate 	    error = path_make_descriptors();
6947c478bd9Sstevel@tonic-gate 	    break;
6957c478bd9Sstevel@tonic-gate 	case DM_ALIAS:
6967c478bd9Sstevel@tonic-gate 	    error = alias_make_descriptors();
6977c478bd9Sstevel@tonic-gate 	    break;
6987c478bd9Sstevel@tonic-gate 	case DM_MEDIA:
6997c478bd9Sstevel@tonic-gate 	    error = media_make_descriptors();
7007c478bd9Sstevel@tonic-gate 	    break;
7017c478bd9Sstevel@tonic-gate 	case DM_PARTITION:
7027c478bd9Sstevel@tonic-gate 	    error = partition_make_descriptors();
7037c478bd9Sstevel@tonic-gate 	    break;
7047c478bd9Sstevel@tonic-gate 	case DM_SLICE:
7057c478bd9Sstevel@tonic-gate 	    error = slice_make_descriptors();
7067c478bd9Sstevel@tonic-gate 	    break;
7077c478bd9Sstevel@tonic-gate 	}
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	return (error);
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate static int
7137c478bd9Sstevel@tonic-gate match_alias(alias_t *ap, alias_t *listp)
7147c478bd9Sstevel@tonic-gate {
7157c478bd9Sstevel@tonic-gate 	if (ap->alias == NULL) {
7167c478bd9Sstevel@tonic-gate 	    return (0);
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	while (listp != NULL) {
7207c478bd9Sstevel@tonic-gate 	    if (libdiskmgt_str_eq(ap->alias, listp->alias)) {
7217c478bd9Sstevel@tonic-gate 		return (1);
7227c478bd9Sstevel@tonic-gate 	    }
7237c478bd9Sstevel@tonic-gate 	    listp = listp->next;
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	return (0);
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate static int
7307c478bd9Sstevel@tonic-gate match_aliases(disk_t *d1p, disk_t *d2p)
7317c478bd9Sstevel@tonic-gate {
7327c478bd9Sstevel@tonic-gate 	alias_t *ap;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	if (d1p->aliases == NULL || d2p->aliases == NULL) {
7357c478bd9Sstevel@tonic-gate 	    return (0);
7367c478bd9Sstevel@tonic-gate 	}
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	ap = d1p->aliases;
7397c478bd9Sstevel@tonic-gate 	while (ap != NULL) {
7407c478bd9Sstevel@tonic-gate 	    if (match_alias(ap, d2p->aliases)) {
7417c478bd9Sstevel@tonic-gate 		return (1);
7427c478bd9Sstevel@tonic-gate 	    }
7437c478bd9Sstevel@tonic-gate 	    ap = ap->next;
7447c478bd9Sstevel@tonic-gate 	}
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	return (0);
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate static int
7507c478bd9Sstevel@tonic-gate match_disk(disk_t *oldp, disk_t *newp)
7517c478bd9Sstevel@tonic-gate {
7527c478bd9Sstevel@tonic-gate 	if (oldp->devid != NULL) {
7537c478bd9Sstevel@tonic-gate 	    if (newp->devid != NULL &&
7547c478bd9Sstevel@tonic-gate 		devid_compare(oldp->devid, newp->devid) == 0) {
7557c478bd9Sstevel@tonic-gate 		return (1);
7567c478bd9Sstevel@tonic-gate 	    }
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	} else {
7597c478bd9Sstevel@tonic-gate 	    /* oldp device id is null */
7607c478bd9Sstevel@tonic-gate 	    if (newp->devid == NULL) {
7617c478bd9Sstevel@tonic-gate 		/* both disks have no device id, check aliases */
7627c478bd9Sstevel@tonic-gate 		if (match_aliases(oldp, newp)) {
7637c478bd9Sstevel@tonic-gate 		    return (1);
7647c478bd9Sstevel@tonic-gate 		}
7657c478bd9Sstevel@tonic-gate 	    }
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	return (0);
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate static descriptor_t *
7727c478bd9Sstevel@tonic-gate new_descriptor(dm_desc_type_t type, void *op, char *name, char *secondary_name)
7737c478bd9Sstevel@tonic-gate {
7747c478bd9Sstevel@tonic-gate 	descriptor_t	*d;
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	if (name != NULL && name[0] == 0) {
7777c478bd9Sstevel@tonic-gate 	    name = NULL;
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	if (secondary_name != NULL && secondary_name[0] == 0) {
7817c478bd9Sstevel@tonic-gate 	    secondary_name = NULL;
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	d = (descriptor_t *)malloc(sizeof (descriptor_t));
7857c478bd9Sstevel@tonic-gate 	if (d == NULL) {
7867c478bd9Sstevel@tonic-gate 	    return (NULL);
7877c478bd9Sstevel@tonic-gate 	}
7887c478bd9Sstevel@tonic-gate 	d->type = type;
7897c478bd9Sstevel@tonic-gate 	switch (type) {
7907c478bd9Sstevel@tonic-gate 	case DM_CONTROLLER:
7917c478bd9Sstevel@tonic-gate 	    d->p.controller = op;
7927c478bd9Sstevel@tonic-gate 	    break;
7937c478bd9Sstevel@tonic-gate 	case DM_BUS:
7947c478bd9Sstevel@tonic-gate 	    d->p.bus = op;
7957c478bd9Sstevel@tonic-gate 	    break;
7967c478bd9Sstevel@tonic-gate 	default:
7977c478bd9Sstevel@tonic-gate 	    d->p.disk = op;
7987c478bd9Sstevel@tonic-gate 	    break;
7997c478bd9Sstevel@tonic-gate 	}
8007c478bd9Sstevel@tonic-gate 	if (name != NULL) {
8017c478bd9Sstevel@tonic-gate 	    d->name = strdup(name);
8027c478bd9Sstevel@tonic-gate 	    if (d->name == NULL) {
8037c478bd9Sstevel@tonic-gate 		free(d);
8047c478bd9Sstevel@tonic-gate 		return (NULL);
8057c478bd9Sstevel@tonic-gate 	    }
8067c478bd9Sstevel@tonic-gate 	} else {
8077c478bd9Sstevel@tonic-gate 	    d->name = NULL;
8087c478bd9Sstevel@tonic-gate 	}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	if (type == DM_SLICE || type == DM_PARTITION) {
8117c478bd9Sstevel@tonic-gate 	    if (secondary_name != NULL) {
8127c478bd9Sstevel@tonic-gate 		d->secondary_name = strdup(secondary_name);
8137c478bd9Sstevel@tonic-gate 		if (d->secondary_name == NULL) {
8147c478bd9Sstevel@tonic-gate 		    free(d->name);
8157c478bd9Sstevel@tonic-gate 		    free(d);
8167c478bd9Sstevel@tonic-gate 		    return (NULL);
8177c478bd9Sstevel@tonic-gate 		}
8187c478bd9Sstevel@tonic-gate 	    } else {
8197c478bd9Sstevel@tonic-gate 		d->secondary_name = NULL;
8207c478bd9Sstevel@tonic-gate 	    }
8217c478bd9Sstevel@tonic-gate 	} else {
8227c478bd9Sstevel@tonic-gate 	    d->secondary_name = NULL;
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	d->refcnt = 0;
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	/* add this descriptor to the head of the list */
8287c478bd9Sstevel@tonic-gate 	if (desc_listp != NULL) {
8297c478bd9Sstevel@tonic-gate 	    desc_listp->prev = d;
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 	d->prev = NULL;
8327c478bd9Sstevel@tonic-gate 	d->next = desc_listp;
8337c478bd9Sstevel@tonic-gate 	desc_listp = d;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	return (d);
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate static void
8397c478bd9Sstevel@tonic-gate rewalk_tree()
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate 	struct search_args	args;
8427c478bd9Sstevel@tonic-gate 	disk_t			*free_disklistp;
8437c478bd9Sstevel@tonic-gate 	controller_t		*free_controllerlistp;
8447c478bd9Sstevel@tonic-gate 	bus_t			*free_buslistp;
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	findevs(&args);
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	if (args.dev_walk_status == 0) {
8497c478bd9Sstevel@tonic-gate 	    descriptor_t	*descp;
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	    /* walk the existing descriptors and update the ptrs */
8527c478bd9Sstevel@tonic-gate 	    descp = desc_listp;
8537c478bd9Sstevel@tonic-gate 	    while (descp != NULL) {
8547c478bd9Sstevel@tonic-gate 		update_desc(descp, args.disk_listp, args.controller_listp,
8557c478bd9Sstevel@tonic-gate 		    args.bus_listp);
8567c478bd9Sstevel@tonic-gate 		descp = descp->next;
8577c478bd9Sstevel@tonic-gate 	    }
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	    /* update the cached object ptrs */
8607c478bd9Sstevel@tonic-gate 	    free_disklistp = disk_listp;
8617c478bd9Sstevel@tonic-gate 	    free_controllerlistp = controller_listp;
8627c478bd9Sstevel@tonic-gate 	    free_buslistp = bus_listp;
8637c478bd9Sstevel@tonic-gate 	    disk_listp = args.disk_listp;
8647c478bd9Sstevel@tonic-gate 	    controller_listp = args.controller_listp;
8657c478bd9Sstevel@tonic-gate 	    bus_listp = args.bus_listp;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	} else {
8687c478bd9Sstevel@tonic-gate 	    free_disklistp = args.disk_listp;
8697c478bd9Sstevel@tonic-gate 	    free_controllerlistp = args.controller_listp;
8707c478bd9Sstevel@tonic-gate 	    free_buslistp = args.bus_listp;
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	/*
8747c478bd9Sstevel@tonic-gate 	 * Free the memory from either the old cached objects or the failed
8757c478bd9Sstevel@tonic-gate 	 * update objects.
8767c478bd9Sstevel@tonic-gate 	 */
8777c478bd9Sstevel@tonic-gate 	while (free_disklistp != NULL) {
8787c478bd9Sstevel@tonic-gate 	    disk_t *nextp;
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	    nextp = free_disklistp->next;
8817c478bd9Sstevel@tonic-gate 	    cache_free_disk(free_disklistp);
8827c478bd9Sstevel@tonic-gate 	    free_disklistp = nextp;
8837c478bd9Sstevel@tonic-gate 	}
8847c478bd9Sstevel@tonic-gate 	while (free_controllerlistp != NULL) {
8857c478bd9Sstevel@tonic-gate 	    controller_t *nextp;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	    nextp = free_controllerlistp->next;
8887c478bd9Sstevel@tonic-gate 	    cache_free_controller(free_controllerlistp);
8897c478bd9Sstevel@tonic-gate 	    free_controllerlistp = nextp;
8907c478bd9Sstevel@tonic-gate 	}
8917c478bd9Sstevel@tonic-gate 	while (free_buslistp != NULL) {
8927c478bd9Sstevel@tonic-gate 	    bus_t *nextp;
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	    nextp = free_buslistp->next;
8957c478bd9Sstevel@tonic-gate 	    cache_free_bus(free_buslistp);
8967c478bd9Sstevel@tonic-gate 	    free_buslistp = nextp;
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate }
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate /*
9017c478bd9Sstevel@tonic-gate  * Walk the new set of cached objects and update the descriptor ptr to point
9027c478bd9Sstevel@tonic-gate  * to the correct new object.  If there is no object any more, set the desc
9037c478bd9Sstevel@tonic-gate  * ptr to null.
9047c478bd9Sstevel@tonic-gate  */
9057c478bd9Sstevel@tonic-gate static void
9067c478bd9Sstevel@tonic-gate update_desc(descriptor_t *descp, disk_t *newdisksp, controller_t *newctrlp,
9077c478bd9Sstevel@tonic-gate 	bus_t *newbusp)
9087c478bd9Sstevel@tonic-gate {
9097c478bd9Sstevel@tonic-gate 	/* if the descriptor is already dead, we're done */
9107c478bd9Sstevel@tonic-gate 	if (descp->p.generic == NULL) {
9117c478bd9Sstevel@tonic-gate 	    return;
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	/*
9157c478bd9Sstevel@tonic-gate 	 * All descriptors use a disk ptr except for controller descriptors
9167c478bd9Sstevel@tonic-gate 	 * and path descriptors.
9177c478bd9Sstevel@tonic-gate 	 */
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	switch (descp->type) {
9207c478bd9Sstevel@tonic-gate 	case DM_BUS:
9217c478bd9Sstevel@tonic-gate 	    update_desc_busp(descp, newbusp);
9227c478bd9Sstevel@tonic-gate 	    break;
9237c478bd9Sstevel@tonic-gate 	case DM_CONTROLLER:
9247c478bd9Sstevel@tonic-gate 	    update_desc_ctrlp(descp, newctrlp);
9257c478bd9Sstevel@tonic-gate 	    break;
9267c478bd9Sstevel@tonic-gate 	case DM_PATH:
9277c478bd9Sstevel@tonic-gate 	    update_desc_pathp(descp, newctrlp);
9287c478bd9Sstevel@tonic-gate 	    break;
9297c478bd9Sstevel@tonic-gate 	default:
9307c478bd9Sstevel@tonic-gate 	    update_desc_diskp(descp, newdisksp);
9317c478bd9Sstevel@tonic-gate 	    break;
9327c478bd9Sstevel@tonic-gate 	}
9337c478bd9Sstevel@tonic-gate }
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate static void
9367c478bd9Sstevel@tonic-gate update_desc_busp(descriptor_t *descp, bus_t *busp)
9377c478bd9Sstevel@tonic-gate {
9387c478bd9Sstevel@tonic-gate 	/* walk the new objects and find the correct bus */
9397c478bd9Sstevel@tonic-gate 	for (; busp; busp = busp->next) {
9407c478bd9Sstevel@tonic-gate 	    if (libdiskmgt_str_eq(descp->p.bus->name, busp->name)) {
9417c478bd9Sstevel@tonic-gate 		descp->p.bus = busp;
9427c478bd9Sstevel@tonic-gate 		return;
9437c478bd9Sstevel@tonic-gate 	    }
9447c478bd9Sstevel@tonic-gate 	}
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	/* we did not find the controller any more, clear the ptr in the desc */
9477c478bd9Sstevel@tonic-gate 	descp->p.bus = NULL;
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate static void
9517c478bd9Sstevel@tonic-gate update_desc_ctrlp(descriptor_t *descp, controller_t *newctrlp)
9527c478bd9Sstevel@tonic-gate {
9537c478bd9Sstevel@tonic-gate 	/* walk the new objects and find the correct controller */
9547c478bd9Sstevel@tonic-gate 	for (; newctrlp; newctrlp = newctrlp->next) {
9557c478bd9Sstevel@tonic-gate 	    if (libdiskmgt_str_eq(descp->p.controller->name, newctrlp->name)) {
9567c478bd9Sstevel@tonic-gate 		descp->p.controller = newctrlp;
9577c478bd9Sstevel@tonic-gate 		return;
9587c478bd9Sstevel@tonic-gate 	    }
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	/* we did not find the controller any more, clear the ptr in the desc */
9627c478bd9Sstevel@tonic-gate 	descp->p.controller = NULL;
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate static void
9667c478bd9Sstevel@tonic-gate update_desc_diskp(descriptor_t *descp, disk_t *newdisksp)
9677c478bd9Sstevel@tonic-gate {
9687c478bd9Sstevel@tonic-gate 	/* walk the new objects and find the correct disk */
9697c478bd9Sstevel@tonic-gate 	for (; newdisksp; newdisksp = newdisksp->next) {
9707c478bd9Sstevel@tonic-gate 	    if (match_disk(descp->p.disk, newdisksp)) {
9717c478bd9Sstevel@tonic-gate 		descp->p.disk = newdisksp;
9727c478bd9Sstevel@tonic-gate 		return;
9737c478bd9Sstevel@tonic-gate 	    }
9747c478bd9Sstevel@tonic-gate 	}
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	/* we did not find the disk any more, clear the ptr in the descriptor */
9777c478bd9Sstevel@tonic-gate 	descp->p.disk = NULL;
9787c478bd9Sstevel@tonic-gate }
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate static void
9817c478bd9Sstevel@tonic-gate update_desc_pathp(descriptor_t *descp, controller_t *newctrlp)
9827c478bd9Sstevel@tonic-gate {
9837c478bd9Sstevel@tonic-gate 	/* walk the new objects and find the correct path */
9847c478bd9Sstevel@tonic-gate 	for (; newctrlp; newctrlp = newctrlp->next) {
9857c478bd9Sstevel@tonic-gate 	    path_t	**pp;
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	    pp = newctrlp->paths;
9887c478bd9Sstevel@tonic-gate 	    if (pp != NULL) {
9897c478bd9Sstevel@tonic-gate 		int i;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 		for (i = 0; pp[i]; i++) {
9927c478bd9Sstevel@tonic-gate 		    if (libdiskmgt_str_eq(descp->p.path->name, pp[i]->name)) {
9937c478bd9Sstevel@tonic-gate 			descp->p.path = pp[i];
9947c478bd9Sstevel@tonic-gate 			return;
9957c478bd9Sstevel@tonic-gate 		    }
9967c478bd9Sstevel@tonic-gate 		}
9977c478bd9Sstevel@tonic-gate 	    }
9987c478bd9Sstevel@tonic-gate 	}
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	/* we did not find the path any more, clear the ptr in the desc */
10017c478bd9Sstevel@tonic-gate 	descp->p.path = NULL;
10027c478bd9Sstevel@tonic-gate }
1003