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 /*
|