From: joshua stein Subject: aq: support detaching To: tech@openbsd.org Date: Tue, 18 Aug 2026 10:04:12 -0500 I bought an OWC 10gbit Thunderbolt adapter and it showed up as aq(4). I unplugged it and the kernel panicked with "config_detach: forced detach of aq0 failed (45)". This implements a detach routine that works for me. aq0 at pci5 dev 0 function 0 "Aquantia AQC107S" rev 0x02: msix, 4 queues, Atlantic B1, F/W version 3.0.33, address 00:30:93:17:07:dc Index: sys/dev/pci/if_aq_pci.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_aq_pci.c,v diff -u -p -u -p -r1.37 if_aq_pci.c --- sys/dev/pci/if_aq_pci.c 24 Jul 2026 02:31:43 -0000 1.37 +++ sys/dev/pci/if_aq_pci.c 18 Aug 2026 14:46:41 -0000 @@ -1001,6 +1001,7 @@ struct aq_softc { void *sc_ih; bus_space_handle_t sc_ioh; bus_space_tag_t sc_iot; + bus_size_t sc_iosize; uint32_t sc_mbox_addr; int sc_rbl_enabled; @@ -1130,6 +1131,7 @@ const struct aq_product { int aq_match(struct device *, void *, void *); void aq_attach(struct device *, struct device *, void *); +int aq_detach(struct device *, int); int aq_activate(struct device *, int); int aq_intr(void *); int aq_intr_link(void *); @@ -1230,7 +1232,7 @@ const struct aq_firmware_ops aq2_fw_ops }; const struct cfattach aq_ca = { - sizeof(struct aq_softc), aq_match, aq_attach, NULL, + sizeof(struct aq_softc), aq_match, aq_attach, aq_detach, aq_activate }; @@ -1296,7 +1298,7 @@ aq_attach(struct device *parent, struct memtype = pci_mapreg_type(pc, tag, AQ_BAR0); if (pci_mapreg_map(pa, AQ_BAR0, memtype, 0, &sc->sc_iot, &sc->sc_ioh, - NULL, NULL, 0)) { + NULL, &sc->sc_iosize, 0)) { printf(": failed to map BAR0\n"); return; } @@ -1528,6 +1530,53 @@ aq_attach(struct device *parent, struct aq_enable_intr(sc, 1, 0); printf("\n"); +} + +int +aq_detach(struct device *self, int flags) +{ + struct aq_softc *sc = (struct aq_softc *)self; + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + struct aq_queues *aq; + int i; + + if (ifp->if_flags & IFF_RUNNING) + aq_down(sc); + + aq_enable_intr(sc, 0, 0); + + for (i = 0; i < sc->sc_nqueues; i++) { + aq = &sc->sc_queues[i]; + + if (aq->q_ihc != NULL) { + pci_intr_disestablish(sc->sc_pc, aq->q_ihc); + aq->q_ihc = NULL; + } + timeout_del(&aq->q_rx.rx_refill); + } + + if (sc->sc_ih != NULL) { + pci_intr_disestablish(sc->sc_pc, sc->sc_ih); + sc->sc_ih = NULL; + } + + if (sc->sc_intrmap != NULL) { + intrmap_destroy(sc->sc_intrmap); + sc->sc_intrmap = NULL; + } + + if (ifp->if_softc != NULL) { + ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); + ether_ifdetach(ifp); + if_detach(ifp); + } + + if (sc->sc_iosize != 0) { + bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); + sc->sc_iosize = 0; + } + + return 0; } int