Subject: autoconf changes for loadable drivers - please review
To: None <tech-kern@netbsd.org>
From: Matthias Drochner <M.Drochner@fz-juelich.de>
List: tech-kern
Date: 08/11/2004 21:17:36
This is a multipart MIME message.

--==_Exmh_31469296649000
Content-Type: text/plain; charset=us-ascii


Hi -
I believe this stuff is good enough now, ready to be commited
to the -current tree.
Basically these are some additions to the autoconf framework
which make it easy to attach/detach loadable drivers, and
generally each device where the driver and the parent bus
support this.
The additions are in particular:
-Add a "child detached" and a "rescan" method (both optional)
 to the device driver. (This is added to the "cfattach" for now
  because this is under the driver writer's control. Logically
  it belongs more to the "cfdriver", but this is automatically
  generated now.)
 The "child detached" is called by the autoconf framework
 during config_detach(), after the child's ca_detach()
 function was called but before the device data structure
 is freed.
 The "rescan" is called explicitely, either after a driver LKM
 was loaded, or on user request (see the "control device" below).
-Add a field to the device instance where the "locators" (in
  terms of the autoconf framework), which describe the actual
 location of the device relatively to the parent bus, can be
 stored. This can be used by the "child detached" function
 for easier bookkeeping (no need to lookup by device instance
  pointer). (An idea for the future is to use this for generation
  of optimized kernel config files - like DEC's "doconfig".)
-Pass the locators tuple describing a device's location to
 various autoconf functions to support the previous. And since
 locators do only make sense in relation to an "interface
 attribute", pass this as well.
 (The latter was actually an inconsistency in the autoconf
  framework. A bus can support multiple interface attributes,
  but which one is meant had to be communicated implicitely,
  by tags as first elements of the "attach args".)
-Add helper functions to add/remove supplemental "cfdata"
 arrays. Needed for driver LKMs.

To describe the appended files:
-autoconf.txt: Implementing the autoconf changes just described.
-pci.txt: Support dynamic attach/detach for PCI devices.
-scsi.txt: Same for SCSI (with the "control application", one
 gets a replacement for the detach/rescan functions of the
 existing "scsictl" utility).
-addon.tar.gz: some support stuff:
 -ctldev: A pseudo device (LKM for now) to access the detach
  and rescan methods.
 -ctlapp: A userland utility to exercise the control device.
 -testdrv: A driver LKM which just grabs unclaimed PCI devices,
  useful to play with all this.

Would be nice to get some opinions about this...

best regards
Matthias



--==_Exmh_31469296649000
Content-Type: text/plain ; name="autoconf.txt"; charset=us-ascii
Content-Description: autoconf.txt
Content-Disposition: attachment; filename="autoconf.txt"

--- ../../netbsd/sys/kern/subr_autoconf.c	2004-04-07 19:51:12.000000000 +0200
+++ ./kern/subr_autoconf.c	2004-08-11 18:09:54.000000000 +0200
@@ -135,7 +135,10 @@ propdb_t dev_propdb;
 
 struct matchinfo {
 	cfmatch_t fn;
+	cfmatch_loc_t fn_loc;
 	struct	device *parent;
+	const char *ifattr;
+	const locdesc_t *ldesc;
 	void	*aux;
 	struct	cfdata *match;
 	int	pri;
@@ -438,9 +441,12 @@ mapply(struct matchinfo *m, struct cfdat
 {
 	int pri;
 
-	if (m->fn != NULL)
+	if (m->fn != NULL) {
+		KASSERT(m->fn_loc == NULL);
 		pri = (*m->fn)(m->parent, cf, m->aux);
-	else {
+	} else if (m->fn_loc != NULL) {
+		pri = (*m->fn_loc)(m->parent, cf, m->ifattr, m->ldesc, m->aux);
+	} else {
 		struct cfattach *ca;
 
 		ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
@@ -465,7 +471,7 @@ mapply(struct matchinfo *m, struct cfdat
  * on `cfp'.
  */
 static int
-cfparent_match(struct device *parent, const struct cfparent *cfp)
+cfparent_match(const struct device *parent, const struct cfparent *cfp)
 {
 	struct cfdriver *pcd;
 	const char * const *cpp;
@@ -518,6 +524,108 @@ cfparent_match(struct device *parent, co
 }
 
 /*
+ * Helper for config_cfdata_attach(): check whether any attachment in the
+ * config data table fits the device, and rescan accordingly.
+ */
+static int
+rescan_with_cfdata(struct device *d, const struct cfdata *cf)
+{
+	const struct cfdata *cf1;
+	int res;
+
+	for (cf1 = cf; cf1->cf_name; cf1++)
+		if (cfparent_match(d, cf1->cf_pspec)) {
+			res = (*d->dv_cfattach->ca_rescan)(d,
+				cf1->cf_pspec->cfp_iattr, cf1->cf_loc);
+			if (res)
+				return (res);
+		}
+
+	return (0);
+}
+
+/*
+ * Attach a supplemental config data table and rescan potential
+ * parent devices if required.
+ */
+int
+config_cfdata_attach(struct cfdata *cf, int scannow)
+{
+	struct cftable *ct;
+	struct device *d;
+	int res;
+
+	ct = malloc(sizeof(struct cftable), M_DEVBUF, M_WAITOK);
+	ct->ct_cfdata = cf;
+	TAILQ_INSERT_TAIL(&allcftables, ct, ct_list);
+
+	if (!scannow)
+		return (0);
+
+	TAILQ_FOREACH(d, &alldevs, dv_list) {
+		if (d->dv_cfattach->ca_rescan) {
+			res = rescan_with_cfdata(d, cf);
+			if (res)
+				return (res);
+		}
+	}
+
+	return (0);
+}
+
+/*
+ * Helper for config_cfdata_detach: check whether a device is
+ * found through any attachment in the config data table.
+ */
+static int
+dev_in_cfdata(const struct device *d, const struct cfdata *cf)
+{
+	const struct cfdata *cf1;
+
+	for (cf1 = cf; cf1->cf_name; cf1++)
+		if (d->dv_cfdata == cf1)
+			return (1);
+
+	return (0);
+}
+
+/*
+ * Detach a supplemental config data table. Detach all devices found
+ * through that table (and thus keeping references to it) before.
+ */
+int
+config_cfdata_detach(struct cfdata *cf)
+{
+	struct device *d;
+	int error;
+	struct cftable *ct;
+
+again:
+	TAILQ_FOREACH(d, &alldevs, dv_list) {
+		if (dev_in_cfdata(d, cf)) {
+			error = config_detach(d, 0);
+			if (error) {
+				aprint_error("%s: unable to detach instance\n",
+					d->dv_xname);
+				return (error);
+			}
+			goto again;
+		}
+	}
+
+	TAILQ_FOREACH(ct, &allcftables, ct_list) {
+		if (ct->ct_cfdata == cf) {
+			TAILQ_REMOVE(&allcftables, ct, ct_list);
+			free(ct, M_DEVBUF);
+			return (0);
+		}
+	}
+
+	/* not found -- shouldn't happen */
+	return (EINVAL);
+}
+
+/*
  * Invoke the "match" routine for a cfdata entry on behalf of
  * an external caller, usually a "submatch" routine.
  */
@@ -556,6 +664,7 @@ config_search(cfmatch_t fn, struct devic
 	KASSERT(config_initialized);
 
 	m.fn = fn;
+	m.fn_loc = NULL;
 	m.parent = parent;
 	m.aux = aux;
 	m.match = NULL;
@@ -580,6 +689,60 @@ config_search(cfmatch_t fn, struct devic
 	return (m.match);
 }
 
+/* same as above, with real locators passed */
+struct cfdata *
+config_search_loc(cfmatch_loc_t fn, struct device *parent,
+		  const char *ifattr, const locdesc_t *ldesc, void *aux)
+{
+	struct cftable *ct;
+	struct cfdata *cf;
+	struct matchinfo m;
+
+	KASSERT(config_initialized);
+
+	m.fn = NULL;
+	m.fn_loc = fn;
+	m.fn_loc = NULL;
+	m.parent = parent;
+	m.ifattr = ifattr;
+	m.ldesc = ldesc;
+	m.aux = aux;
+	m.match = NULL;
+	m.pri = 0;
+
+	TAILQ_FOREACH(ct, &allcftables, ct_list) {
+		for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
+
+			/* We don't match root nodes here. */
+			if (!cf->cf_pspec)
+				continue;
+
+			/*
+			 * Skip cf if no longer eligible, otherwise scan
+			 * through parents for one matching `parent', and
+			 * try match function.
+			 */
+			if (cf->cf_fstate == FSTATE_FOUND)
+				continue;
+			if (cf->cf_fstate == FSTATE_DNOTFOUND ||
+			    cf->cf_fstate == FSTATE_DSTAR)
+				continue;
+
+			/*
+			 * If an interface attribute was specified,
+			 * consider only children which attach to
+			 * that attribute.
+			 */
+			if (ifattr && !STREQ(ifattr, cf->cf_pspec->cfp_iattr))
+				continue;
+
+			if (cfparent_match(parent, cf->cf_pspec))
+				mapply(&m, cf);
+		}
+	}
+	return (m.match);
+}
+
 /*
  * Find the given root device.
  * This is much like config_search, but there is no parent.
@@ -594,6 +757,7 @@ config_rootsearch(cfmatch_t fn, const ch
 	struct matchinfo m;
 
 	m.fn = fn;
+	m.fn_loc = NULL;
 	m.parent = ROOT;
 	m.aux = aux;
 	m.match = NULL;
@@ -637,6 +801,24 @@ config_found_sm(struct device *parent, v
 	return (NULL);
 }
 
+/* same as above, with real locators passed */
+struct device *
+config_found_sm_loc(struct device *parent,
+		const char *ifattr, const locdesc_t *ldesc, void *aux,
+		cfprint_t print, cfmatch_loc_t submatch)
+{
+	struct cfdata *cf;
+
+	if ((cf = config_search_loc(submatch, parent, ifattr, ldesc, aux)))
+		return(config_attach_loc(parent, cf, ldesc, aux, print));
+	if (print) {
+		if (config_do_twiddle)
+			twiddle();
+		aprint_normal("%s", msgs[(*print)(aux, parent->dv_xname)]);
+	}
+	return (NULL);
+}
+
 /*
  * As above, but for root devices.
  */
@@ -705,8 +887,8 @@ config_makeroom(int n, struct cfdriver *
  * Attach a found device.  Allocates memory for device variables.
  */
 struct device *
-config_attach(struct device *parent, struct cfdata *cf, void *aux,
-	cfprint_t print)
+config_attach_loc(struct device *parent, struct cfdata *cf,
+	const locdesc_t *ldesc, void *aux, cfprint_t print)
 {
 	struct device *dev;
 	struct cftable *ct;
@@ -773,6 +955,11 @@ config_attach(struct device *parent, str
 	memcpy(dev->dv_xname + lname, xunit, lunit);
 	dev->dv_parent = parent;
 	dev->dv_flags = DVF_ACTIVE;	/* always initially active */
+	if (ldesc) {
+		dev->dv_locators = malloc(ldesc->len * sizeof(int),
+					  M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
+		memcpy(dev->dv_locators, ldesc->locs, ldesc->len * sizeof(int));
+	}
 
 	if (config_do_twiddle)
 		twiddle();
@@ -994,6 +1181,13 @@ config_detach(struct device *dev, int fl
 	}
 #endif
 
+	/* notify the parent that the child is gone */
+	if (dev->dv_parent) {
+		struct device *p = dev->dv_parent;
+		if (p->dv_cfattach->ca_childdetached)
+			(*p->dv_cfattach->ca_childdetached)(p, dev);
+	}
+
 	/*
 	 * Mark cfdata to show that the unit can be reused, if possible.
 	 */
@@ -1029,6 +1223,8 @@ config_detach(struct device *dev, int fl
 	cd->cd_devs[dev->dv_unit] = NULL;
 	if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0)
 		aprint_normal("%s detached\n", dev->dv_xname);
+	if (dev->dv_locators)
+		free(dev->dv_locators, M_DEVBUF);
 	free(dev, M_DEVBUF);
 
 	/*
--- ../../netbsd/sys/sys/device.h	2004-05-18 21:26:02.000000000 +0200
+++ ./sys/device.h	2004-08-11 16:23:25.000000000 +0200
@@ -113,6 +113,7 @@ struct device {
 	struct	device *dv_parent;	/* pointer to parent device
 					   (NULL if pesudo- or root node) */
 	int	dv_flags;		/* misc. flags; see below */
+	int	*dv_locators;		/* our actual locators (optional) */
 };
 
 /* dv_flags */
@@ -215,6 +216,18 @@ TAILQ_HEAD(cftablelist, cftable);
 typedef int (*cfmatch_t)(struct device *, struct cfdata *, void *);
 
 /*
+ * XXX the "locdesc_t" is unnecessary; the len is known to "config" and
+ * should be made available through cfdata->cf_pspec->cfp_iattr.
+ * So just an "int *" should do it.
+ */
+typedef struct {
+	int len;
+	int locs[1];
+} locdesc_t;
+typedef int (*cfmatch_loc_t)(struct device *, struct cfdata *,
+			     const char *, const locdesc_t *, void *);
+
+/*
  * `configuration' attachment and driver (what the machine-independent
  * autoconf uses).  As devices are found, they are applied against all
  * the potential matches.  The one with the best match is taken, and a
@@ -237,12 +250,23 @@ struct cfattach {
 	void	(*ca_attach)(struct device *, struct device *, void *);
 	int	(*ca_detach)(struct device *, int);
 	int	(*ca_activate)(struct device *, enum devact);
+	/* technically, the next 2 belong into "struct cfdriver" */
+	int	(*ca_rescan)(struct device *, const char *,
+			     const int *); /* scan for new children */
+	void	(*ca_childdetached)(struct device *, struct device *);
 };
 LIST_HEAD(cfattachlist, cfattach);
 
 #define	CFATTACH_DECL(name, ddsize, matfn, attfn, detfn, actfn)		\
 struct cfattach __CONCAT(name,_ca) = {					\
-	___STRING(name), { 0 }, ddsize, matfn, attfn, detfn, actfn	\
+	___STRING(name), { 0 }, ddsize, matfn, attfn, detfn, actfn, 0, 0 \
+}
+
+#define	CFATTACH_DECL2(name, ddsize, matfn, attfn, detfn, actfn, \
+	rescanfn, chdetfn) \
+struct cfattach __CONCAT(name,_ca) = {					\
+	___STRING(name), { 0 }, ddsize, matfn, attfn, detfn, actfn, \
+		rescanfn, chdetfn \
 }
 
 /* Flags given to config_detach(), and the ca_detach function. */
@@ -317,15 +341,24 @@ int	config_cfdriver_detach(struct cfdriv
 int	config_cfattach_attach(const char *, struct cfattach *);
 int	config_cfattach_detach(const char *, struct cfattach *);
 
+int	config_cfdata_attach(struct cfdata *, int);
+int	config_cfdata_detach(struct cfdata *);
+
 struct cfdriver *config_cfdriver_lookup(const char *);
 struct cfattach *config_cfattach_lookup(const char *, const char *);
 
 struct cfdata *config_search(cfmatch_t, struct device *, void *);
+struct cfdata *config_search_loc(cfmatch_loc_t, struct device *,
+				 const char *, const locdesc_t *, void *);
 struct cfdata *config_rootsearch(cfmatch_t, const char *, void *);
 struct device *config_found_sm(struct device *, void *, cfprint_t, cfmatch_t);
+struct device *config_found_sm_loc(struct device *,
+				   const char *, const locdesc_t *, void *,
+				   cfprint_t, cfmatch_loc_t);
 struct device *config_rootfound(const char *, void *);
-struct device *config_attach(struct device *, struct cfdata *, void *,
-    cfprint_t);
+struct device *config_attach_loc(struct device *, struct cfdata *,
+    const locdesc_t *, void *, cfprint_t);
+#define config_attach(p, cf, aux, pr) config_attach_loc(p, cf, 0, aux, pr)
 int config_match(struct device *, struct cfdata *, void *);
 
 struct device *config_attach_pseudo(const char *, int);

--==_Exmh_31469296649000
Content-Type: text/plain ; name="pci.txt"; charset=us-ascii
Content-Description: pci.txt
Content-Disposition: attachment; filename="pci.txt"

--- ../../netbsd/sys/arch/sparc64/dev/pci_machdep.c	2004-08-02 14:29:29.000000000 +0200
+++ ./arch/sparc64/dev/pci_machdep.c	2004-08-08 22:55:29.000000000 +0200
@@ -58,6 +58,8 @@ __KERNEL_RCSID(0, "$NetBSD: pci_machdep.
 #include <sparc64/dev/psychovar.h>
 #include <sparc64/sparc64/cache.h>
 
+#include "locators.h"
+
 #ifdef DEBUG
 #define SPDB_CONF	0x01
 #define SPDB_INTR	0x04
@@ -265,7 +267,7 @@ pci_decompose_tag(pc, tag, bp, dp, fp)
 }
 
 int
-sparc64_pci_enumerate_bus(struct pci_softc *sc,
+sparc64_pci_enumerate_bus(struct pci_softc *sc, const int *locators,
     int (*match)(struct pci_attach_args *), struct pci_attach_args *pap)
 {
 	struct ofw_pci_register reg;
@@ -331,6 +333,12 @@ sparc64_pci_enumerate_bus(struct pci_sof
 			"(%d/%d/%d)\n", sc->sc_dev.dv_xname, name, b, d, f);
 			continue;
 		}
+                if ((locators[PCICF_DEV] != PCICF_DEV_DEFAULT) &&
+                    (locators[PCICF_DEV] != d))
+                        continue;
+		if ((locators[PCICF_FUNCTION] != PCICF_FUNCTION_DEFAULT) &&
+		    (locators[PCICF_FUNCTION] != f))
+			continue;
 
 		tag = ofpci_make_tag(pc, node, b, d, f);
 
--- ../../netbsd/sys/arch/sparc64/include/pci_machdep.h	2004-08-02 14:29:29.000000000 +0200
+++ ./arch/sparc64/include/pci_machdep.h	2004-08-08 22:51:11.000000000 +0200
@@ -83,8 +83,8 @@ void		*pci_intr_establish(pci_chipset_ta
 					 int, int (*)(void *), void *);
 void		pci_intr_disestablish(pci_chipset_tag_t, void *);
 
-int		sparc64_pci_enumerate_bus(struct pci_softc *,
-		    int (*match)(struct pci_attach_args *),
+int		sparc64_pci_enumerate_bus(struct pci_softc *, const int *,
+		    int (*)(struct pci_attach_args *),
 		    struct pci_attach_args *);
 #define PCI_MACHDEP_ENUMERATE_BUS sparc64_pci_enumerate_bus
 
--- ../../netbsd/sys/dev/pci/pci.c	2004-08-02 14:29:35.000000000 +0200
+++ ./dev/pci/pci.c	2004-08-11 21:14:19.000000000 +0200
@@ -60,17 +60,20 @@ int pci_config_dump = 0;
 
 int pcimatch __P((struct device *, struct cfdata *, void *));
 void pciattach __P((struct device *, struct device *, void *));
+int pcirescan(struct device *, const char *, const int *);
+void pcidevdetached(struct device *, struct device *);
 
-CFATTACH_DECL(pci, sizeof(struct pci_softc),
-    pcimatch, pciattach, NULL, NULL);
+CFATTACH_DECL2(pci, sizeof(struct pci_softc),
+    pcimatch, pciattach, NULL, NULL, pcirescan, pcidevdetached);
 
 int	pciprint __P((void *, const char *));
-int	pcisubmatch __P((struct device *, struct cfdata *, void *));
+int	pcisubmatch __P((struct device *, struct cfdata *,
+			 const char *, const locdesc_t *, void *));
 
 #ifdef PCI_MACHDEP_ENUMERATE_BUS
 #define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS
 #else
-int pci_enumerate_bus(struct pci_softc *,
+int pci_enumerate_bus(struct pci_softc *, const int *,
     int (*)(struct pci_attach_args *), struct pci_attach_args *);
 #endif
 
@@ -136,6 +139,8 @@ pciattach(parent, self, aux)
 	struct pci_softc *sc = (struct pci_softc *)self;
 	int io_enabled, mem_enabled, mrl_enabled, mrm_enabled, mwi_enabled;
 	const char *sep = "";
+	static const int wildcard[2] = { PCICF_DEV_DEFAULT,
+					 PCICF_FUNCTION_DEFAULT };
 
 	pci_attach_hook(parent, self, pba);
 
@@ -192,7 +197,18 @@ do {									\
 	sc->sc_intrswiz = pba->pba_intrswiz;
 	sc->sc_intrtag = pba->pba_intrtag;
 	sc->sc_flags = pba->pba_flags;
-	pci_enumerate_bus(sc, NULL, NULL);
+	pcirescan(&sc->sc_dev, "pci", wildcard);
+}
+
+int
+pcirescan(struct device *sc, const char *ifattr, const int *locators)
+{
+
+	KASSERT(ifattr && !strcmp(ifattr, "pci"));
+	KASSERT(locators);
+
+	pci_enumerate_bus((struct pci_softc *)sc, locators, NULL, NULL);
+	return (0);
 }
 
 int
@@ -246,18 +262,15 @@ pciprint(aux, pnp)
 }
 
 int
-pcisubmatch(parent, cf, aux)
-	struct device *parent;
-	struct cfdata *cf;
-	void *aux;
+pcisubmatch(struct device *parent, struct cfdata *cf,
+	    const char *ifattr, const locdesc_t *ldesc, void *aux)
 {
-	struct pci_attach_args *pa = aux;
 
 	if (cf->pcicf_dev != PCI_UNK_DEV &&
-	    cf->pcicf_dev != pa->pa_device)
+	    cf->pcicf_dev != ldesc->locs[PCICF_DEV])
 		return (0);
 	if (cf->pcicf_function != PCI_UNK_FUNCTION &&
-	    cf->pcicf_function != pa->pa_function)
+	    cf->pcicf_function != ldesc->locs[PCICF_FUNCTION])
 		return (0);
 	return (config_match(parent, cf, aux));
 }
@@ -270,9 +283,16 @@ pci_probe_device(struct pci_softc *sc, p
 	struct pci_attach_args pa;
 	pcireg_t id, csr, class, intr, bhlcr;
 	int ret, pin, bus, device, function;
+	int help[3];
+	locdesc_t *ldp = (void *)&help; /* XXX XXX */
+	struct device *subdev;
 
 	pci_decompose_tag(pc, tag, &bus, &device, &function);
 
+	/* a driver already attached? */
+	if (sc->PCI_SC_DEVICESC(device, function) && !match)
+		return (0);
+
 	bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
 	if (PCI_HDRTYPE_TYPE(bhlcr) > 2)
 		return (0);
@@ -348,13 +368,34 @@ pci_probe_device(struct pci_softc *sc, p
 		if (ret != 0 && pap != NULL)
 			*pap = pa;
 	} else {
-		ret = config_found_sm(&sc->sc_dev, &pa, pciprint,
-		    pcisubmatch) != NULL;
+		ldp->len = 2;
+		ldp->locs[PCICF_DEV] = device;
+		ldp->locs[PCICF_FUNCTION] = function;
+
+		subdev = config_found_sm_loc(&sc->sc_dev, "pci", ldp, &pa,
+					     pciprint, pcisubmatch);
+		sc->PCI_SC_DEVICESC(device, function) = subdev;
+		ret = (subdev != NULL);
 	}
 
 	return (ret);
 }
 
+void
+pcidevdetached(struct device *sc, struct device *dev)
+{
+	struct pci_softc *psc = (struct pci_softc *)sc;
+	int d, f;
+
+	KASSERT(dev->dv_locators);
+	d = dev->dv_locators[PCICF_DEV];
+	f = dev->dv_locators[PCICF_FUNCTION];
+
+	KASSERT(psc->PCI_SC_DEVICESC(d, f) == dev);
+
+	psc->PCI_SC_DEVICESC(d, f) = 0;
+}
+
 int
 pci_get_capability(pc, tag, capid, offset, value)
 	pci_chipset_tag_t pc;
@@ -410,11 +451,12 @@ pci_find_device(struct pci_attach_args *
 	extern struct cfdriver pci_cd;
 	struct device *pcidev;
 	int i;
+	static const int deflocators[2] = { -1, -1 };
 
 	for (i = 0; i < pci_cd.cd_ndevs; i++) {
 		pcidev = pci_cd.cd_devs[i];
 		if (pcidev != NULL &&
-		    pci_enumerate_bus((struct pci_softc *) pcidev,
+		    pci_enumerate_bus((struct pci_softc *)pcidev, deflocators,
 		    		      match, pa) != 0)
 			return (1);
 	}
@@ -427,7 +469,7 @@ pci_find_device(struct pci_attach_args *
  * code needs to provide something else.
  */
 int
-pci_enumerate_bus(struct pci_softc *sc,
+pci_enumerate_bus(struct pci_softc *sc, const int *locators,
     int (*match)(struct pci_attach_args *), struct pci_attach_args *pap)
 {
 	pci_chipset_tag_t pc = sc->sc_pc;
@@ -447,6 +489,10 @@ pci_enumerate_bus(struct pci_softc *sc,
 	for (device = 0; device < sc->sc_maxndevs; device++)
 #endif
 	{
+		if ((locators[PCICF_DEV] != PCICF_DEV_DEFAULT) &&
+		    (locators[PCICF_DEV] != device))
+			continue;
+
 		tag = pci_make_tag(pc, sc->sc_bus, device, 0);
 
 		bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
@@ -474,6 +520,10 @@ pci_enumerate_bus(struct pci_softc *sc,
 			nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1;
 
 		for (function = 0; function < nfunctions; function++) {
+			if ((locators[PCICF_FUNCTION] != PCICF_FUNCTION_DEFAULT)
+			    && (locators[PCICF_FUNCTION] != function))
+				continue;
+
 			if (qd != NULL &&
 			    (qd->quirks & PCI_QUIRK_SKIP_FUNC(function)) != 0)
 				continue;
--- ../../netbsd/sys/dev/pci/pcivar.h	2004-08-07 18:43:14.000000000 +0200
+++ ./dev/pci/pcivar.h	2004-08-08 15:53:16.000000000 +0200
@@ -166,6 +166,9 @@ struct pci_softc {
 	u_int sc_intrswiz;
 	pcitag_t sc_intrtag;
 	int sc_flags;
+	/* accounting of child devices */
+	struct device *sc_devices[32*8];
+#define PCI_SC_DEVICESC(d, f) sc_devices[(d) * 8 + (f)]
 };
 
 extern struct cfdriver pci_cd;

--==_Exmh_31469296649000
Content-Type: text/plain ; name="scsi.txt"; charset=us-ascii
Content-Description: scsi.txt
Content-Disposition: attachment; filename="scsi.txt"

--- ../../netbsd/sys/dev/scsipi/scsiconf.c	2004-08-10 22:06:08.000000000 +0200
+++ ./dev/scsipi/scsiconf.c	2004-08-11 21:18:34.000000000 +0200
@@ -98,11 +98,15 @@ int	scsibusmatch __P((struct device *, s
 void	scsibusattach __P((struct device *, struct device *, void *));
 int	scsibusactivate __P((struct device *, enum devact));
 int	scsibusdetach __P((struct device *, int flags));
+int	scsibusrescan(struct device *, const char *, const int *);
+void	scsidevdetached(struct device *, struct device *);
 
-int	scsibussubmatch __P((struct device *, struct cfdata *, void *));
+int	scsibussubmatch __P((struct device *, struct cfdata *,
+		const char *, const locdesc_t *, void *));
 
-CFATTACH_DECL(scsibus, sizeof(struct scsibus_softc),
-    scsibusmatch, scsibusattach, scsibusdetach, scsibusactivate);
+CFATTACH_DECL2(scsibus, sizeof(struct scsibus_softc),
+    scsibusmatch, scsibusattach, scsibusdetach, scsibusactivate,
+    scsibusrescan, scsidevdetached);
 
 extern struct cfdriver scsibus_cd;
 
@@ -248,19 +252,15 @@ scsibus_config(chan, arg)
 }
 
 int
-scsibussubmatch(parent, cf, aux)
-	struct device *parent;
-	struct cfdata *cf;
-	void *aux;
+scsibussubmatch(struct device *parent, struct cfdata *cf,
+	const char *ifattr, const locdesc_t *ldesc, void *aux)
 {
-	struct scsipibus_attach_args *sa = aux;
-	struct scsipi_periph *periph = sa->sa_periph;
 
 	if (cf->cf_loc[SCSIBUSCF_TARGET] != SCSIBUSCF_TARGET_DEFAULT &&
-	    cf->cf_loc[SCSIBUSCF_TARGET] != periph->periph_target)
+	    cf->cf_loc[SCSIBUSCF_TARGET] != ldesc->locs[0])
 		return (0);
 	if (cf->cf_loc[SCSIBUSCF_LUN] != SCSIBUSCF_LUN_DEFAULT &&
-	    cf->cf_loc[SCSIBUSCF_LUN] != periph->periph_lun)
+	    cf->cf_loc[SCSIBUSCF_LUN] != ldesc->locs[1]) 
 		return (0);
 	return (config_match(parent, cf, aux));
 }
@@ -412,6 +412,35 @@ scsi_probe_bus(sc, target, lun)
 	return (0);
 }
 
+int
+scsibusrescan(struct device *sc, const char *ifattr, const int *locators)
+{
+
+	KASSERT(ifattr && !strcmp(ifattr, "scsibus"));
+	KASSERT(locators);
+
+	return (scsi_probe_bus((struct scsibus_softc *)sc,
+		locators[SCSIBUSCF_TARGET], locators[SCSIBUSCF_LUN]));
+}
+
+void
+scsidevdetached(struct device *sc, struct device *dev)
+{
+	struct scsibus_softc *ssc = (struct scsibus_softc *)sc;
+	struct scsipi_channel *chan = ssc->sc_channel;
+	struct scsipi_periph *periph;
+	int target, lun;
+
+	target = dev->dv_locators[SCSIBUSCF_TARGET];
+	lun = dev->dv_locators[SCSIBUSCF_LUN];
+
+	periph = scsipi_lookup_periph(chan, target, lun);
+	KASSERT(periph->periph_dev == dev);
+
+	scsipi_remove_periph(chan, periph);
+	free(periph, M_DEVBUF);
+}
+
 /*
  * Print out autoconfiguration information for a subdevice.
  *
@@ -729,6 +758,9 @@ scsi_probe_device(sc, target, lun)
 	int checkdtype, priority, docontinue, quirks;
 	struct scsipibus_attach_args sa;
 	struct cfdata *cf;
+	int help[3];
+	locdesc_t *locd = (void *)&help;
+	struct device *chld;
 
 	/*
 	 * Assume no more luns to search after this one.
@@ -941,14 +973,20 @@ scsi_probe_device(sc, target, lun)
 	if ((periph->periph_quirks & PQUIRK_NOLUNS) == 0)
 		docontinue = 1;
 
-	if ((cf = config_search(scsibussubmatch, &sc->sc_dev, &sa)) != NULL) {
+	locd->len = 2;
+	locd->locs[0] = target;
+	locd->locs[1] = lun;
+
+	if ((cf = config_search_loc(scsibussubmatch, &sc->sc_dev,
+	     "scsibus", locd, &sa)) != NULL) {
 		scsipi_insert_periph(chan, periph);
 		/*
 		 * XXX Can't assign periph_dev here, because we'll
 		 * XXX need it before config_attach() returns.  Must
 		 * XXX assign it in periph driver.
 		 */
-		(void) config_attach(&sc->sc_dev, cf, &sa, scsibusprint);
+		chld = config_attach_loc(&sc->sc_dev, cf, locd, &sa,
+					 scsibusprint);
 	} else {
 		scsibusprint(&sa, sc->sc_dev.dv_xname);
 		aprint_normal(" not configured\n");
--- ../../netbsd/sys/dev/scsipi/scsipi_base.c	2004-08-07 18:43:14.000000000 +0200
+++ ./dev/scsipi/scsipi_base.c	2004-08-11 01:16:11.000000000 +0200
@@ -2580,8 +2580,6 @@ scsipi_target_detach(chan, target, lun, 
 			error = config_detach(periph->periph_dev, flags);
 			if (error)
 				return (error);
-			scsipi_remove_periph(chan, periph);
-			free(periph, M_DEVBUF);
 		}
 	}
 	return(0);

--==_Exmh_31469296649000
Content-Type: application/x-gzip ; name="addon.tar.gz"
Content-Description: addon.tar.gz
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="addon.tar.gz"

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

--==_Exmh_31469296649000--