--- old/usr/src/uts/common/fs/devfs/devfs_subr.c	Tue Jul  3 21:12:48 2018
+++ new/usr/src/uts/common/fs/devfs/devfs_subr.c	Tue Jul  3 21:12:48 2018
@@ -18,11 +18,16 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
+ * Copyright 2018 Nexenta Systems, Inc.
+ */
+
+/*
  * miscellaneous routines for the devfs
  */
 
@@ -72,7 +77,7 @@
 
 /* prototype memory vattrs */
 vattr_t dv_vattr_dir = {
-	AT_TYPE|AT_MODE|AT_UID|AT_GID, 		/* va_mask */
+	AT_TYPE|AT_MODE|AT_UID|AT_GID,		/* va_mask */
 	VDIR,					/* va_type */
 	DV_DIRMODE_DEFAULT,			/* va_mode */
 	DV_UID_DEFAULT,				/* va_uid */
@@ -380,7 +385,7 @@
  */
 static struct dv_node *
 dv_mknod(struct dv_node *ddv, dev_info_t *devi, char *nm,
-	struct ddi_minor_data *dmd)
+    struct ddi_minor_data *dmd)
 {
 	struct dv_node	*dv;
 	struct vnode	*vp;
@@ -403,13 +408,10 @@
 	vn_setops(vp, vn_getops(DVTOV(ddv)));
 	vn_exists(vp);
 
-	/* increment dev_ref with devi_lock held */
 	ASSERT(DEVI_BUSY_OWNED(devi));
-	mutex_enter(&DEVI(devi)->devi_lock);
-	dv->dv_devi = devi;
-	DEVI(devi)->devi_ref++;		/* ndi_hold_devi(dip) */
-	mutex_exit(&DEVI(devi)->devi_lock);
+	ndi_hold_devi(devi);
 
+	dv->dv_devi = devi;
 	dv->dv_ino = dv_mkino(devi, vp->v_type, vp->v_rdev);
 	dv->dv_nlink = 0;		/* updated on insert */
 	dv->dv_dotdot = ddv;
@@ -922,7 +924,7 @@
  */
 int
 dv_find(struct dv_node *ddv, char *nm, struct vnode **vpp, struct pathname *pnp,
-	struct vnode *rdir, struct cred *cred, uint_t ndi_flags)
+    struct vnode *rdir, struct cred *cred, uint_t ndi_flags)
 {
 	extern int isminiroot;	/* see modctl.c */
 
@@ -1445,8 +1447,24 @@
 			ASSERT(dv->dv_nlink == 1);	/* no hard links */
 			mutex_enter(&vp->v_lock);
 			if (vp->v_count > 0) {
-				mutex_exit(&vp->v_lock);
-				goto set_busy;
+				/*
+				 * The file still has references to it.  If
+				 * DV_DEVI_GONE is *not* specified then a
+				 * referenced file is considered busy.
+				 */
+				if (!(flags & DV_DEVI_GONE)) {
+					mutex_exit(&vp->v_lock);
+					goto set_busy;
+				}
+
+				/*
+				 * Mark referenced file stale so that DR will
+				 * succeed even if there are userland opens.
+				 */
+				ASSERT(!DV_STALE(dv));
+				ndi_rele_devi(dv->dv_devi);
+				DEVI(dv->dv_devi)->devi_gone = 1;
+				dv->dv_devi = NULL;
 			}
 		}
 
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Tue Jul  3 21:12:48 2018
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Tue Jul  3 21:12:48 2018
@@ -6183,7 +6183,7 @@
 	uint32_t		page_address;
 	uint16_t		bay_num, enclosure, io_flags;
 	uint32_t		dev_info;
-	char 			uabuf[SCSI_WWN_BUFLEN];
+	char			uabuf[SCSI_WWN_BUFLEN];
 	dev_info_t		*dip;
 	mdi_pathinfo_t		*pip;
 
