xref: /openbsd/sys/kern/subr_autoconf.c (revision d89ec533)
1 /*	$OpenBSD: subr_autoconf.c,v 1.95 2021/10/26 16:29:49 deraadt Exp $	*/
2 /*	$NetBSD: subr_autoconf.c,v 1.21 1996/04/04 06:06:18 cgd Exp $	*/
3 
4 /*
5  * Copyright (c) 1992, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This software was developed by the Computer Systems Engineering group
9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10  * contributed to Berkeley.
11  *
12  * All advertising materials mentioning features or use of this software
13  * must display the following acknowledgement:
14  *	This product includes software developed by the University of
15  *	California, Lawrence Berkeley Laboratories.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  * 3. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp  (LBL)
42  *
43  *	@(#)subr_autoconf.c	8.1 (Berkeley) 6/10/93
44  */
45 
46 #include <sys/param.h>
47 #include <sys/device.h>
48 #include <sys/hotplug.h>
49 #include <sys/malloc.h>
50 #include <sys/systm.h>
51 #include <sys/queue.h>
52 #include <sys/mutex.h>
53 #include <sys/atomic.h>
54 #include <sys/reboot.h>
55 
56 #include "hotplug.h"
57 #include "mpath.h"
58 
59 /*
60  * Autoconfiguration subroutines.
61  */
62 
63 /*
64  * ioconf.c exports exactly two names: cfdata and cfroots.  All system
65  * devices and drivers are found via these tables.
66  */
67 extern short cfroots[];
68 
69 #define	ROOT ((struct device *)NULL)
70 
71 struct matchinfo {
72 	cfmatch_t fn;
73 	struct	device *parent;
74 	void	*match, *aux;
75 	int	indirect, pri;
76 };
77 
78 #ifndef AUTOCONF_VERBOSE
79 #define AUTOCONF_VERBOSE 0
80 #endif /* AUTOCONF_VERBOSE */
81 int autoconf_verbose = AUTOCONF_VERBOSE;	/* trace probe calls */
82 
83 static void mapply(struct matchinfo *, struct cfdata *);
84 
85 struct deferred_config {
86 	TAILQ_ENTRY(deferred_config) dc_queue;
87 	struct device *dc_dev;
88 	void (*dc_func)(struct device *);
89 };
90 
91 TAILQ_HEAD(, deferred_config) deferred_config_queue;
92 TAILQ_HEAD(, deferred_config) mountroot_config_queue;
93 
94 void *config_rootsearch(cfmatch_t, char *, void *);
95 void config_process_deferred_children(struct device *);
96 
97 struct devicelist alldevs;		/* list of all devices */
98 
99 volatile int config_pending;		/* semaphore for mountroot */
100 
101 struct mutex autoconf_attdet_mtx = MUTEX_INITIALIZER(IPL_HIGH);
102 /*
103  * If > 0, devices are being attached and any thread which tries to
104  * detach will sleep; if < 0 devices are being detached and any
105  * thread which tries to attach will sleep.
106  */
107 int	autoconf_attdet;
108 
109 /*
110  * Initialize autoconfiguration data structures.  This occurs before console
111  * initialization as that might require use of this subsystem.  Furthermore
112  * this means that malloc et al. isn't yet available.
113  */
114 void
115 config_init(void)
116 {
117 	TAILQ_INIT(&deferred_config_queue);
118 	TAILQ_INIT(&mountroot_config_queue);
119 	TAILQ_INIT(&alldevs);
120 }
121 
122 /*
123  * Apply the matching function and choose the best.  This is used
124  * a few times and we want to keep the code small.
125  */
126 void
127 mapply(struct matchinfo *m, struct cfdata *cf)
128 {
129 	int pri;
130 	void *match;
131 
132 	if (m->indirect)
133 		match = config_make_softc(m->parent, cf);
134 	else
135 		match = cf;
136 
137 	if (autoconf_verbose) {
138 		printf(">>> probing for %s", cf->cf_driver->cd_name);
139 		if (cf->cf_fstate == FSTATE_STAR)
140 			printf("*\n");
141 		else
142 			printf("%d\n", cf->cf_unit);
143 	}
144 	if (m->fn != NULL)
145 		pri = (*m->fn)(m->parent, match, m->aux);
146 	else {
147 	        if (cf->cf_attach->ca_match == NULL) {
148 			panic("mapply: no match function for '%s' device",
149 			    cf->cf_driver->cd_name);
150 		}
151 		pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux);
152 	}
153 	if (autoconf_verbose)
154 		printf(">>> %s probe returned %d\n", cf->cf_driver->cd_name,
155 		    pri);
156 
157 	if (pri > m->pri) {
158 		if (m->indirect && m->match) {
159 			cf = ((struct device *)m->match)->dv_cfdata;
160 			free(m->match, M_DEVBUF, cf->cf_attach->ca_devsize);
161 		}
162 		m->match = match;
163 		m->pri = pri;
164 	} else {
165 		if (m->indirect)
166 			free(match, M_DEVBUF, cf->cf_attach->ca_devsize);
167 	}
168 }
169 
170 /*
171  * Iterate over all potential children of some device, calling the given
172  * function (default being the child's match function) for each one.
173  * Nonzero returns are matches; the highest value returned is considered
174  * the best match.  Return the `found child' if we got a match, or NULL
175  * otherwise.  The `aux' pointer is simply passed on through.
176  *
177  * Note that this function is designed so that it can be used to apply
178  * an arbitrary function to all potential children (its return value
179  * can be ignored).
180  */
181 void *
182 config_search(cfmatch_t fn, struct device *parent, void *aux)
183 {
184 	struct cfdata *cf;
185 	short *p;
186 	struct matchinfo m;
187 
188 	m.fn = fn;
189 	m.parent = parent;
190 	m.match = NULL;
191 	m.aux = aux;
192 	m.indirect = parent && (parent->dv_cfdata->cf_driver->cd_mode & CD_INDIRECT);
193 	m.pri = 0;
194 
195 	for (cf = cfdata; cf->cf_driver; cf++) {
196 		/*
197 		 * Skip cf if no longer eligible, otherwise scan
198 		 * through parents for one matching `parent',
199 		 * and try match function.
200 		 */
201 		if (cf->cf_fstate == FSTATE_FOUND)
202 			continue;
203 		if (cf->cf_fstate == FSTATE_DNOTFOUND ||
204 		    cf->cf_fstate == FSTATE_DSTAR)
205 			continue;
206 		if (boothowto & RB_UNHIBERNATE) {
207 			if (cf->cf_driver->cd_mode & CD_SKIPHIBERNATE)
208 				continue;
209 			if (cf->cf_driver->cd_class == DV_IFNET)
210 				continue;
211 			if (cf->cf_driver->cd_class == DV_TAPE)
212 				continue;
213 		}
214 		for (p = cf->cf_parents; *p >= 0; p++)
215 			if (parent->dv_cfdata == &cfdata[*p])
216 				mapply(&m, cf);
217 	}
218 
219 	if (autoconf_verbose) {
220 		if (m.match) {
221 			if (m.indirect)
222 				cf = ((struct device *)m.match)->dv_cfdata;
223 			else
224 				cf = (struct cfdata *)m.match;
225 			printf(">>> %s probe won\n",
226 			    cf->cf_driver->cd_name);
227 		} else
228 			printf(">>> no winning probe\n");
229 	}
230 	return (m.match);
231 }
232 
233 /*
234  * Iterate over all potential children of some device, calling the given
235  * function for each one.
236  *
237  * Note that this function is designed so that it can be used to apply
238  * an arbitrary function to all potential children (its return value
239  * can be ignored).
240  */
241 void
242 config_scan(cfscan_t fn, struct device *parent)
243 {
244 	struct cfdata *cf;
245 	short *p;
246 	void *match;
247 	int indirect;
248 
249 	indirect = parent && (parent->dv_cfdata->cf_driver->cd_mode & CD_INDIRECT);
250 
251 	for (cf = cfdata; cf->cf_driver; cf++) {
252 		/*
253 		 * Skip cf if no longer eligible, otherwise scan
254 		 * through parents for one matching `parent',
255 		 * and try match function.
256 		 */
257 		if (cf->cf_fstate == FSTATE_FOUND)
258 			continue;
259 		if (cf->cf_fstate == FSTATE_DNOTFOUND ||
260 		    cf->cf_fstate == FSTATE_DSTAR)
261 			continue;
262 		for (p = cf->cf_parents; *p >= 0; p++)
263 			if (parent->dv_cfdata == &cfdata[*p]) {
264 				match = indirect?
265 				    config_make_softc(parent, cf) :
266 				    (void *)cf;
267 				(*fn)(parent, match);
268 			}
269 	}
270 }
271 
272 /*
273  * Find the given root device.
274  * This is much like config_search, but there is no parent.
275  */
276 void *
277 config_rootsearch(cfmatch_t fn, char *rootname, void *aux)
278 {
279 	struct cfdata *cf;
280 	short *p;
281 	struct matchinfo m;
282 
283 	m.fn = fn;
284 	m.parent = ROOT;
285 	m.match = NULL;
286 	m.aux = aux;
287 	m.indirect = 0;
288 	m.pri = 0;
289 	/*
290 	 * Look at root entries for matching name.  We do not bother
291 	 * with found-state here since only one instance of each possible
292 	 * root child should ever be searched.
293 	 */
294 	for (p = cfroots; *p >= 0; p++) {
295 		cf = &cfdata[*p];
296 		if (cf->cf_fstate == FSTATE_DNOTFOUND ||
297 		    cf->cf_fstate == FSTATE_DSTAR)
298 			continue;
299 		if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
300 			mapply(&m, cf);
301 	}
302 	return (m.match);
303 }
304 
305 const char *msgs[3] = { "", " not configured\n", " unsupported\n" };
306 
307 /*
308  * The given `aux' argument describes a device that has been found
309  * on the given parent, but not necessarily configured.  Locate the
310  * configuration data for that device (using the submatch function
311  * provided, or using candidates' cd_match configuration driver
312  * functions) and attach it, and return true.  If the device was
313  * not configured, call the given `print' function and return 0.
314  */
315 struct device *
316 config_found_sm(struct device *parent, void *aux, cfprint_t print,
317     cfmatch_t submatch)
318 {
319 	void *match;
320 
321 	if ((match = config_search(submatch, parent, aux)) != NULL)
322 		return (config_attach(parent, match, aux, print));
323 	if (print)
324 		printf("%s", msgs[(*print)(aux, parent->dv_xname)]);
325 	return (NULL);
326 }
327 
328 /*
329  * As above, but for root devices.
330  */
331 struct device *
332 config_rootfound(char *rootname, void *aux)
333 {
334 	void *match;
335 
336 	if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
337 		return (config_attach(ROOT, match, aux, (cfprint_t)NULL));
338 	printf("root device %s not configured\n", rootname);
339 	return (NULL);
340 }
341 
342 /*
343  * Attach a found device.  Allocates memory for device variables.
344  */
345 struct device *
346 config_attach(struct device *parent, void *match, void *aux, cfprint_t print)
347 {
348 	struct cfdata *cf;
349 	struct device *dev;
350 	struct cfdriver *cd;
351 	struct cfattach *ca;
352 
353 	mtx_enter(&autoconf_attdet_mtx);
354 	while (autoconf_attdet < 0)
355 		msleep_nsec(&autoconf_attdet, &autoconf_attdet_mtx,
356 		    PWAIT, "autoconf", INFSLP);
357 	autoconf_attdet++;
358 	mtx_leave(&autoconf_attdet_mtx);
359 
360 	if (parent && (parent->dv_cfdata->cf_driver->cd_mode & CD_INDIRECT)) {
361 		dev = match;
362 		cf = dev->dv_cfdata;
363 	} else {
364 		cf = match;
365 		dev = config_make_softc(parent, cf);
366 	}
367 
368 	cd = cf->cf_driver;
369 	ca = cf->cf_attach;
370 
371 	KASSERT(cd->cd_devs != NULL);
372 	KASSERT(dev->dv_unit < cd->cd_ndevs);
373 	KASSERT(cd->cd_devs[dev->dv_unit] == NULL);
374 	cd->cd_devs[dev->dv_unit] = dev;
375 
376 	/*
377 	 * If this is a "STAR" device and we used the last unit, prepare for
378 	 * another one.
379 	 */
380 	if (cf->cf_fstate == FSTATE_STAR) {
381 		if (dev->dv_unit == cf->cf_unit)
382 			cf->cf_unit++;
383 	} else
384 		cf->cf_fstate = FSTATE_FOUND;
385 
386 	TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
387 	device_ref(dev);
388 
389 	if (parent == ROOT)
390 		printf("%s at root", dev->dv_xname);
391 	else {
392 		printf("%s at %s", dev->dv_xname, parent->dv_xname);
393 		if (print)
394 			(void) (*print)(aux, NULL);
395 	}
396 
397 	/*
398 	 * Before attaching, clobber any unfound devices that are
399 	 * otherwise identical, or bump the unit number on all starred
400 	 * cfdata for this device.
401 	 */
402 	for (cf = cfdata; cf->cf_driver; cf++) {
403 		if (cf->cf_driver == cd &&
404 		    cf->cf_unit == dev->dv_unit) {
405 			if (cf->cf_fstate == FSTATE_NOTFOUND)
406 				cf->cf_fstate = FSTATE_FOUND;
407 			if (cf->cf_fstate == FSTATE_STAR)
408 				cf->cf_unit++;
409 		}
410 	}
411 	device_register(dev, aux);
412 	(*ca->ca_attach)(parent, dev, aux);
413 	config_process_deferred_children(dev);
414 #if NHOTPLUG > 0
415 	if (!cold)
416 		hotplug_device_attach(cd->cd_class, dev->dv_xname);
417 #endif
418 
419 	mtx_enter(&autoconf_attdet_mtx);
420 	if (--autoconf_attdet == 0)
421 		wakeup(&autoconf_attdet);
422 	mtx_leave(&autoconf_attdet_mtx);
423 	return (dev);
424 }
425 
426 struct device *
427 config_make_softc(struct device *parent, struct cfdata *cf)
428 {
429 	struct device *dev;
430 	struct cfdriver *cd;
431 	struct cfattach *ca;
432 
433 	cd = cf->cf_driver;
434 	ca = cf->cf_attach;
435 	if (ca->ca_devsize < sizeof(struct device))
436 		panic("config_make_softc");
437 
438 	/* get memory for all device vars */
439 	dev = malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT|M_ZERO);
440 	if (dev == NULL)
441 		panic("config_make_softc: allocation for device softc failed");
442 
443 	dev->dv_class = cd->cd_class;
444 	dev->dv_cfdata = cf;
445 	dev->dv_flags = DVF_ACTIVE;	/* always initially active */
446 
447 	/* If this is a STAR device, search for a free unit number */
448 	if (cf->cf_fstate == FSTATE_STAR) {
449 		for (dev->dv_unit = cf->cf_starunit1;
450 		    dev->dv_unit < cf->cf_unit; dev->dv_unit++)
451 			if (cd->cd_ndevs == 0 ||
452 			    dev->dv_unit >= cd->cd_ndevs ||
453 			    cd->cd_devs[dev->dv_unit] == NULL)
454 				break;
455 	} else
456 		dev->dv_unit = cf->cf_unit;
457 
458 	/* Build the device name into dv_xname. */
459 	if (snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d",
460 	    cd->cd_name, dev->dv_unit) >= sizeof(dev->dv_xname))
461 		panic("config_make_softc: device name too long");
462 	dev->dv_parent = parent;
463 
464 	/* put this device in the devices array */
465 	if (dev->dv_unit >= cd->cd_ndevs) {
466 		/*
467 		 * Need to expand the array.
468 		 */
469 		int old = cd->cd_ndevs, new;
470 		void **nsp;
471 
472 		if (old == 0)
473 			new = MINALLOCSIZE / sizeof(void *);
474 		else
475 			new = old * 2;
476 		while (new <= dev->dv_unit)
477 			new *= 2;
478 		cd->cd_ndevs = new;
479 		nsp = mallocarray(new, sizeof(void *), M_DEVBUF, M_NOWAIT|M_ZERO);
480 		if (nsp == NULL)
481 			panic("config_make_softc: %sing dev array",
482 			    old != 0 ? "expand" : "creat");
483 		if (old != 0) {
484 			bcopy(cd->cd_devs, nsp, old * sizeof(void *));
485 			free(cd->cd_devs, M_DEVBUF, old * sizeof(void *));
486 		}
487 		cd->cd_devs = nsp;
488 	}
489 	if (cd->cd_devs[dev->dv_unit])
490 		panic("config_make_softc: duplicate %s", dev->dv_xname);
491 
492 	dev->dv_ref = 1;
493 
494 	return (dev);
495 }
496 
497 /*
498  * Detach a device.  Optionally forced (e.g. because of hardware
499  * removal) and quiet.  Returns zero if successful, non-zero
500  * (an error code) otherwise.
501  *
502  * Note that this code wants to be run from a process context, so
503  * that the detach can sleep to allow processes which have a device
504  * open to run and unwind their stacks.
505  */
506 int
507 config_detach(struct device *dev, int flags)
508 {
509 	struct cfdata *cf;
510 	struct cfattach *ca;
511 	struct cfdriver *cd;
512 	int rv = 0, i;
513 #ifdef DIAGNOSTIC
514 	struct device *d;
515 #endif
516 #if NHOTPLUG > 0
517 	char devname[16];
518 #endif
519 
520 	mtx_enter(&autoconf_attdet_mtx);
521 	while (autoconf_attdet > 0)
522 		msleep_nsec(&autoconf_attdet, &autoconf_attdet_mtx,
523 		    PWAIT, "autoconf", INFSLP);
524 	autoconf_attdet--;
525 	mtx_leave(&autoconf_attdet_mtx);
526 
527 #if NHOTPLUG > 0
528 	strlcpy(devname, dev->dv_xname, sizeof(devname));
529 #endif
530 
531 	cf = dev->dv_cfdata;
532 #ifdef DIAGNOSTIC
533 	if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR)
534 		panic("config_detach: bad device fstate");
535 #endif
536 	ca = cf->cf_attach;
537 	cd = cf->cf_driver;
538 
539 	/*
540 	 * Ensure the device is deactivated.  If the device has an
541 	 * activation entry point and DVF_ACTIVE is still set, the
542 	 * device is busy, and the detach fails.
543 	 */
544 	rv = config_deactivate(dev);
545 
546 	/*
547 	 * Try to detach the device.  If that's not possible, then
548 	 * we either panic() (for the forced but failed case), or
549 	 * return an error.
550 	 */
551 	if (rv == 0) {
552 		if (ca->ca_detach != NULL)
553 			rv = (*ca->ca_detach)(dev, flags);
554 		else
555 			rv = EOPNOTSUPP;
556 	}
557 	if (rv != 0) {
558 		if ((flags & DETACH_FORCE) == 0)
559 			goto done;
560 		else
561 			panic("config_detach: forced detach of %s failed (%d)",
562 			    dev->dv_xname, rv);
563 	}
564 
565 	/*
566 	 * The device has now been successfully detached.
567 	 */
568 
569 #ifdef DIAGNOSTIC
570 	/*
571 	 * Sanity: If you're successfully detached, you should have no
572 	 * children.  (Note that because children must be attached
573 	 * after parents, we only need to search the latter part of
574 	 * the list.)
575 	 */
576 	i = 0;
577 	for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
578 	     d = TAILQ_NEXT(d, dv_list)) {
579 		if (d->dv_parent == dev) {
580 			printf("config_detach: %s attached at %s\n",
581 			    d->dv_xname, dev->dv_xname);
582 			i = 1;
583 		}
584 	}
585 	if (i != 0)
586 		panic("config_detach: detached device (%s) has children",
587 		    dev->dv_xname);
588 #endif
589 
590 	/*
591 	 * Mark cfdata to show that the unit can be reused, if possible.
592 	 * Note that we can only re-use a starred unit number if the unit
593 	 * being detached had the last assigned unit number.
594 	 */
595 	for (cf = cfdata; cf->cf_driver; cf++) {
596 		if (cf->cf_driver == cd) {
597 			if (cf->cf_fstate == FSTATE_FOUND &&
598 			    cf->cf_unit == dev->dv_unit)
599 				cf->cf_fstate = FSTATE_NOTFOUND;
600 			if (cf->cf_fstate == FSTATE_STAR &&
601 			    cf->cf_unit == dev->dv_unit + 1)
602 				cf->cf_unit--;
603 		}
604 	}
605 
606 	/*
607 	 * Unlink from device list.
608 	 */
609 	TAILQ_REMOVE(&alldevs, dev, dv_list);
610 	device_unref(dev);
611 
612 	/*
613 	 * Remove from cfdriver's array, tell the world, and free softc.
614 	 */
615 	cd->cd_devs[dev->dv_unit] = NULL;
616 	if ((flags & DETACH_QUIET) == 0)
617 		printf("%s detached\n", dev->dv_xname);
618 
619 	device_unref(dev);
620 	/*
621 	 * If the device now has no units in use, deallocate its softc array.
622 	 */
623 	for (i = 0; i < cd->cd_ndevs; i++)
624 		if (cd->cd_devs[i] != NULL)
625 			break;
626 	if (i == cd->cd_ndevs) {		/* nothing found; deallocate */
627 		free(cd->cd_devs, M_DEVBUF, cd->cd_ndevs * sizeof(void *));
628 		cd->cd_devs = NULL;
629 		cd->cd_ndevs = 0;
630 		cf->cf_unit = 0;
631 	}
632 
633 #if NHOTPLUG > 0
634 	if (!cold)
635 		hotplug_device_detach(cd->cd_class, devname);
636 #endif
637 
638 	/*
639 	 * Return success.
640 	 */
641 done:
642 	mtx_enter(&autoconf_attdet_mtx);
643 	if (++autoconf_attdet == 0)
644 		wakeup(&autoconf_attdet);
645 	mtx_leave(&autoconf_attdet_mtx);
646 	return (rv);
647 }
648 
649 int
650 config_deactivate(struct device *dev)
651 {
652 	int rv = 0, oflags = dev->dv_flags;
653 
654 	if (dev->dv_flags & DVF_ACTIVE) {
655 		dev->dv_flags &= ~DVF_ACTIVE;
656 		rv = config_suspend(dev, DVACT_DEACTIVATE);
657 		if (rv)
658 			dev->dv_flags = oflags;
659 	}
660 	return (rv);
661 }
662 
663 /*
664  * Defer the configuration of the specified device until all
665  * of its parent's devices have been attached.
666  */
667 void
668 config_defer(struct device *dev, void (*func)(struct device *))
669 {
670 	struct deferred_config *dc;
671 
672 	if (dev->dv_parent == NULL)
673 		panic("config_defer: can't defer config of a root device");
674 
675 #ifdef DIAGNOSTIC
676 	for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
677 	     dc = TAILQ_NEXT(dc, dc_queue)) {
678 		if (dc->dc_dev == dev)
679 			panic("config_defer: deferred twice");
680 	}
681 #endif
682 
683 	if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
684 		panic("config_defer: can't allocate defer structure");
685 
686 	dc->dc_dev = dev;
687 	dc->dc_func = func;
688 	TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
689 	config_pending_incr();
690 }
691 
692 /*
693  * Defer the configuration of the specified device until after
694  * root file system is mounted.
695  */
696 void
697 config_mountroot(struct device *dev, void (*func)(struct device *))
698 {
699 	struct deferred_config *dc;
700 
701 	/*
702 	 * No need to defer if root file system is already mounted.
703 	 */
704 	if (rootvp != NULL) {
705 		(*func)(dev);
706 		return;
707 	}
708 
709 #ifdef DIAGNOSTIC
710 	for (dc = TAILQ_FIRST(&mountroot_config_queue); dc != NULL;
711 	     dc = TAILQ_NEXT(dc, dc_queue)) {
712 		if (dc->dc_dev == dev)
713 			panic("config_mountroot: deferred twice");
714 	}
715 #endif
716 
717 	if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
718 		panic("config_mountroot: can't allocate defer structure");
719 
720 	dc->dc_dev = dev;
721 	dc->dc_func = func;
722 	TAILQ_INSERT_TAIL(&mountroot_config_queue, dc, dc_queue);
723 }
724 
725 /*
726  * Process the deferred configuration queue for a device.
727  */
728 void
729 config_process_deferred_children(struct device *parent)
730 {
731 	struct deferred_config *dc, *ndc;
732 
733 	for (dc = TAILQ_FIRST(&deferred_config_queue);
734 	     dc != NULL; dc = ndc) {
735 		ndc = TAILQ_NEXT(dc, dc_queue);
736 		if (dc->dc_dev->dv_parent == parent) {
737 			TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue);
738 			(*dc->dc_func)(dc->dc_dev);
739 			free(dc, M_DEVBUF, sizeof(*dc));
740 			config_pending_decr();
741 		}
742 	}
743 }
744 
745 /*
746  * Process the deferred configuration queue after the root file
747  * system is mounted .
748  */
749 void
750 config_process_deferred_mountroot(void)
751 {
752 	struct deferred_config *dc;
753 
754 	while ((dc = TAILQ_FIRST(&mountroot_config_queue)) != NULL) {
755 		TAILQ_REMOVE(&mountroot_config_queue, dc, dc_queue);
756 		(*dc->dc_func)(dc->dc_dev);
757 		free(dc, M_DEVBUF, sizeof(*dc));
758 	}
759 }
760 
761 /*
762  * Manipulate the config_pending semaphore.
763  */
764 void
765 config_pending_incr(void)
766 {
767 
768 	config_pending++;
769 }
770 
771 void
772 config_pending_decr(void)
773 {
774 
775 #ifdef DIAGNOSTIC
776 	if (config_pending == 0)
777 		panic("config_pending_decr: config_pending == 0");
778 #endif
779 	config_pending--;
780 	if (config_pending == 0)
781 		wakeup((void *)&config_pending);
782 }
783 
784 int
785 config_detach_children(struct device *parent, int flags)
786 {
787 	struct device *dev, *next_dev;
788 	int rv = 0;
789 
790 	/*
791 	 * The config_detach routine may sleep, meaning devices
792 	 * may be added to the queue. However, all devices will
793 	 * be added to the tail of the queue, the queue won't
794 	 * be re-organized, and the subtree of parent here should be locked
795 	 * for purposes of adding/removing children.
796 	 *
797 	 * Note that we can not afford trying to walk the device list
798 	 * once - our ``next'' device might be a child of the device
799 	 * we are about to detach, so it would disappear.
800 	 * Just play it safe and restart from the parent.
801 	 */
802 	for (dev = TAILQ_LAST(&alldevs, devicelist);
803 	    dev != NULL; dev = next_dev) {
804 		if (dev->dv_parent == parent) {
805 			if ((rv = config_detach(dev, flags)) != 0)
806 				return (rv);
807 			next_dev = TAILQ_LAST(&alldevs, devicelist);
808 		} else {
809 			next_dev = TAILQ_PREV(dev, devicelist, dv_list);
810 		}
811 	}
812 
813 	return (0);
814 }
815 
816 int
817 config_suspend(struct device *dev, int act)
818 {
819 	struct cfattach *ca = dev->dv_cfdata->cf_attach;
820 	int r;
821 
822 	device_ref(dev);
823 	if (ca->ca_activate)
824 		r = (*ca->ca_activate)(dev, act);
825 	else
826 		r = config_activate_children(dev, act);
827 	device_unref(dev);
828 	return (r);
829 }
830 
831 int
832 config_suspend_all(int act)
833 {
834 	struct device *mainbus = device_mainbus();
835 	struct device *mpath = device_mpath();
836 	int rv = 0;
837 
838 	switch (act) {
839 	case DVACT_QUIESCE:
840 	case DVACT_SUSPEND:
841 	case DVACT_POWERDOWN:
842 		if (mpath) {
843 			rv = config_suspend(mpath, act);
844 			if (rv)
845 				return rv;
846 		}
847 		if (mainbus)
848 			rv = config_suspend(mainbus, act);
849 		break;
850 	case DVACT_RESUME:
851 	case DVACT_WAKEUP:
852 		if (mainbus) {
853 			rv = config_suspend(mainbus, act);
854 			if (rv)
855 				return rv;
856 		}
857 		if (mpath)
858 			rv = config_suspend(mpath, act);
859 		break;
860 	}
861 
862 	return (rv);
863 }
864 
865 /*
866  * Call the ca_activate for each of our children, letting each
867  * decide whether they wish to do the same for their children
868  * and more.
869  */
870 int
871 config_activate_children(struct device *parent, int act)
872 {
873 	struct device *d;
874 	int rv = 0;
875 
876 	for (d = TAILQ_NEXT(parent, dv_list); d != NULL;
877 	    d = TAILQ_NEXT(d, dv_list)) {
878 		if (d->dv_parent != parent)
879 			continue;
880 		switch (act) {
881 		case DVACT_QUIESCE:
882 		case DVACT_SUSPEND:
883 		case DVACT_RESUME:
884 		case DVACT_WAKEUP:
885 		case DVACT_POWERDOWN:
886 			rv = config_suspend(d, act);
887 			break;
888 		case DVACT_DEACTIVATE:
889 			rv = config_deactivate(d);
890 			break;
891 		}
892 		if (rv == 0)
893 			continue;
894 
895 		/*
896 		 * Found a device that refuses the action.
897 		 * If we were being asked to suspend, we can
898 		 * try to resume all previous devices.
899 		 */
900 #ifdef DIAGNOSTIC
901 		printf("config_activate_children: device %s failed %d\n",
902 		    d->dv_xname, act);
903 #endif
904 		if (act == DVACT_RESUME)
905 			printf("failing resume cannot be handled\n");
906 		if (act == DVACT_POWERDOWN)
907 			return (rv);
908 		if (act != DVACT_SUSPEND)
909 			return (rv);
910 
911 		d = TAILQ_PREV(d, devicelist, dv_list);
912 		for (; d != NULL && d != parent;
913 		    d = TAILQ_PREV(d, devicelist, dv_list)) {
914 			if (d->dv_parent != parent)
915 				continue;
916 			printf("resume %s\n", d->dv_xname);
917 			config_suspend(d, DVACT_RESUME);
918 		}
919 		return (rv);
920 	}
921 	return (rv);
922 }
923 
924 /*
925  * Lookup a device in the cfdriver device array.  Does not return a
926  * device if it is not active.
927  *
928  * Increments ref count on the device by one, reflecting the
929  * new reference created on the stack.
930  *
931  * Context: process only
932  */
933 struct device *
934 device_lookup(struct cfdriver *cd, int unit)
935 {
936 	struct device *dv = NULL;
937 
938 	if (unit >= 0 && unit < cd->cd_ndevs)
939 		dv = (struct device *)(cd->cd_devs[unit]);
940 
941 	if (!dv)
942 		return (NULL);
943 
944 	if (!(dv->dv_flags & DVF_ACTIVE))
945 		dv = NULL;
946 
947 	if (dv != NULL)
948 		device_ref(dv);
949 
950 	return (dv);
951 }
952 
953 struct device *
954 device_mainbus(void)
955 {
956 	extern struct cfdriver mainbus_cd;
957 
958 	if (mainbus_cd.cd_ndevs < 1)
959 		return (NULL);
960 
961 	return (mainbus_cd.cd_devs[0]);
962 }
963 
964 struct device *
965 device_mpath(void)
966 {
967 #if NMPATH > 0
968 	extern struct cfdriver mpath_cd;
969 
970 	if (mpath_cd.cd_ndevs < 1)
971 		return (NULL);
972 
973 	return (mpath_cd.cd_devs[0]);
974 #else
975 	return (NULL);
976 #endif
977 }
978 
979 /*
980  * Increments the ref count on the device structure. The device
981  * structure is freed when the ref count hits 0.
982  *
983  * Context: process or interrupt
984  */
985 void
986 device_ref(struct device *dv)
987 {
988 	atomic_inc_int(&dv->dv_ref);
989 }
990 
991 /*
992  * Decrement the ref count on the device structure.
993  *
994  * free's the structure when the ref count hits zero.
995  *
996  * Context: process or interrupt
997  */
998 void
999 device_unref(struct device *dv)
1000 {
1001 	struct cfattach *ca;
1002 
1003 	if (atomic_dec_int_nv(&dv->dv_ref) == 0) {
1004 		ca = dv->dv_cfdata->cf_attach;
1005 		free(dv, M_DEVBUF, ca->ca_devsize);
1006 	}
1007 }
1008