1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2014 Nexenta Systems Inc. All rights reserved.
  24  */
  25 
  26 /*
  27  * Multipath driver interface (MDI) implementation; see mdi_impldefs.h for a
  28  * more detailed discussion of the overall mpxio architecture.
  29  *
  30  * Default locking order:
  31  *
  32  * _NOTE(LOCK_ORDER(mdi_mutex, mdi_vhci:vh_phci_mutex);
  33  * _NOTE(LOCK_ORDER(mdi_mutex, mdi_vhci:vh_client_mutex);
  34  * _NOTE(LOCK_ORDER(mdi_vhci:vh_phci_mutex, mdi_phci::ph_mutex);
  35  * _NOTE(LOCK_ORDER(mdi_vhci:vh_client_mutex, mdi_client::ct_mutex);
  36  * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex))
  37  * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex))
  38  * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex))
  39  */
  40 
  41 #include <sys/note.h>
  42 #include <sys/types.h>
  43 #include <sys/varargs.h>
  44 #include <sys/param.h>
  45 #include <sys/errno.h>
  46 #include <sys/uio.h>
  47 #include <sys/buf.h>
  48 #include <sys/modctl.h>
  49 #include <sys/open.h>
  50 #include <sys/kmem.h>
  51 #include <sys/poll.h>
  52 #include <sys/conf.h>
  53 #include <sys/bootconf.h>
  54 #include <sys/cmn_err.h>
  55 #include <sys/stat.h>
  56 #include <sys/ddi.h>
  57 #include <sys/sunddi.h>
  58 #include <sys/ddipropdefs.h>
 
 
1179                         continue;
1180                 }
1181                 ddi_prop_free(data);
1182                 break;
1183         }
1184         ndi_devi_exit(vh->vh_dip, circular);
1185         return (cdip);
1186 }
1187 
1188 /*
1189  * i_mdi_devinfo_remove():
1190  *              Remove a client device node
1191  */
1192 static int
1193 i_mdi_devinfo_remove(dev_info_t *vdip, dev_info_t *cdip, int flags)
1194 {
1195         int     rv = MDI_SUCCESS;
1196 
1197         if (i_mdi_is_child_present(vdip, cdip) == MDI_SUCCESS ||
1198             (flags & MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED)) {
1199                 rv = ndi_devi_offline(cdip, NDI_DEVFS_CLEAN | NDI_DEVI_REMOVE);
1200                 if (rv != NDI_SUCCESS) {
1201                         MDI_DEBUG(1, (MDI_NOTE, cdip,
1202                             "!failed: cdip %p", (void *)cdip));
1203                 }
1204                 /*
1205                  * Convert to MDI error code
1206                  */
1207                 switch (rv) {
1208                 case NDI_SUCCESS:
1209                         rv = MDI_SUCCESS;
1210                         break;
1211                 case NDI_BUSY:
1212                         rv = MDI_BUSY;
1213                         break;
1214                 default:
1215                         rv = MDI_FAILURE;
1216                         break;
1217                 }
1218         }
1219         return (rv);
 
3246                         rv = (*f)(vh->vh_dip, pip, 0);
3247                 }
3248         } else
3249                 rv = MDI_SUCCESS;
3250 
3251         /*
3252          * If vo_pi_uninit() completed successfully.
3253          */
3254         if (rv == MDI_SUCCESS) {
3255                 if (client_held) {
3256                         MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip,
3257                             "i_mdi_pm_rele_client\n"));
3258                         i_mdi_pm_rele_client(ct, 1);
3259                 }
3260                 i_mdi_pi_free(ph, pip, ct);
3261                 if (ct->ct_path_count == 0) {
3262                         /*
3263                          * Client lost its last path.
3264                          * Clean up the client device
3265                          */
3266                         MDI_CLIENT_UNLOCK(ct);
3267                         (void) i_mdi_client_free(ct->ct_vhci, ct);
3268                         MDI_VHCI_CLIENT_UNLOCK(vh);
3269                         return (rv);
3270                 }
3271         }
3272         MDI_CLIENT_UNLOCK(ct);
3273         MDI_VHCI_CLIENT_UNLOCK(vh);
3274 
3275         if (rv == MDI_FAILURE)
3276                 vhcache_pi_add(vh->vh_config, MDI_PI(pip));
3277 
3278         return (rv);
3279 }
3280 
3281 /*
3282  * i_mdi_pi_free():
3283  *              Free the mdi_pathinfo node
3284  */
3285 static void
 