@@ -15057,7 +15057,7 @@
 		(void) ddi_deviname(cdip, devname);
 		/* Clean cache */
 		(void) devfs_clean(parent, devname + 1,
-		    DV_CLEAN_FORCE);
+		    DV_CLEAN_FORCE|DV_DEVI_GONE);
 		kmem_free(devname, MAXNAMELEN + 1);
 	}
 	if (rpip != NULL) {
@@ -15127,7 +15127,7 @@
 		(void) ddi_deviname(cdip, devname);
 		/* Clean cache */
 		(void) devfs_clean(pdip, devname + 1,
-		    DV_CLEAN_FORCE);
+		    DV_CLEAN_FORCE|DV_DEVI_GONE);
 		kmem_free(devname, MAXNAMELEN + 1);
 	}
 
@@ -16820,7 +16820,7 @@
 	Mpi2SepReply_t		rep;
 	int			ret;
 	mptsas_enclosure_t	*mep;
-	uint16_t 		enctype;
+	uint16_t		enctype;
 
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
--- old/usr/src/uts/common/io/scsi/targets/sd.c	Tue Jul  3 21:12:49 2018
+++ new/usr/src/uts/common/io/scsi/targets/sd.c	Tue Jul  3 21:12:49 2018
@@ -8551,26 +8551,31 @@
 	dev_t			dev;
 	dev_info_t		*pdip = ddi_get_parent(devi);
 	int			instance = ddi_get_instance(devi);
+	int			devigone = DEVI(devi)->devi_gone;
 
 	mutex_enter(&sd_detach_mutex);
 
 	/*
 	 * Fail the detach for any of the following:
-	 *  - Unable to get the sd_lun struct for the instance
-	 *  - A layered driver has an outstanding open on the instance
-	 *  - Another thread is already detaching this instance
-	 *  - Another thread is currently performing an open
+	 * - Unable to get the sd_lun struct for the instance
+	 * - Another thread is already detaching this instance
+	 * - Another thread is currently performing an open
+	 *
+	 * Additionaly, if "device gone" flag is not set:
+	 * - There are outstanding commands in driver
+	 * - There are outstanding commands in transport
 	 */
 	devp = ddi_get_driver_private(devi);
