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