3653                                          */
3654                                         MDI_CLIENT_UNLOCK(ct);
3655                                         rv = ndi_devi_online(cdip, 0);
3656                                         MDI_CLIENT_LOCK(ct);
3657                                         if ((rv != NDI_SUCCESS) &&
3658                                             (MDI_CLIENT_STATE(ct) ==
3659                                             MDI_CLIENT_STATE_DEGRADED)) {
3660                                                 MDI_DEBUG(1, (MDI_WARN, cdip,
3661                                                     "!ndi_devi_online failed "
3662                                                     "error %x", rv));
3663                                         }
3664                                         rv = NDI_SUCCESS;
3665                                 }
3666                                 break;
3667 
3668                         case MDI_CLIENT_STATE_FAILED:
3669                                 /*
3670                                  * This is the last path case for
3671                                  * non-user initiated events.
3672                                  */
3673                                 if (((flag & NDI_USER_REQ) == 0) &&
3674                                     cdip && (i_ddi_node_state(cdip) >=
3675                                     DS_INITIALIZED)) {
3676                                         MDI_CLIENT_UNLOCK(ct);
3677                                         rv = ndi_devi_offline(cdip,
3678                                             NDI_DEVFS_CLEAN);
3679                                         MDI_CLIENT_LOCK(ct);
3680 
3681                                         if (rv != NDI_SUCCESS) {
3682                                                 /*
3683                                                  * ndi_devi_offline failed.
3684                                                  * Reset client flags to
3685                                                  * online as the path could not
3686                                                  * be offlined.
3687                                                  */
3688                                                 MDI_DEBUG(1, (MDI_WARN, cdip,
3689                                                     "!ndi_devi_offline failed: "
3690                                                     "error %x", rv));
3691                                                 MDI_CLIENT_SET_ONLINE(ct);
3692                                         }
3693                                 }
3694                                 break;
3695                         }
3696                         /*
3697                          * Convert to MDI error code
3698                          */
3699                         switch (rv) {
3700                         case NDI_SUCCESS:
3701                                 MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct);
3702                                 i_mdi_report_path_state(ct, pip);
3703                                 rv = MDI_SUCCESS;
3704                                 break;
3705                         case NDI_BUSY:
3706                                 rv = MDI_BUSY;
3707                                 break;
3708                         default:
3709                                 rv = MDI_FAILURE;
3710                                 break;
3711                         }
3712                 }
3713         }
 