-	if ((devp == NULL) ||
-	    ((un = (struct sd_lun *)devp->sd_private) == NULL) ||
-	    (un->un_ncmds_in_driver != 0) || (un->un_layer_count != 0) ||
-	    (un->un_detach_count != 0) || (un->un_opens_in_progress != 0)) {
+	if (devp == NULL || (un = (struct sd_lun *)devp->sd_private) == NULL ||
+	    un->un_detach_count != 0 || un->un_opens_in_progress != 0 ||
+	    (!devigone && (un->un_ncmds_in_driver != 0 ||
+	    un->un_ncmds_in_transport != 0 ||
+	    un->un_state == SD_STATE_RWAIT))) {
 		mutex_exit(&sd_detach_mutex);
 		return (DDI_FAILURE);
 	}
 
-	SD_TRACE(SD_LOG_ATTACH_DETACH, un, "sd_unit_detach: entry 0x%p\n", un);
+	SD_TRACE(SD_LOG_ATTACH_DETACH, un, "%s: entry 0x%p\n", __func__, un);
 
 	/*
 	 * Mark this instance as currently in a detach, to inhibit any
@@ -8584,10 +8589,6 @@
 
 	dev = sd_make_device(SD_DEVINFO(un));
 
-#ifndef lint
-	_NOTE(COMPETING_THREADS_NOW);
-#endif
-
 	mutex_enter(SD_MUTEX(un));
 
 	/*
@@ -8601,24 +8602,10 @@
 	}
 
 	/*
-	 * Verify there are NO outstanding commands issued to this device.
-	 * ie, un_ncmds_in_transport == 0.
-	 * It's possible to have outstanding commands through the physio
-	 * code path, even though everything's closed.
-	 */
-	if ((un->un_ncmds_in_transport != 0) || (un->un_retry_timeid != NULL) ||
-	    (un->un_direct_priority_timeid != NULL) ||
-	    (un->un_state == SD_STATE_RWAIT)) {
-		mutex_exit(SD_MUTEX(un));
-		SD_ERROR(SD_LOG_ATTACH_DETACH, un,
-		    "sd_dr_detach: Detach failure due to outstanding cmds\n");
-		goto err_stillbusy;
-	}
-
-	/*
 	 * If we have the device reserved, release the reservation.
 	 */
-	if ((un->un_resvd_status & SD_RESERVE) &&
+	if (!devigone &&
+	    (un->un_resvd_status & SD_RESERVE) &&
 	    !(un->un_resvd_status & SD_LOST_RESERVE)) {
 		mutex_exit(SD_MUTEX(un));
 		/*
@@ -8627,7 +8614,7 @@
 		 */
 		if (sd_reserve_release(dev, SD_RELEASE) != 0) {
 			SD_ERROR(SD_LOG_ATTACH_DETACH, un,
-			    "sd_dr_detach: Cannot release reservation \n");
+			    "%s: cannot release reservation\n", __func__);
 		}
 	} else {
 		mutex_exit(SD_MUTEX(un));
@@ -8684,6 +8671,13 @@
 	sd_rmv_resv_reclaim_req(dev);
 
 	mutex_enter(SD_MUTEX(un));
+	if (un->un_retry_timeid != NULL) {
+		timeout_id_t temp_id = un->un_retry_timeid;
+		un->un_retry_timeid = NULL;
+		mutex_exit(SD_MUTEX(un));
+		(void) untimeout(temp_id);
+		mutex_enter(SD_MUTEX(un));
+	}
 
 	/* Cancel any pending callbacks for SD_PATH_DIRECT_PRIORITY cmd. */
 	if (un->un_direct_priority_timeid != NULL) {
@@ -8701,7 +8695,7 @@
 		if (scsi_watch_request_terminate(un->un_mhd_token,
 		    SCSI_WATCH_TERMINATE_NOWAIT)) {
 			SD_ERROR(SD_LOG_ATTACH_DETACH, un,
-			    "sd_dr_detach: Cannot cancel mhd watch request\n");
+			    "%s: cannot cancel mhd watch request\n", __func__);
 			/*
 			 * Note: We are returning here after having removed
 			 * some driver timeouts above. This is consistent with
@@ -8720,7 +8714,7 @@
 		if (scsi_watch_request_terminate(un->un_swr_token,
 		    SCSI_WATCH_TERMINATE_NOWAIT)) {
 			SD_ERROR(SD_LOG_ATTACH_DETACH, un,
-			    "sd_dr_detach: Cannot cancel swr watch request\n");
+			    "%s: cannot cancel swr watch request\n", __func__);
 			/*
 			 * Note: We are returning here after having removed
 			 * some driver timeouts above. This is consistent with
@@ -8733,13 +8727,12 @@
 		un->un_swr_token = NULL;
 	}
 
-	mutex_exit(SD_MUTEX(un));
-
 	/*
 	 * Clear any scsi_reset_notifies. We clear the reset notifies
 	 * if we have not registered one.
 	 * Note: The sd_mhd_reset_notify_cb() fn tries to acquire SD_MUTEX!
 	 */
+	mutex_exit(SD_MUTEX(un));
 	(void) scsi_reset_notify(SD_ADDRESS(un), SCSI_RESET_CANCEL,
 	    sd_mhd_reset_notify_cb, (caddr_t)un);
 
@@ -8791,9 +8784,9 @@
 		    (pm_lower_power(SD_DEVINFO(un), 0, SD_PM_STATE_STOPPED(un))
 		    != DDI_SUCCESS)) {
 			SD_ERROR(SD_LOG_ATTACH_DETACH, un,
-		    "sd_dr_detach: Lower power request failed, ignoring.\n");
+			    "%s: lower power request failed, ignoring\n",
+			    __func__);
 			/*
-			 * Fix for bug: 4297749, item # 13
 			 * The above test now includes a check to see if PM is
 			 * supported by this device before call
 			 * pm_lower_power().
@@ -8856,7 +8849,7 @@
 			 * be the right thing to do.
 			 */
 			SD_ERROR(SD_LOG_ATTACH_DETACH, un,
-			    "sd_dr_detach: Cannot cancel insert event\n");
+			    "%s: cannot cancel insert event\n", __func__);
 			goto err_remove_event;
 		}
 		un->un_insert_event = NULL;
