I think this approach is wrong, insane, and fragile. DVF_ACTIVE doesn't work precisely that way.
A better approach would be a whole-tree change such that attach functions are non-void. This has been proposed a few times, but noone ever sat down and did the whole-tree work. > could we allow config_attach() to 'fail' without leaving dead device behind? > ie. with gpioow(4) it's easy to make a load of these while testing stuff, > which does lead to inconsistent unit numbering unless you manually detach > the broken ones before attaching another.. > > for devices which are found during autoconf, i guess DETACH_QUIET would > be wanted to keep dmesg pretty, as the error messages printed from any > ca->ca_attach() should be enough, and would mean no visible change for > drivers failing out with this:) > > for smaller diff i chose to use the DVF_ACTIVE, while i'd actually prefer > adding "DVF_FAILED" or something. untested morning-coffee-qual.diff below. > > comments? > > -Artturi > > > diff --git sys/dev/gpio/gpioow.c sys/dev/gpio/gpioow.c > index 64d79ab0cb8..912537b7de7 100644 > --- sys/dev/gpio/gpioow.c > +++ sys/dev/gpio/gpioow.c > @@ -101,7 +101,7 @@ gpioow_attach(struct device *parent, struct device *self, > void *aux) > /* Check that we have enough pins */ > if (gpio_npins(ga->ga_mask) != GPIOOW_NPINS) { > printf(": invalid pin mask\n"); > - return; > + goto fail_nomap; > } > > /* Map pins */ > @@ -110,7 +110,7 @@ gpioow_attach(struct device *parent, struct device *self, > void *aux) > if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, > &sc->sc_map)) { > printf(": can't map pins\n"); > - return; > + goto fail_nomap; > } > > /* Configure data pin */ > @@ -153,6 +153,8 @@ gpioow_attach(struct device *parent, struct device *self, > void *aux) > > fail: > gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); > +fail_nomap: > + config_defer_failure(self); > } > > int > diff --git sys/kern/subr_autoconf.c sys/kern/subr_autoconf.c > index 3fff153e8ad..9a797712510 100644 > --- sys/kern/subr_autoconf.c > +++ sys/kern/subr_autoconf.c > @@ -409,6 +409,11 @@ config_attach(struct device *parent, void *match, void > *aux, cfprint_t print) > if (--autoconf_attdet == 0) > wakeup(&autoconf_attdet); > mtx_leave(&autoconf_attdet_mtx); > + > + if ((dev->dv_flags & DVF_ACTIVE) == 0) { > + if (config_detach(dev, 0) == 0) > + dev = NULL; > + } > return (dev); > } > > @@ -678,6 +683,17 @@ config_defer(struct device *dev, void (*func)(struct > device *)) > config_pending_incr(); > } > > +/* > + * Defer the detachment of the specified device until the end > + * of its own configuration. > + */ > +void > +config_defer_failure(struct device *dev) > +{ > + > + dev->dv_flags &= ~DVF_ACTIVE; > +} > + > /* > * Defer the configuration of the specified device until after > * root file system is mounted. > diff --git sys/sys/device.h sys/sys/device.h > index 00a1f6ad2a6..3820cc6e0f5 100644 > --- sys/sys/device.h > +++ sys/sys/device.h > @@ -185,6 +185,7 @@ int config_activate_children(struct device *, int); > struct device *config_make_softc(struct device *parent, > struct cfdata *cf); > void config_defer(struct device *, void (*)(struct device *)); > +void config_defer_failure(struct device *); > void config_pending_incr(void); > void config_pending_decr(void); > void config_mountroot(struct device *, void (*)(struct device *)); >