4838                 ct_status = "unknown";
4839         }
4840 
4841         lb_buf[0] = 0;          /* not interested in load balancing config */
4842 
4843         if (MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip)) {
4844                 status = "removed";
4845         } else if (MDI_PI_IS_OFFLINE(pip)) {
4846                 status = "offline";
4847         } else if (MDI_PI_IS_ONLINE(pip)) {
4848                 status = "online";
4849                 report_lb_p = 1;
4850         } else if (MDI_PI_IS_STANDBY(pip)) {
4851                 status = "standby";
4852         } else if (MDI_PI_IS_FAULT(pip)) {
4853                 status = "faulted";
4854         } else {
4855                 status = "unknown";
4856         }
4857 
4858         if (cdip) {
4859                 ct_path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
4860 
4861                 /*
4862                  * NOTE: Keeping "multipath status: %s" and
4863                  * "Load balancing: %s" format unchanged in case someone
4864                  * scrubs /var/adm/messages looking for these messages.
4865                  */
4866                 if (report_lb_c && report_lb_p) {
4867                         if (ct->ct_lb == LOAD_BALANCE_LBA) {
4868                                 (void) snprintf(lb_buf, sizeof (lb_buf),
4869                                     "%s, region-size: %d", mdi_load_balance_lba,
4870                                     ct->ct_lb_args->region_size);
4871                         } else if (ct->ct_lb == LOAD_BALANCE_NONE) {
4872                                 (void) snprintf(lb_buf, sizeof (lb_buf),
4873                                     "%s", mdi_load_balance_none);
4874                         } else {
4875                                 (void) snprintf(lb_buf, sizeof (lb_buf), "%s",
4876                                     mdi_load_balance_rr);
4877                         }
4878 
4879                         cmn_err(mdi_debug_consoleonly ? CE_NOTE : CE_CONT,
4880                             "?%s (%s%d) multipath status: %s: "
4881                             "path %d %s is %s: Load balancing: %s\n",
4882                             ddi_pathname(cdip, ct_path), ddi_driver_name(cdip),
4883                             ddi_get_instance(cdip), ct_status,
4884                             mdi_pi_get_path_instance(pip),
4885                             mdi_pi_spathname(pip), status, lb_buf);
4886                 } else {
4887                         cmn_err(mdi_debug_consoleonly ? CE_NOTE : CE_CONT,
4888                             "?%s (%s%d) multipath status: %s: "
4889                             "path %d %s is %s\n",
4890                             ddi_pathname(cdip, ct_path), ddi_driver_name(cdip),
4891                             ddi_get_instance(cdip), ct_status,
4892                             mdi_pi_get_path_instance(pip),
4893                             mdi_pi_spathname(pip), status);
4894                 }
4895 
4896                 kmem_free(ct_path, MAXPATHLEN);
4897                 MDI_CLIENT_CLEAR_REPORT_DEV_NEEDED(ct);
4898         }
4899 }
4900 
4901 #ifdef  DEBUG
4902 /*
4903  * i_mdi_log():
4904  *              Utility function for error message management
4905  *
4906  *              NOTE: Implementation takes care of trailing \n for cmn_err,
4907  *              MDI_DEBUG should not terminate fmt strings with \n.
4908  *
4909  *              NOTE: If the level is >= 2, and there is no leading !?^
4910  *              then a leading ! is implied (but can be overriden via
4911  *              mdi_debug_consoleonly). If you are using kmdb on the console,
4912  *              consider setting mdi_debug_consoleonly to 1 as an aid.
 
6058         MDI_CLIENT_UNLOCK(ct);
6059 }
6060 
6061 int
6062 mdi_pi_kstat_exists(mdi_pathinfo_t *pip)
6063 {
6064         return (MDI_PI(pip)->pi_kstats ? 1 : 0);
6065 }
6066 
6067 /*
6068  * create and install per-path (client - pHCI) statistics
6069  * I/O stats supported: nread, nwritten, reads, and writes
6070  * Error stats - hard errors, soft errors, & transport errors
6071  */
6072 int
6073 mdi_pi_kstat_create(mdi_pathinfo_t *pip, char *ksname)
6074 {
6075         kstat_t                 *kiosp, *kerrsp;
6076         struct pi_errs          *nsp;
6077         struct mdi_pi_kstats    *mdi_statp;
6078 
6079         if (MDI_PI(pip)->pi_kstats != NULL)
6080                 return (MDI_SUCCESS);
6081 
6082         if ((kiosp = kstat_create("mdi", 0, ksname, "iopath",
6083             KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT)) == NULL) {
6084                 return (MDI_FAILURE);
6085         }
6086 
6087         (void) strcat(ksname, ",err");
6088         kerrsp = kstat_create("mdi", 0, ksname, "iopath_errors",
6089             KSTAT_TYPE_NAMED,
6090             sizeof (struct pi_errs) / sizeof (kstat_named_t), 0);
6091         if (kerrsp == NULL) {
6092                 kstat_delete(kiosp);
6093                 return (MDI_FAILURE);
6094         }
6095 
6096         nsp = (struct pi_errs *)kerrsp->ks_data;
6097         kstat_named_init(&nsp->pi_softerrs, "Soft Errors", KSTAT_DATA_UINT32);
6098         kstat_named_init(&nsp->pi_harderrs, "Hard Errors", KSTAT_DATA_UINT32);
6099         kstat_named_init(&nsp->pi_transerrs, "Transport Errors",
6100             KSTAT_DATA_UINT32);
6101         kstat_named_init(&nsp->pi_icnt_busy, "Interconnect Busy",
6102             KSTAT_DATA_UINT32);
6103         kstat_named_init(&nsp->pi_icnt_errors, "Interconnect Errors",
6104             KSTAT_DATA_UINT32);
6105         kstat_named_init(&nsp->pi_phci_rsrc, "pHCI No Resources",
6106             KSTAT_DATA_UINT32);
6107         kstat_named_init(&nsp->pi_phci_localerr, "pHCI Local Errors",
6108             KSTAT_DATA_UINT32);
6109         kstat_named_init(&nsp->pi_phci_invstate, "pHCI Invalid State",
6110             KSTAT_DATA_UINT32);
6111         kstat_named_init(&nsp->pi_failedfrom, "Failed From",
6112             KSTAT_DATA_UINT32);
6113         kstat_named_init(&nsp->pi_failedto, "Failed To", KSTAT_DATA_UINT32);
6114 
6115         mdi_statp = kmem_alloc(sizeof (*mdi_statp), KM_SLEEP);
6116         mdi_statp->pi_kstat_ref = 1;
6117         mdi_statp->pi_kstat_iostats = kiosp;
6118         mdi_statp->pi_kstat_errstats = kerrsp;
6119         kstat_install(kiosp);
6120         kstat_install(kerrsp);
6121         MDI_PI(pip)->pi_kstats = mdi_statp;
6122         return (MDI_SUCCESS);
6123 }
6124 
6125 /*
6126  * destroy per-path properties
6127  */
6128 static void
6129 i_mdi_pi_kstat_destroy(mdi_pathinfo_t *pip)
6130 {
6131 
6132         struct mdi_pi_kstats *mdi_statp;
6133 
6134         if (MDI_PI(pip)->pi_kstats == NULL)
6135                 return;
6136         if ((mdi_statp = MDI_PI(pip)->pi_kstats) == NULL)
6137                 return;
6138 
6139         MDI_PI(pip)->pi_kstats = NULL;
6140 
6141         /*
 
 | 
   1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2018 Nexenta Systems, Inc.
  25  */
  26 
  27 /*
  28  * Multipath driver interface (MDI) implementation; see mdi_impldefs.h for a
  29  * more detailed discussion of the overall mpxio architecture.
  30  */
  31 
  32 #include <sys/note.h>
  33 #include <sys/types.h>
  34 #include <sys/varargs.h>
  35 #include <sys/param.h>
  36 #include <sys/errno.h>
  37 #include <sys/uio.h>
  38 #include <sys/buf.h>
  39 #include <sys/modctl.h>
  40 #include <sys/open.h>
  41 #include <sys/kmem.h>
  42 #include <sys/poll.h>
  43 #include <sys/conf.h>
  44 #include <sys/bootconf.h>
  45 #include <sys/cmn_err.h>
  46 #include <sys/stat.h>
  47 #include <sys/ddi.h>
  48 #include <sys/sunddi.h>
  49 #include <sys/ddipropdefs.h>
 
 
1170                         continue;
1171                 }
1172                 ddi_prop_free(data);
1173                 break;
1174         }
1175         ndi_devi_exit(vh->vh_dip, circular);
1176         return (cdip);
1177 }
1178 
1179 /*
1180  * i_mdi_devinfo_remove():
1181  *              Remove a client device node
1182  */
1183 static int
1184 i_mdi_devinfo_remove(dev_info_t *vdip, dev_info_t *cdip, int flags)
1185 {
1186         int     rv = MDI_SUCCESS;
1187 
1188         if (i_mdi_is_child_present(vdip, cdip) == MDI_SUCCESS ||
1189             (flags & MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED)) {
1190                 int nflags = NDI_DEVFS_CLEAN | NDI_DEVI_REMOVE;
1191 
1192                 if (flags & MDI_CLIENT_FLAGS_NO_EVENT)
1193                         nflags |= NDI_NO_EVENT;
1194 
1195                 rv = ndi_devi_offline(cdip, nflags);
1196                 if (rv != NDI_SUCCESS) {
1197                         MDI_DEBUG(1, (MDI_NOTE, cdip,
1198                             "!failed: cdip %p", (void *)cdip));
1199                 }
1200                 /*
1201                  * Convert to MDI error code
1202                  */
1203                 switch (rv) {
1204                 case NDI_SUCCESS:
1205                         rv = MDI_SUCCESS;
1206                         break;
1207                 case NDI_BUSY:
1208                         rv = MDI_BUSY;
1209                         break;
1210                 default:
1211                         rv = MDI_FAILURE;
1212                         break;
1213                 }
1214         }
1215         return (rv);
 
3242                         rv = (*f)(vh->vh_dip, pip, 0);
3243                 }
3244         } else
3245                 rv = MDI_SUCCESS;
3246 
3247         /*
3248          * If vo_pi_uninit() completed successfully.
3249          */
3250         if (rv == MDI_SUCCESS) {
3251                 if (client_held) {
3252                         MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip,
3253                             "i_mdi_pm_rele_client\n"));
3254                         i_mdi_pm_rele_client(ct, 1);
3255                 }
3256                 i_mdi_pi_free(ph, pip, ct);
3257                 if (ct->ct_path_count == 0) {
3258                         /*
3259                          * Client lost its last path.
3260                          * Clean up the client device
3261                          */
3262                         ct->ct_flags |= flags;
3263                         MDI_CLIENT_UNLOCK(ct);
3264                         (void) i_mdi_client_free(ct->ct_vhci, ct);
3265                         MDI_VHCI_CLIENT_UNLOCK(vh);
3266                         return (rv);
3267                 }
3268         }
3269         MDI_CLIENT_UNLOCK(ct);
3270         MDI_VHCI_CLIENT_UNLOCK(vh);
3271 
3272         if (rv == MDI_FAILURE)
3273                 vhcache_pi_add(vh->vh_config, MDI_PI(pip));
3274 
3275         return (rv);
3276 }
3277 
3278 /*
3279  * i_mdi_pi_free():
3280  *              Free the mdi_pathinfo node
3281  */
3282 static void
 
