From 0929604dd3c95ca773b9b855e375a567cc6681c1 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh@NetBSD.org>
Date: Mon, 31 Jan 2022 22:56:03 +0000
Subject: [PATCH 35/39] autoconf(9): Disentangle slightly circuitous
 config_detach logic.

No functional change intended.
---
 sys/kern/subr_autoconf.c | 37 +++++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 12 deletions(-)

diff --git a/sys/kern/subr_autoconf.c b/sys/kern/subr_autoconf.c
index 03afc7f54b55..5c1c865785f8 100644
--- a/sys/kern/subr_autoconf.c
+++ b/sys/kern/subr_autoconf.c
@@ -2029,6 +2029,11 @@ config_detach(device_t dev, int flags)
 	alldevs_nwrite++;
 	mutex_exit(&alldevs_lock);
 
+	/*
+	 * Call the driver's .ca_detach function, unless it has none or
+	 * we are skipping it because it's unforced shutdown time and
+	 * the driver didn't ask to detach on shutdown.
+	 */
 	if (!detachall &&
 	    (flags & (DETACH_SHUTDOWN|DETACH_FORCE)) == DETACH_SHUTDOWN &&
 	    (dev->dv_flags & DVF_DETACH_SHUTDOWN) == 0) {
@@ -2041,31 +2046,39 @@ config_detach(device_t dev, int flags)
 	/*
 	 * If it was not possible to detach the device, then we either
 	 * panic() (for the forced but failed case), or return an error.
-	 *
-	 * If it was possible to detach the device, ensure that the
-	 * device is deactivated.
 	 */
-	if (rv == 0) {
-		config_detach_commit(dev);
-		dev->dv_flags &= ~DVF_ACTIVE; /* XXXSMP */
-	} else if ((flags & DETACH_FORCE) == 0) {
+	if (rv) {
 		/*
-		 * Detach failed -- likely EBUSY.  Driver must not have
-		 * called config_detach_commit.
+		 * Detach failed -- likely EOPNOTSUPP or EBUSY.  Driver
+		 * must not have called config_detach_commit.
 		 */
 		KASSERTMSG(!dev->dv_detached,
 		    "%s committed to detaching and then backed out",
 		    device_xname(dev));
+		if (flags & DETACH_FORCE) {
+			panic("config_detach: forced detach of %s failed (%d)",
+			    device_xname(dev), rv);
+		}
 		goto out;
-	} else {
-		panic("config_detach: forced detach of %s failed (%d)",
-		    device_xname(dev), rv);
 	}
 
 	/*
 	 * The device has now been successfully detached.
 	 */
 
+	/*
+	 * If .ca_detach didn't commit to detach, then do that for it.
+	 * This wakes any pending device_lookup_acquire calls so they
+	 * will fail.
+	 */
+	config_detach_commit(dev);
+
+	/*
+	 * If it was possible to detach the device, ensure that the
+	 * device is deactivated.
+	 */
+	dev->dv_flags &= ~DVF_ACTIVE; /* XXXSMP */
+
 	/*
 	 * Wait for all device_lookup_acquire references -- mostly, for
 	 * all attempts to open the device -- to drain.  It is the