xref: /titanic_51/usr/src/cmd/fs.d/preenlib.c (revision 081901271249c8ffce8241a6035a9f13fb1c0aa9)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
237c478bd9Sstevel@tonic-gate /*
24*08190127Sdh145677  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25*08190127Sdh145677  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * common routines for parallelization (used by both fsck and quotacheck)
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <fcntl.h>
337c478bd9Sstevel@tonic-gate #include <dlfcn.h>
347c478bd9Sstevel@tonic-gate #include <macros.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/wait.h>
377c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
387c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * data structures for parallelization
427c478bd9Sstevel@tonic-gate  */
43*08190127Sdh145677 struct driver {
447c478bd9Sstevel@tonic-gate 	char 	*name;			/* driver name (from DKIOCINFO) */
457c478bd9Sstevel@tonic-gate 	uint_t	mapsize;		/* size of `busymap' */
467c478bd9Sstevel@tonic-gate 	uint_t	*busymap;		/* bitmask of active units */
477c478bd9Sstevel@tonic-gate 	int	(*choosefunc)();	/* driver specific chooser */
487c478bd9Sstevel@tonic-gate 	void	*data;			/* driver private data */
497c478bd9Sstevel@tonic-gate };
507c478bd9Sstevel@tonic-gate 
51*08190127Sdh145677 struct onedev {
527c478bd9Sstevel@tonic-gate 	int	drvid;			/* index in driver array */
537c478bd9Sstevel@tonic-gate 	uint_t	mapsize;		/* size of `unitmap' */
547c478bd9Sstevel@tonic-gate 	uint_t	*unitmap;		/* unit #'s (from DKIOCINFO) */
557c478bd9Sstevel@tonic-gate 	struct onedev *nxtdev;
567c478bd9Sstevel@tonic-gate };
577c478bd9Sstevel@tonic-gate 
58*08190127Sdh145677 struct rawdev {
597c478bd9Sstevel@tonic-gate 	char	*devname;		/* name passed to preen_addev */
607c478bd9Sstevel@tonic-gate 	struct	onedev *alldevs;	/* info about each component device */
617c478bd9Sstevel@tonic-gate 	struct rawdev *nxtrd;		/* next entry in list */
627c478bd9Sstevel@tonic-gate };
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static int debug = 0;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * defines used in building shared object names
687c478bd9Sstevel@tonic-gate  */
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /* the directory where we find shared objects */
717c478bd9Sstevel@tonic-gate #define	OBJECT_DIRECTORY	"/usr/lib/drv"
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /* a shared object name is OBJECT_PREFIX || driver_name */
747c478bd9Sstevel@tonic-gate #define	OBJECT_PREFIX		"preen_"
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /* the version of the driver interface we support */
777c478bd9Sstevel@tonic-gate #define	OBJECT_VERSION		1
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /* the "build" entry point for a driver specific object is named this */
807c478bd9Sstevel@tonic-gate #define	BUILD_ENTRY		preen_build_devs
817c478bd9Sstevel@tonic-gate #define	BUILD_NAME		"preen_build_devs"
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate #define	DRIVER_ALLOC	10
847c478bd9Sstevel@tonic-gate static int ndrivers, ndalloc;
857c478bd9Sstevel@tonic-gate static struct driver *dlist;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate static struct rawdev *unchecked, *active, *get_runnable();
887c478bd9Sstevel@tonic-gate static struct onedev *alloc_dev();
897c478bd9Sstevel@tonic-gate static int chooseone();
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate #define	WORDSIZE	(NBBY * sizeof (uint_t))
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate void 	preen_addunit(void *, char *, int (*)(), void *, uint_t);
947c478bd9Sstevel@tonic-gate int 	preen_subdev(char *, struct dk_cinfo *, void *);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate static int 	alloc_driver(char *, int (*)(), void *);
977c478bd9Sstevel@tonic-gate static void 	addunit(struct onedev *, uint_t);
987c478bd9Sstevel@tonic-gate static void	makebusy(struct onedev *);
997c478bd9Sstevel@tonic-gate static void	notbusy(struct rawdev *);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * add the given device to the list of devices to be checked
1037c478bd9Sstevel@tonic-gate  */
104*08190127Sdh145677 int
1057c478bd9Sstevel@tonic-gate preen_addev(char *devnm)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate 	struct rawdev *rdp;
1087c478bd9Sstevel@tonic-gate 	int fd;
1097c478bd9Sstevel@tonic-gate 	struct dk_cinfo dki;
1107c478bd9Sstevel@tonic-gate 	extern char *strdup();
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	if ((fd = open64(devnm, O_RDONLY)) == -1) {
1137c478bd9Sstevel@tonic-gate 		perror(devnm);
1147c478bd9Sstevel@tonic-gate 		return (-1);
1157c478bd9Sstevel@tonic-gate 	}
1167c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DKIOCINFO, &dki) == -1) {
1177c478bd9Sstevel@tonic-gate 		perror("DKIOCINFO");
1187c478bd9Sstevel@tonic-gate 		fprintf(stderr, "device: `%s'\n", devnm);
1197c478bd9Sstevel@tonic-gate 		(void) close(fd);
1207c478bd9Sstevel@tonic-gate 		return (-1);
1217c478bd9Sstevel@tonic-gate 	}
1227c478bd9Sstevel@tonic-gate 	(void) close(fd);
1237c478bd9Sstevel@tonic-gate 	if ((rdp = (struct rawdev *)malloc(sizeof (struct rawdev))) == NULL) {
1247c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "out of memory in preenlib\n");
1257c478bd9Sstevel@tonic-gate 		return (-1);
1267c478bd9Sstevel@tonic-gate 	}
1277c478bd9Sstevel@tonic-gate 	if ((rdp->devname = strdup(devnm)) == NULL) {
1287c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "out of memory in preenlib\n");
1297c478bd9Sstevel@tonic-gate 		return (-1);
1307c478bd9Sstevel@tonic-gate 	}
1317c478bd9Sstevel@tonic-gate 	rdp->alldevs = NULL;
1327c478bd9Sstevel@tonic-gate 	rdp->nxtrd = NULL;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	if (preen_subdev(devnm, &dki, (void *)rdp)) {
1357c478bd9Sstevel@tonic-gate 		preen_addunit(rdp, dki.dki_dname, NULL, NULL, dki.dki_unit);
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	rdp->nxtrd = unchecked;
1397c478bd9Sstevel@tonic-gate 	unchecked = rdp;
1407c478bd9Sstevel@tonic-gate 	return (0);
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate 
143*08190127Sdh145677 int
1447c478bd9Sstevel@tonic-gate preen_subdev(char *name, struct dk_cinfo *dkiop, void *dp)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate 	char modname[255];
1477c478bd9Sstevel@tonic-gate 	void *dlhandle;
1487c478bd9Sstevel@tonic-gate 	int (*fptr)();
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	(void) sprintf(modname, "%s/%s%s.so.%d",
1517c478bd9Sstevel@tonic-gate 	    OBJECT_DIRECTORY, OBJECT_PREFIX, dkiop->dki_dname, OBJECT_VERSION);
1527c478bd9Sstevel@tonic-gate 	dlhandle = dlopen(modname, RTLD_LAZY);
1537c478bd9Sstevel@tonic-gate 	if (dlhandle == NULL) {
1547c478bd9Sstevel@tonic-gate 		if (debug)
1557c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "preen_subdev: %s\n", dlerror());
1567c478bd9Sstevel@tonic-gate 		return (1);
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 	fptr = (int (*)())dlsym(dlhandle, BUILD_NAME);
1597c478bd9Sstevel@tonic-gate 	if (fptr == NULL) {
1607c478bd9Sstevel@tonic-gate 		if (debug)
1617c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "preen_subdev: %s\n", dlerror());
1627c478bd9Sstevel@tonic-gate 		return (1);
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 	(*fptr)(name, dkiop, dp);
1657c478bd9Sstevel@tonic-gate 	return (0);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate  * select a device from the "unchecked" list, and add it to the
1707c478bd9Sstevel@tonic-gate  * active list.
1717c478bd9Sstevel@tonic-gate  */
172*08190127Sdh145677 int
1737c478bd9Sstevel@tonic-gate preen_getdev(char *devnm)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate 	struct rawdev *rdp;
176*08190127Sdh145677 	struct onedev *dp;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (unchecked == NULL)
1797c478bd9Sstevel@tonic-gate 		return (0);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	rdp = get_runnable(&unchecked);
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	if (rdp) {
1847c478bd9Sstevel@tonic-gate 		for (dp = rdp->alldevs; dp; dp = dp->nxtdev) {
1857c478bd9Sstevel@tonic-gate 			makebusy(dp);
1867c478bd9Sstevel@tonic-gate 		}
1877c478bd9Sstevel@tonic-gate 		rdp->nxtrd = active;
1887c478bd9Sstevel@tonic-gate 		active = rdp;
1897c478bd9Sstevel@tonic-gate 		(void) strcpy(devnm, rdp->devname);
1907c478bd9Sstevel@tonic-gate 		return (1);
1917c478bd9Sstevel@tonic-gate 	} else {
1927c478bd9Sstevel@tonic-gate 		return (2);
1937c478bd9Sstevel@tonic-gate 	}
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
196*08190127Sdh145677 int
1977c478bd9Sstevel@tonic-gate preen_releasedev(char *name)
1987c478bd9Sstevel@tonic-gate {
199*08190127Sdh145677 	struct rawdev *dp, *ldp;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	for (ldp = NULL, dp = active; dp != NULL; ldp = dp, dp = dp->nxtrd) {
2027c478bd9Sstevel@tonic-gate 		if (strcmp(dp->devname, name) == 0)
2037c478bd9Sstevel@tonic-gate 			break;
2047c478bd9Sstevel@tonic-gate 	}
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if (dp == NULL)
2077c478bd9Sstevel@tonic-gate 		return (-1);
2087c478bd9Sstevel@tonic-gate 	if (ldp != NULL) {
2097c478bd9Sstevel@tonic-gate 		ldp->nxtrd = dp->nxtrd;
2107c478bd9Sstevel@tonic-gate 	} else {
2117c478bd9Sstevel@tonic-gate 		active = dp->nxtrd;
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	notbusy(dp);
2157c478bd9Sstevel@tonic-gate 	/*
2167c478bd9Sstevel@tonic-gate 	 * free(dp->devname);
2177c478bd9Sstevel@tonic-gate 	 * free(dp);
2187c478bd9Sstevel@tonic-gate 	 */
2197c478bd9Sstevel@tonic-gate 	return (0);
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate static
2237c478bd9Sstevel@tonic-gate struct rawdev *
2247c478bd9Sstevel@tonic-gate get_runnable(struct rawdev **devlist)
2257c478bd9Sstevel@tonic-gate {
226*08190127Sdh145677 	struct rawdev *last, *rdp;
227*08190127Sdh145677 	struct onedev *devp;
228*08190127Sdh145677 	struct driver *drvp;
2297c478bd9Sstevel@tonic-gate 	int rc = 1;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	for (last = NULL, rdp = *devlist; rdp; last = rdp, rdp = rdp->nxtrd) {
2327c478bd9Sstevel@tonic-gate 		for (devp = rdp->alldevs; devp != NULL; devp = devp->nxtdev) {
2337c478bd9Sstevel@tonic-gate 			drvp = &dlist[devp->drvid];
2347c478bd9Sstevel@tonic-gate 			rc = (*drvp->choosefunc)(devp->mapsize, devp->unitmap,
2357c478bd9Sstevel@tonic-gate 			    drvp->mapsize, drvp->busymap);
2367c478bd9Sstevel@tonic-gate 			if (rc != 0)
2377c478bd9Sstevel@tonic-gate 				break;
2387c478bd9Sstevel@tonic-gate 		}
2397c478bd9Sstevel@tonic-gate 		if (rc == 0)
2407c478bd9Sstevel@tonic-gate 			break;
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	/*
2447c478bd9Sstevel@tonic-gate 	 * remove from list...
2457c478bd9Sstevel@tonic-gate 	 */
2467c478bd9Sstevel@tonic-gate 	if (rdp) {
2477c478bd9Sstevel@tonic-gate 		if (last) {
2487c478bd9Sstevel@tonic-gate 			last->nxtrd = rdp->nxtrd;
2497c478bd9Sstevel@tonic-gate 		} else {
2507c478bd9Sstevel@tonic-gate 			*devlist = rdp->nxtrd;
2517c478bd9Sstevel@tonic-gate 		}
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	return (rdp);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * add the given driver/unit reference to the `rawdev' structure identified
2597c478bd9Sstevel@tonic-gate  * by `cookie'
2607c478bd9Sstevel@tonic-gate  * If a new `driver' structure needs to be created, associate the given
2617c478bd9Sstevel@tonic-gate  * choosing function and driver private data with it.
2627c478bd9Sstevel@tonic-gate  */
2637c478bd9Sstevel@tonic-gate void
2647c478bd9Sstevel@tonic-gate preen_addunit(
2657c478bd9Sstevel@tonic-gate 	void    *cookie,
2667c478bd9Sstevel@tonic-gate 	char	*dname,		/* driver name */
2677c478bd9Sstevel@tonic-gate 	int	(*cf)(),	/* candidate choosing function */
2687c478bd9Sstevel@tonic-gate 	void	*datap,		/* driver private data */
2697c478bd9Sstevel@tonic-gate 	uint_t	unit)		/* unit number */
2707c478bd9Sstevel@tonic-gate {
271*08190127Sdh145677 	int drvid;
272*08190127Sdh145677 	struct driver *dp;
273*08190127Sdh145677 	struct onedev *devp;
2747c478bd9Sstevel@tonic-gate 	struct rawdev *rdp = (struct rawdev *)cookie;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	/*
2777c478bd9Sstevel@tonic-gate 	 * locate the driver struct
2787c478bd9Sstevel@tonic-gate 	 */
2797c478bd9Sstevel@tonic-gate 	dp = NULL;
2807c478bd9Sstevel@tonic-gate 	for (drvid = 0; drvid < ndrivers; drvid++) {
2817c478bd9Sstevel@tonic-gate 		if (strcmp(dlist[drvid].name, dname) == 0) {
2827c478bd9Sstevel@tonic-gate 			dp = &dlist[drvid];
2837c478bd9Sstevel@tonic-gate 			break;
2847c478bd9Sstevel@tonic-gate 		}
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	if (dp == NULL) {
2887c478bd9Sstevel@tonic-gate 		/*
2897c478bd9Sstevel@tonic-gate 		 * driver struct doesn't exist yet -- create one
2907c478bd9Sstevel@tonic-gate 		 */
2917c478bd9Sstevel@tonic-gate 		if (cf == NULL)
2927c478bd9Sstevel@tonic-gate 			cf = chooseone;
2937c478bd9Sstevel@tonic-gate 		drvid = alloc_driver(dname, cf, datap);
2947c478bd9Sstevel@tonic-gate 		dp = &dlist[drvid];
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	for (devp = rdp->alldevs; devp != NULL; devp = devp->nxtdev) {
2987c478bd9Sstevel@tonic-gate 		/*
2997c478bd9Sstevel@tonic-gate 		 * see if this device already references the given driver
3007c478bd9Sstevel@tonic-gate 		 */
3017c478bd9Sstevel@tonic-gate 		if (devp->drvid == drvid)
3027c478bd9Sstevel@tonic-gate 			break;
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	if (devp == NULL) {
3067c478bd9Sstevel@tonic-gate 		/*
3077c478bd9Sstevel@tonic-gate 		 * allocate a new `struct onedev' and chain it in
3087c478bd9Sstevel@tonic-gate 		 * rdp->alldevs...
3097c478bd9Sstevel@tonic-gate 		 */
3107c478bd9Sstevel@tonic-gate 		devp = alloc_dev(drvid);
3117c478bd9Sstevel@tonic-gate 		devp->nxtdev = rdp->alldevs;
3127c478bd9Sstevel@tonic-gate 		rdp->alldevs = devp;
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/*
3167c478bd9Sstevel@tonic-gate 	 * add `unit' to the unitmap in devp
3177c478bd9Sstevel@tonic-gate 	 */
3187c478bd9Sstevel@tonic-gate 	addunit(devp, unit);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate static
3227c478bd9Sstevel@tonic-gate int
3237c478bd9Sstevel@tonic-gate alloc_driver(char *name, int (*cf)(), void *datap)
3247c478bd9Sstevel@tonic-gate {
325*08190127Sdh145677 	struct driver *dp;
3267c478bd9Sstevel@tonic-gate 	extern char *strdup();
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	if (ndrivers == ndalloc) {
3297c478bd9Sstevel@tonic-gate 		dlist = ndalloc ?
3307c478bd9Sstevel@tonic-gate 		    (struct driver *)
3317c478bd9Sstevel@tonic-gate 		    realloc(dlist, sizeof (struct driver) * DRIVER_ALLOC) :
3327c478bd9Sstevel@tonic-gate 		    (struct driver *)
3337c478bd9Sstevel@tonic-gate 		    malloc(sizeof (struct driver) * DRIVER_ALLOC);
3347c478bd9Sstevel@tonic-gate 		if (dlist == NULL) {
3357c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "out of memory in preenlib\n");
3367c478bd9Sstevel@tonic-gate 			exit(1);
3377c478bd9Sstevel@tonic-gate 		}
3387c478bd9Sstevel@tonic-gate 		ndalloc += DRIVER_ALLOC;
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	dp = &dlist[ndrivers];
3427c478bd9Sstevel@tonic-gate 	dp->name = strdup(name);
3437c478bd9Sstevel@tonic-gate 	if (dp->name == NULL) {
3447c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "out of memory in preenlib\n");
3457c478bd9Sstevel@tonic-gate 		exit(1);
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 	dp->choosefunc = cf;
3487c478bd9Sstevel@tonic-gate 	dp->data = datap;
3497c478bd9Sstevel@tonic-gate 	dp->mapsize = 0;
3507c478bd9Sstevel@tonic-gate 	dp->busymap = NULL;
3517c478bd9Sstevel@tonic-gate 	return (ndrivers++);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate static
3557c478bd9Sstevel@tonic-gate struct onedev *
3567c478bd9Sstevel@tonic-gate alloc_dev(int did)
3577c478bd9Sstevel@tonic-gate {
358*08190127Sdh145677 	struct onedev *devp;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	devp = (struct onedev *)malloc(sizeof (struct onedev));
3617c478bd9Sstevel@tonic-gate 	if (devp == NULL) {
3627c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "out of memory in preenlib\n");
3637c478bd9Sstevel@tonic-gate 		exit(1);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 	devp->drvid = did;
3667c478bd9Sstevel@tonic-gate 	devp->mapsize = 0;
3677c478bd9Sstevel@tonic-gate 	devp->unitmap = NULL;
3687c478bd9Sstevel@tonic-gate 	devp->nxtdev = NULL;
3697c478bd9Sstevel@tonic-gate 	return (devp);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate static
3737c478bd9Sstevel@tonic-gate void
3747c478bd9Sstevel@tonic-gate addunit(struct onedev *devp, uint_t unit)
3757c478bd9Sstevel@tonic-gate {
3767c478bd9Sstevel@tonic-gate 	uint_t newsize;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	newsize = howmany(unit+1, WORDSIZE);
3797c478bd9Sstevel@tonic-gate 	if (devp->mapsize < newsize) {
3807c478bd9Sstevel@tonic-gate 		devp->unitmap = devp->mapsize ?
3817c478bd9Sstevel@tonic-gate 		    (uint_t *)realloc(devp->unitmap,
3827c478bd9Sstevel@tonic-gate 		    newsize * sizeof (uint_t)) :
3837c478bd9Sstevel@tonic-gate 		    (uint_t *)malloc(newsize * sizeof (uint_t));
3847c478bd9Sstevel@tonic-gate 		if (devp->unitmap == NULL) {
3857c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "out of memory in preenlib\n");
3867c478bd9Sstevel@tonic-gate 			exit(1);
3877c478bd9Sstevel@tonic-gate 		}
3887c478bd9Sstevel@tonic-gate 		(void) memset((char *)&devp->unitmap[devp->mapsize], 0,
3897c478bd9Sstevel@tonic-gate 		    (uint_t)((newsize - devp->mapsize) * sizeof (uint_t)));
3907c478bd9Sstevel@tonic-gate 		devp->mapsize = newsize;
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 	devp->unitmap[unit / WORDSIZE] |= (1 << (unit % WORDSIZE));
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
395*08190127Sdh145677 static int
3967c478bd9Sstevel@tonic-gate chooseone(int devmapsize, ulong_t *devmap, int drvmapsize, ulong_t *drvmap)
3977c478bd9Sstevel@tonic-gate {
398*08190127Sdh145677 	int i;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	for (i = 0; i < min(devmapsize, drvmapsize); i++) {
4017c478bd9Sstevel@tonic-gate 		if (devmap[i] & drvmap[i])
4027c478bd9Sstevel@tonic-gate 			return (1);
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 	return (0);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate  * mark the given driver/unit pair as busy.  This is called from
4097c478bd9Sstevel@tonic-gate  * preen_getdev.
4107c478bd9Sstevel@tonic-gate  */
4117c478bd9Sstevel@tonic-gate static
4127c478bd9Sstevel@tonic-gate void
4137c478bd9Sstevel@tonic-gate makebusy(struct onedev *dev)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	struct driver *drvp = &dlist[dev->drvid];
4167c478bd9Sstevel@tonic-gate 	int newsize = dev->mapsize;
417*08190127Sdh145677 	int i;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	if (drvp->mapsize < newsize) {
4207c478bd9Sstevel@tonic-gate 		drvp->busymap = drvp->mapsize ?
4217c478bd9Sstevel@tonic-gate 		    (uint_t *)realloc(drvp->busymap,
4227c478bd9Sstevel@tonic-gate 		    newsize * sizeof (uint_t)) :
4237c478bd9Sstevel@tonic-gate 		    (uint_t *)malloc(newsize * sizeof (uint_t));
4247c478bd9Sstevel@tonic-gate 		if (drvp->busymap == NULL) {
4257c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "out of memory in preenlib\n");
4267c478bd9Sstevel@tonic-gate 			exit(1);
4277c478bd9Sstevel@tonic-gate 		}
4287c478bd9Sstevel@tonic-gate 		(void) memset((char *)&drvp->busymap[drvp->mapsize], 0,
4297c478bd9Sstevel@tonic-gate 		    (uint_t)((newsize - drvp->mapsize) * sizeof (uint_t)));
4307c478bd9Sstevel@tonic-gate 		drvp->mapsize = newsize;
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	for (i = 0; i < newsize; i++)
4347c478bd9Sstevel@tonic-gate 		drvp->busymap[i] |= dev->unitmap[i];
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate /*
4387c478bd9Sstevel@tonic-gate  * make each device in the given `rawdev' un-busy.
4397c478bd9Sstevel@tonic-gate  * Called from preen_releasedev
4407c478bd9Sstevel@tonic-gate  */
4417c478bd9Sstevel@tonic-gate static
4427c478bd9Sstevel@tonic-gate void
4437c478bd9Sstevel@tonic-gate notbusy(struct rawdev *rd)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate 	struct onedev *devp;
4467c478bd9Sstevel@tonic-gate 	struct driver *drvp;
447*08190127Sdh145677 	int i;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	for (devp = rd->alldevs; devp; devp = devp->nxtdev) {
4507c478bd9Sstevel@tonic-gate 		drvp = &dlist[devp->drvid];
4517c478bd9Sstevel@tonic-gate 		for (i = 0; i < devp->mapsize; i++)
4527c478bd9Sstevel@tonic-gate 			drvp->busymap[i] &= ~(devp->unitmap[i]);
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate }
455