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