@@ -8871,7 +8864,7 @@
 			 * be the right thing to do.
 			 */
 			SD_ERROR(SD_LOG_ATTACH_DETACH, un,
-			    "sd_dr_detach: Cannot cancel remove event\n");
+			    "%s: cannot cancel remove event\n", __func__);
 			goto err_remove_event;
 		}
 		un->un_remove_event = NULL;
@@ -9014,7 +9007,7 @@
 	un->un_detach_count--;
 	mutex_exit(&sd_detach_mutex);
 
-	SD_TRACE(SD_LOG_ATTACH_DETACH, un, "sd_unit_detach: exit failure\n");
+	SD_TRACE(SD_LOG_ATTACH_DETACH, un, "%s: exit failure\n", __func__);
 	return (DDI_FAILURE);
 }
 
--- old/usr/src/uts/common/os/devcfg.c	Tue Jul  3 21:12:51 2018
+++ new/usr/src/uts/common/os/devcfg.c	Tue Jul  3 21:12:51 2018
@@ -18,9 +18,10 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.
  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  * Copyright (c) 2016 by Delphix. All rights reserved.
@@ -1360,8 +1361,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(dip)->devi_gone)
 		return (DDI_FAILURE);
 
 	NDI_CONFIG_DEBUG((CE_CONT, "detach_node: 0x%p(%s%d)\n",
@@ -3821,8 +3822,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;
@@ -9053,7 +9054,7 @@
 char *
 ddi_curr_redirect(char *curr)
 {
-	char 	*alias;
+	char *alias;
 	int i;
 
 	if (ddi_aliases_present == B_FALSE)
--- old/usr/src/uts/common/sys/ddi_impldefs.h	Tue Jul  3 21:12:52 2018
+++ new/usr/src/uts/common/sys/ddi_impldefs.h	Tue Jul  3 21:12:52 2018
@@ -18,11 +18,16 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
  * Copyright 2016 Joyent, Inc.
  * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.
  */
 
 #ifndef _SYS_DDI_IMPLDEFS_H
@@ -210,6 +215,7 @@
 						/* see below for definitions */
 	kcondvar_t	devi_cv;		/* cv */
 	int		devi_ref;		/* reference count */
+	int		devi_gone;		/* devi gone, force clean */
 
 	dacf_rsrvlist_t *devi_dacf_tasks;	/* dacf reservation queue */
 
--- old/usr/src/uts/common/sys/fs/dv_node.h	Tue Jul  3 21:12:52 2018
+++ new/usr/src/uts/common/sys/fs/dv_node.h	Tue Jul  3 21:12:52 2018
@@ -18,11 +18,16 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright 2018 Nexenta Systems, Inc.
+ */
+
 #ifndef _SYS_DV_NODE_H
 #define	_SYS_DV_NODE_H
 
@@ -110,6 +115,7 @@
 #define	DV_CLEAN_FORCE	0x01	/* force clean of refed directories */
 #define	DV_RESET_PERM	0x02	/* force resetting of node permission */
 #define	DV_CLEANDIR_LCK	0x04	/* dv_contents already held */
+#define	DV_DEVI_GONE	0x08	/* force clean of refed files */
 
 struct devfs_data {
 	struct	dv_node	*devfs_root;
@@ -139,13 +145,13 @@
 #define	VATTR_MP_MERGE(attr, mp)				\
 	attr.va_uid = mp.mp_uid;				\
 	attr.va_gid = mp.mp_gid;				\
-	attr.va_mode = 						\
+	attr.va_mode =						\
 	    (attr.va_mode & ~S_IAMB) | (mp.mp_mode & S_IAMB);
 
 #define	VATTRP_MP_MERGE(attrp, mp)				\
 	attrp->va_uid = mp.mp_uid;				\
 	attrp->va_gid = mp.mp_gid;				\
-	attrp->va_mode = 					\
+	attrp->va_mode =					\
 	    (attrp->va_mode & ~S_IAMB) | (mp.mp_mode & S_IAMB);
 
 /*
