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