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