--- old/usr/src/uts/common/os/devcfg.c	Mon Aug  5 17:33:00 2019
+++ new/usr/src/uts/common/os/devcfg.c	Mon Aug  5 17:33:00 2019
@@ -18,11 +18,12 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.
  * Copyright (c) 2016 by Delphix. All rights reserved.
  */
 
@@ -171,10 +172,9 @@
 int identify_9e = 0;
 
 /*
- * Add flag so behaviour of preventing attach for retired persistant nodes
- * can be disabled.
+ * Don't prevent attaching retired devices by default.
  */
-int retire_prevents_attach = 1;
+int retire_prevents_attach = 0;
 
 int mtc_off;					/* turn off mt config */
 
@@ -485,11 +485,6 @@
 	    "dip=%p, name=%s", (void *)dip, devi->devi_node_name));
 
 	kmem_free(devi->devi_node_name, strlen(devi->devi_node_name) + 1);
-
-	/* free event data */
-	if (devi->devi_ev_path)
-		kmem_free(devi->devi_ev_path, MAXPATHLEN);
-
 	kmem_cache_free(ddi_node_cache, devi);
 }
 
@@ -1360,8 +1355,8 @@
 	ASSERT(DEVI_BUSY_OWNED(ddi_get_parent(dip)));
 	ASSERT(i_ddi_node_state(dip) == DS_ATTACHED);
 
-	/* check references */
-	if (DEVI(dip)->devi_ref)
+	/* Check references */
+	if (DEVI(dip)->devi_ref != 0 && !DEVI_IS_GONE(dip))
 		return (DDI_FAILURE);
 
 	NDI_CONFIG_DEBUG((CE_CONT, "detach_node: 0x%p(%s%d)\n",
@@ -1463,6 +1458,8 @@
 {
 	int rval;
 
+	DEVI_UNSET_GONE(dip);
+
 	/*
 	 * For hotplug busses like USB, it's possible that devices
 	 * are removed but dip is still around. We don't want to
@@ -3821,8 +3818,8 @@
  * to ioc's bus_config entry point.
  */
 int
-resolve_pathname(char *pathname,
-	dev_info_t **dipp, dev_t *devtp, int *spectypep)
+resolve_pathname(char *pathname, dev_info_t **dipp, dev_t *devtp,
+    int *spectypep)
 {
 	int			error;
 	dev_info_t		*parent, *child;
@@ -4600,9 +4597,9 @@
  * report device status
  */
 static void
-i_ndi_devi_report_status_change(dev_info_t *dip, char *path)
+i_ndi_devi_report_status_change(dev_info_t *dip)
 {
-	char *status;
+	const char *status;
 
 	if (!DEVI_NEED_REPORT(dip) ||
 	    (i_ddi_node_state(dip) < DS_INITIALIZED) ||
@@ -4629,17 +4626,8 @@
 		status = "unknown";
 	}
 
-	if (path == NULL) {
-		path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
-		cmn_err(CE_CONT, "?%s (%s%d) %s\n",
-		    ddi_pathname(dip, path), ddi_driver_name(dip),
-		    ddi_get_instance(dip), status);
-		kmem_free(path, MAXPATHLEN);
-	} else {
-		cmn_err(CE_CONT, "?%s (%s%d) %s\n",
-		    path, ddi_driver_name(dip),
-		    ddi_get_instance(dip), status);
-	}
+	cmn_err(CE_CONT, "?%s%d %s\n", ddi_driver_name(dip),
+	    ddi_get_instance(dip), status);
 
 	mutex_enter(&(DEVI(dip)->devi_lock));
 	DEVI_REPORT_DONE(dip);
@@ -5227,7 +5215,7 @@
 		return (NDI_FAILURE);
 	}
 
-	i_ndi_devi_report_status_change(dip, NULL);
+	i_ndi_devi_report_status_change(dip);
 
 	/*
 	 * log an event, but not during devfs lookups in which case
@@ -5765,6 +5753,17 @@
 		ASSERT(retval == LDI_EV_NONE);
 	}
 
+	/*
+	 * In order to allow a device retire to succeed that is in use
+	 */
+
+	if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "allow-unconstrained-retire", 0) == 1 && failure == 0) {
+		RIO_VERBOSE((CE_NOTE, "e_ddi_offline_notify(): setting "
+		    "constraint flag due to 'allow-unconstrained-retire' "
+		    "property on dip=%p", (void *)dip));
+		constraint = 1;
+	}
 out:
 	mutex_enter(&(DEVI(dip)->devi_lock));
 	if ((DEVI(dip)->devi_flags & DEVI_RETIRING) && failure) {
@@ -5930,27 +5929,30 @@
 	}
 
 	if (i_ddi_node_state(dip) == DS_INITIALIZED) {
-		struct dev_info *devi = DEVI(dip);
-
-		if (devi->devi_ev_path == NULL) {
-			devi->devi_ev_path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
-			(void) ddi_pathname(dip, devi->devi_ev_path);
-		}
 		if (flags & NDI_DEVI_OFFLINE)
-			i_ndi_devi_report_status_change(dip,
-			    devi->devi_ev_path);
+			i_ndi_devi_report_status_change(dip);
 
 		if (need_remove_event(dip, flags)) {
-			/*
-			 * instance and path data are lost in call to
-			 * ddi_uninitchild
-			 */
-			devi->devi_ev_instance = ddi_get_instance(dip);
-
 			mutex_enter(&(DEVI(dip)->devi_lock));
 			DEVI_SET_EVREMOVE(dip);
 			mutex_exit(&(DEVI(dip)->devi_lock));
+
+			post_event = (flags & NDI_DEVI_REMOVE) ||
+			    DEVI_IS_GONE(dip);
 		}
+
+		if (post_event) {
+			/*
+			 * Instance and path data are lost in call to
+			 * ddi_uninitchild.
+			 */
+			path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+			(void) ddi_pathname(dip, path);
+			class = i_ddi_strdup(i_ddi_devi_class(dip), KM_SLEEP);
+			driver = i_ddi_strdup((char *)ddi_driver_name(dip),
+			    KM_SLEEP);
+			instance = ddi_get_instance(dip);
+		}
 	}
 
 	if (flags & (NDI_UNCONFIG | NDI_DEVI_REMOVE)) {
@@ -5964,46 +5966,28 @@
 			if (!ndi_dev_is_persistent_node(dip))
 				flags |= NDI_DEVI_REMOVE;
 
-			if (flags & NDI_DEVI_REMOVE) {
-				/*
-				 * NOTE: If there is a consumer of LDI events,
-				 * ddi_uninitchild above would have failed
-				 * because of active devi_ref from ldi_open().
-				 */
-
-				if (DEVI_EVREMOVE(dip)) {
-					path = i_ddi_strdup(
-					    DEVI(dip)->devi_ev_path,
-					    KM_SLEEP);
-					class =
-					    i_ddi_strdup(i_ddi_devi_class(dip),
-					    KM_SLEEP);
-					driver =
-					    i_ddi_strdup(
-					    (char *)ddi_driver_name(dip),
-					    KM_SLEEP);
-					instance = DEVI(dip)->devi_ev_instance;
-					post_event = 1;
-				}
-
+			if (flags & NDI_DEVI_REMOVE)
 				ret = ddi_remove_child(dip, 0);
-				if (post_event && ret == NDI_SUCCESS) {
-					/* Generate EC_DEVFS_DEVI_REMOVE */
-					(void) i_log_devfs_remove_devinfo(path,
-					    class, driver, instance, flags);
-				}
-			}
-
 		}
 	}
 
-	if (path)
-		strfree(path);
-	if (class)
+	if (ret == NDI_SUCCESS && post_event) {
+		/* Generate EC_DEVFS/ESC_DEVFS_DEVI_REMOVE */
+		(void) i_log_devfs_remove_devinfo(path,
+		    class, driver, instance, flags);
+	}
+
+	if (path != NULL)
+		kmem_free(path, MAXPATHLEN);
+	if (class != NULL)
 		strfree(class);
-	if (driver)
+	if (driver != NULL)
 		strfree(driver);
 
+	/* Clean the flag on successful detach */
+	if (ret == NDI_SUCCESS)
+		DEVI_UNSET_GONE(dip);
+
 	return (ret);
 }
 
