--- old/usr/src/uts/common/os/sunmdi.c	Mon Aug  5 17:33:34 2019
+++ new/usr/src/uts/common/os/sunmdi.c	Mon Aug  5 17:33:34 2019
@@ -18,24 +18,15 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014 Nexenta Systems Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.
  */
 
 /*
  * Multipath driver interface (MDI) implementation; see mdi_impldefs.h for a
  * more detailed discussion of the overall mpxio architecture.
- *
- * Default locking order:
- *
- * _NOTE(LOCK_ORDER(mdi_mutex, mdi_vhci:vh_phci_mutex);
- * _NOTE(LOCK_ORDER(mdi_mutex, mdi_vhci:vh_client_mutex);
- * _NOTE(LOCK_ORDER(mdi_vhci:vh_phci_mutex, mdi_phci::ph_mutex);
- * _NOTE(LOCK_ORDER(mdi_vhci:vh_client_mutex, mdi_client::ct_mutex);
- * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex))
- * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex))
- * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex))
  */
 
 #include <sys/note.h>
@@ -1196,7 +1187,12 @@
 
 	if (i_mdi_is_child_present(vdip, cdip) == MDI_SUCCESS ||
 	    (flags & MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED)) {
-		rv = ndi_devi_offline(cdip, NDI_DEVFS_CLEAN | NDI_DEVI_REMOVE);
+		int nflags = NDI_DEVFS_CLEAN | NDI_DEVI_REMOVE;
+
+		if (flags & MDI_CLIENT_FLAGS_NO_EVENT)
+			nflags |= NDI_NO_EVENT;
+
+		rv = ndi_devi_offline(cdip, nflags);
 		if (rv != NDI_SUCCESS) {
 			MDI_DEBUG(1, (MDI_NOTE, cdip,
 			    "!failed: cdip %p", (void *)cdip));
@@ -3263,6 +3259,7 @@
 			 * Client lost its last path.
 			 * Clean up the client device
 			 */
+			ct->ct_flags |= flags;
 			MDI_CLIENT_UNLOCK(ct);
 			(void) i_mdi_client_free(ct->ct_vhci, ct);
 			MDI_VHCI_CLIENT_UNLOCK(vh);
@@ -3670,26 +3667,25 @@
 				 * This is the last path case for
 				 * non-user initiated events.
 				 */
-				if (((flag & NDI_USER_REQ) == 0) &&
-				    cdip && (i_ddi_node_state(cdip) >=
-				    DS_INITIALIZED)) {
-					MDI_CLIENT_UNLOCK(ct);
-					rv = ndi_devi_offline(cdip,
-					    NDI_DEVFS_CLEAN);
-					MDI_CLIENT_LOCK(ct);
+				if ((flag & NDI_USER_REQ) ||
+				    cdip == NULL || i_ddi_node_state(cdip) <
+				    DS_INITIALIZED)
+					break;
 
-					if (rv != NDI_SUCCESS) {
-						/*
-						 * ndi_devi_offline failed.
-						 * Reset client flags to
-						 * online as the path could not
-						 * be offlined.
-						 */
-						MDI_DEBUG(1, (MDI_WARN, cdip,
-						    "!ndi_devi_offline failed: "
-						    "error %x", rv));
-						MDI_CLIENT_SET_ONLINE(ct);
-					}
+				MDI_CLIENT_UNLOCK(ct);
+				rv = ndi_devi_offline(cdip, NDI_DEVFS_CLEAN |
+				    NDI_DEVI_GONE);
+				MDI_CLIENT_LOCK(ct);
+
+				if (rv != NDI_SUCCESS) {
+					/*
+					 * Reset client flags to online as the
+					 * path could not be offlined.
+					 */
+					MDI_DEBUG(1, (MDI_WARN, cdip,
+					    "!ndi_devi_offline failed: %d",
+					    rv));
+					MDI_CLIENT_SET_ONLINE(ct);
 				}
 				break;
 			}
@@ -4855,14 +4851,9 @@
 		status = "unknown";
 	}
 
-	if (cdip) {
+	if (cdip != NULL) {
 		ct_path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
 
-		/*
-		 * NOTE: Keeping "multipath status: %s" and
-		 * "Load balancing: %s" format unchanged in case someone
-		 * scrubs /var/adm/messages looking for these messages.
-		 */
 		if (report_lb_c && report_lb_p) {
 			if (ct->ct_lb == LOAD_BALANCE_LBA) {
 				(void) snprintf(lb_buf, sizeof (lb_buf),
@@ -4876,20 +4867,14 @@
 				    mdi_load_balance_rr);
 			}
 
-			cmn_err(mdi_debug_consoleonly ? CE_NOTE : CE_CONT,
-			    "?%s (%s%d) multipath status: %s: "
-			    "path %d %s is %s: Load balancing: %s\n",
-			    ddi_pathname(cdip, ct_path), ddi_driver_name(cdip),
-			    ddi_get_instance(cdip), ct_status,
-			    mdi_pi_get_path_instance(pip),
+			dev_err(cdip, CE_CONT, "!multipath status: %s: "
+			    "path %d %s is %s; load balancing: %s\n",
+			    ct_status, mdi_pi_get_path_instance(pip),
 			    mdi_pi_spathname(pip), status, lb_buf);
 		} else {
-			cmn_err(mdi_debug_consoleonly ? CE_NOTE : CE_CONT,
-			    "?%s (%s%d) multipath status: %s: "
-			    "path %d %s is %s\n",
-			    ddi_pathname(cdip, ct_path), ddi_driver_name(cdip),
-			    ddi_get_instance(cdip), ct_status,
-			    mdi_pi_get_path_instance(pip),
+			dev_err(cdip, CE_CONT,
+			    "!multipath status: %s: path %d %s is %s\n",
+			    ct_status, mdi_pi_get_path_instance(pip),
 			    mdi_pi_spathname(pip), status);
 		}
 
@@ -6075,9 +6060,17 @@
 	kstat_t			*kiosp, *kerrsp;
 	struct pi_errs		*nsp;
 	struct mdi_pi_kstats	*mdi_statp;
+	char			*errksname;
+	size_t			len;
 
-	if (MDI_PI(pip)->pi_kstats != NULL)
+	/*
+	 * If the kstat name was already created nothing to do.
+	 */
+	if ((kiosp = kstat_hold_byname("mdi", 0, ksname,
+	    ALL_ZONES)) != NULL) {
+		kstat_rele(kiosp);
 		return (MDI_SUCCESS);
+	}
 
 	if ((kiosp = kstat_create("mdi", 0, ksname, "iopath",
 	    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT)) == NULL) {
@@ -6084,12 +6077,16 @@
 		return (MDI_FAILURE);
 	}
 
-	(void) strcat(ksname, ",err");
-	kerrsp = kstat_create("mdi", 0, ksname, "iopath_errors",
+	len = strlen(ksname) + strlen(",err") + 1;
+	errksname = kmem_alloc(len, KM_SLEEP);
+	(void) snprintf(errksname, len, "%s,err", ksname);
+
+	kerrsp = kstat_create("mdi", 0, errksname, "iopath_errors",
 	    KSTAT_TYPE_NAMED,
 	    sizeof (struct pi_errs) / sizeof (kstat_named_t), 0);
 	if (kerrsp == NULL) {
 		kstat_delete(kiosp);
+		kmem_free(errksname, len);
 		return (MDI_FAILURE);
 	}
 
@@ -6119,6 +6116,7 @@
 	kstat_install(kiosp);
 	kstat_install(kerrsp);
 	MDI_PI(pip)->pi_kstats = mdi_statp;
+	kmem_free(errksname, len);
 	return (MDI_SUCCESS);
 }
 