3650                                          */
3651                                         MDI_CLIENT_UNLOCK(ct);
3652                                         rv = ndi_devi_online(cdip, 0);
3653                                         MDI_CLIENT_LOCK(ct);
3654                                         if ((rv != NDI_SUCCESS) &&
3655                                             (MDI_CLIENT_STATE(ct) ==
3656                                             MDI_CLIENT_STATE_DEGRADED)) {
3657                                                 MDI_DEBUG(1, (MDI_WARN, cdip,
3658                                                     "!ndi_devi_online failed "
3659                                                     "error %x", rv));
3660                                         }
3661                                         rv = NDI_SUCCESS;
3662                                 }
3663                                 break;
3664 
3665                         case MDI_CLIENT_STATE_FAILED:
3666                                 /*
3667                                  * This is the last path case for
3668                                  * non-user initiated events.
3669                                  */
3670                                 if ((flag & NDI_USER_REQ) ||
3671                                     cdip == NULL || i_ddi_node_state(cdip) <
3672                                     DS_INITIALIZED)
3673                                         break;
3674 
3675                                 MDI_CLIENT_UNLOCK(ct);
3676                                 rv = ndi_devi_offline(cdip, NDI_DEVFS_CLEAN |
3677                                     NDI_DEVI_GONE);
3678                                 MDI_CLIENT_LOCK(ct);
3679 
3680                                 if (rv != NDI_SUCCESS) {
3681                                         /*
3682                                          * Reset client flags to online as the
3683                                          * path could not be offlined.
3684                                          */
3685                                         MDI_DEBUG(1, (MDI_WARN, cdip,
3686                                             "!ndi_devi_offline failed: %d",
3687                                             rv));
3688                                         MDI_CLIENT_SET_ONLINE(ct);
3689                                 }
3690                                 break;
3691                         }
3692                         /*
3693                          * Convert to MDI error code
3694                          */
3695                         switch (rv) {
3696                         case NDI_SUCCESS:
3697                                 MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct);
3698                                 i_mdi_report_path_state(ct, pip);
3699                                 rv = MDI_SUCCESS;
3700                                 break;
3701                         case NDI_BUSY:
3702                                 rv = MDI_BUSY;
3703                                 break;
3704                         default:
3705                                 rv = MDI_FAILURE;
3706                                 break;
3707                         }
3708                 }
3709         }
 