@@ -6579,6 +6563,9 @@
 
 	flags |= NDI_DEVI_OFFLINE;
 
+	if (flags & NDI_DEVI_GONE)
+		DEVI_SET_GONE(dip);
+
 	/*
 	 * If child is pHCI and vHCI and pHCI are not siblings then enter vHCI
 	 * before parent(pHCI) to avoid deadlock with mpxio Client power
@@ -8100,7 +8087,7 @@
 	dnp->dn_head = dip;
 	UNLOCK_DEV_OPS(&dnp->dn_lock);
 
-	i_ndi_devi_report_status_change(dip, NULL);
+	i_ndi_devi_report_status_change(dip);
 
 	return (dip);
 }
@@ -8147,7 +8134,7 @@
 	mutex_exit(&(DEVI(dip)->devi_lock));
 
 	/* report remove (as 'removed') */
-	i_ndi_devi_report_status_change(dip, NULL);
+	i_ndi_devi_report_status_change(dip);
 
 	/*
 	 * Invalidate the cache to ensure accurate
@@ -8184,7 +8171,7 @@
 	mutex_exit(&(DEVI(dip)->devi_lock));
 
 	/* report insert (as 'online') */
-	i_ndi_devi_report_status_change(dip, NULL);
+	i_ndi_devi_report_status_change(dip);
 
 	/*
 	 * Invalidate the cache to ensure accurate
@@ -9053,7 +9040,7 @@
 char *
 ddi_curr_redirect(char *curr)
 {
-	char 	*alias;
+	char *alias;
 	int i;
 
 	if (ddi_aliases_present == B_FALSE)
