LCOV - code coverage report
Current view: top level - kern - subr_autoconf.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 405 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 26 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13