4834                 ct_status = "unknown";
4835         }
4836 
4837         lb_buf[0] = 0;          /* not interested in load balancing config */
4838 
4839         if (MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip)) {
4840                 status = "removed";
4841         } else if (MDI_PI_IS_OFFLINE(pip)) {
4842                 status = "offline";
4843         } else if (MDI_PI_IS_ONLINE(pip)) {
4844                 status = "online";
4845                 report_lb_p = 1;
4846         } else if (MDI_PI_IS_STANDBY(pip)) {
4847                 status = "standby";
4848         } else if (MDI_PI_IS_FAULT(pip)) {
4849                 status = "faulted";
4850         } else {
4851                 status = "unknown";
4852         }
4853 
4854         if (cdip != NULL) {
4855                 ct_path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
4856 
4857                 if (report_lb_c && report_lb_p) {
4858                         if (ct->ct_lb == LOAD_BALANCE_LBA) {
4859                                 (void) snprintf(lb_buf, sizeof (lb_buf),
4860                                     "%s, region-size: %d", mdi_load_balance_lba,
4861                                     ct->ct_lb_args->region_size);
4862                         } else if (ct->ct_lb == LOAD_BALANCE_NONE) {
4863                                 (void) snprintf(lb_buf, sizeof (lb_buf),
4864                                     "%s", mdi_load_balance_none);
4865                         } else {
4866                                 (void) snprintf(lb_buf, sizeof (lb_buf), "%s",
4867                                     mdi_load_balance_rr);
4868                         }
4869 
4870                         dev_err(cdip, CE_CONT, "!multipath status: %s: "
4871                             "path %d %s is %s; load balancing: %s\n",
4872                             ct_status, mdi_pi_get_path_instance(pip),
4873                             mdi_pi_spathname(pip), status, lb_buf);
4874                 } else {
4875                         dev_err(cdip, CE_CONT,
4876                             "!multipath status: %s: path %d %s is %s\n",
4877                             ct_status, mdi_pi_get_path_instance(pip),
4878                             mdi_pi_spathname(pip), status);
4879                 }
4880 
4881                 kmem_free(ct_path, MAXPATHLEN);
4882                 MDI_CLIENT_CLEAR_REPORT_DEV_NEEDED(ct);
4883         }
4884 }
4885 
4886 #ifdef  DEBUG
4887 /*
4888  * i_mdi_log():
4889  *              Utility function for error message management
4890  *
4891  *              NOTE: Implementation takes care of trailing \n for cmn_err,
4892  *              MDI_DEBUG should not terminate fmt strings with \n.
4893  *
4894  *              NOTE: If the level is >= 2, and there is no leading !?^
4895  *              then a leading ! is implied (but can be overriden via
4896  *              mdi_debug_consoleonly). If you are using kmdb on the console,
4897  *              consider setting mdi_debug_consoleonly to 1 as an aid.
 
6043         MDI_CLIENT_UNLOCK(ct);
6044 }
6045 
6046 int
6047 mdi_pi_kstat_exists(mdi_pathinfo_t *pip)
6048 {
6049         return (MDI_PI(pip)->pi_kstats ? 1 : 0);
6050 }
6051 
6052 /*
6053  * create and install per-path (client - pHCI) statistics
6054  * I/O stats supported: nread, nwritten, reads, and writes
6055  * Error stats - hard errors, soft errors, & transport errors
6056  */
6057 int
6058 mdi_pi_kstat_create(mdi_pathinfo_t *pip, char *ksname)
6059 {
6060         kstat_t                 *kiosp, *kerrsp;
6061         struct pi_errs          *nsp;
6062         struct mdi_pi_kstats    *mdi_statp;
6063         char                    *errksname;
6064         size_t                  len;
6065 
6066         /*
6067          * If the kstat name was already created nothing to do.
6068          */
6069         if ((kiosp = kstat_hold_byname("mdi", 0, ksname,
6070             ALL_ZONES)) != NULL) {
6071                 kstat_rele(kiosp);
6072                 return (MDI_SUCCESS);
6073         }
6074 
6075         if ((kiosp = kstat_create("mdi", 0, ksname, "iopath",
6076             KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT)) == NULL) {
6077                 return (MDI_FAILURE);
6078         }
6079 
6080         len = strlen(ksname) + strlen(",err") + 1;
6081         errksname = kmem_alloc(len, KM_SLEEP);
6082         (void) snprintf(errksname, len, "%s,err", ksname);
6083 
6084         kerrsp = kstat_create("mdi", 0, errksname, "iopath_errors",
6085             KSTAT_TYPE_NAMED,
6086             sizeof (struct pi_errs) / sizeof (kstat_named_t), 0);
6087         if (kerrsp == NULL) {
6088                 kstat_delete(kiosp);
6089                 kmem_free(errksname, len);
6090                 return (MDI_FAILURE);
6091         }
6092 
6093         nsp = (struct pi_errs *)kerrsp->ks_data;
6094         kstat_named_init(&nsp->pi_softerrs, "Soft Errors", KSTAT_DATA_UINT32);
6095         kstat_named_init(&nsp->pi_harderrs, "Hard Errors", KSTAT_DATA_UINT32);
6096         kstat_named_init(&nsp->pi_transerrs, "Transport Errors",
6097             KSTAT_DATA_UINT32);
6098         kstat_named_init(&nsp->pi_icnt_busy, "Interconnect Busy",
6099             KSTAT_DATA_UINT32);
6100         kstat_named_init(&nsp->pi_icnt_errors, "Interconnect Errors",
6101             KSTAT_DATA_UINT32);
6102         kstat_named_init(&nsp->pi_phci_rsrc, "pHCI No Resources",
6103             KSTAT_DATA_UINT32);
6104         kstat_named_init(&nsp->pi_phci_localerr, "pHCI Local Errors",
6105             KSTAT_DATA_UINT32);
6106         kstat_named_init(&nsp->pi_phci_invstate, "pHCI Invalid State",
6107             KSTAT_DATA_UINT32);
6108         kstat_named_init(&nsp->pi_failedfrom, "Failed From",
6109             KSTAT_DATA_UINT32);
6110         kstat_named_init(&nsp->pi_failedto, "Failed To", KSTAT_DATA_UINT32);
6111 
6112         mdi_statp = kmem_alloc(sizeof (*mdi_statp), KM_SLEEP);
6113         mdi_statp->pi_kstat_ref = 1;
6114         mdi_statp->pi_kstat_iostats = kiosp;
6115         mdi_statp->pi_kstat_errstats = kerrsp;
6116         kstat_install(kiosp);
6117         kstat_install(kerrsp);
6118         MDI_PI(pip)->pi_kstats = mdi_statp;
6119         kmem_free(errksname, len);
6120         return (MDI_SUCCESS);
6121 }
6122 
6123 /*
6124  * destroy per-path properties
6125  */
6126 static void
6127 i_mdi_pi_kstat_destroy(mdi_pathinfo_t *pip)
6128 {
6129 
6130         struct mdi_pi_kstats *mdi_statp;
6131 
6132         if (MDI_PI(pip)->pi_kstats == NULL)
6133                 return;
6134         if ((mdi_statp = MDI_PI(pip)->pi_kstats) == NULL)
6135                 return;
6136 
6137         MDI_PI(pip)->pi_kstats = NULL;
6138 
6139         /*
 
 |