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