xref: /illumos-gate/usr/src/uts/common/io/softmac/softmac_stat.c (revision fc910014e8a32a65612105835a10995f2c13d942)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Copyright 2015 Garrett D'Amore <garret@damore.org>
26  * Copyright 2016 Joyent, Inc.
27  */
28 
29 #include <sys/types.h>
30 #include <sys/kstat.h>
31 #include <sys/mac.h>
32 #include <sys/dls.h>
33 #include <sys/softmac_impl.h>
34 
35 typedef struct i_softmac_stat_info_s {
36 	uint_t		ssi_stat;
37 	char		*ssi_name;
38 	char		*ssi_alias;
39 } i_softmac_stat_info_t;
40 
41 /*
42  * Must be the same order as mac_driver_stat.
43  */
44 static i_softmac_stat_info_t	i_softmac_driver_si[] = {
45 	{ MAC_STAT_IFSPEED,	"ifspeed",	"link_speed"	},
46 	{ MAC_STAT_MULTIRCV,	"multircv",	NULL		},
47 	{ MAC_STAT_BRDCSTRCV,	"brdcstrcv",	NULL		},
48 	{ MAC_STAT_MULTIXMT,	"multixmt",	NULL		},
49 	{ MAC_STAT_BRDCSTXMT,	"brdcstxmt",	NULL		},
50 	{ MAC_STAT_NORCVBUF,	"norcvbuf",	"rx_no_buf"	},
51 	{ MAC_STAT_IERRORS,	"ierrors",	NULL		},
52 	{ MAC_STAT_UNKNOWNS,	"unknowns",	NULL		},
53 	{ MAC_STAT_NOXMTBUF,	"noxmtbuf",	"No Txpkt "	},
54 	{ MAC_STAT_OERRORS,	"oerrors",	NULL		},
55 	{ MAC_STAT_COLLISIONS,	"collisions",	NULL		},
56 	{ MAC_STAT_RBYTES,	"rbytes64",	"rbytes"	},
57 	{ MAC_STAT_IPACKETS,	"ipackets64",	"ipackets"	},
58 	{ MAC_STAT_OBYTES,	"obytes64",	"obytes"	},
59 	{ MAC_STAT_OPACKETS,	"opackets64",	"opackets"	},
60 	{ MAC_STAT_UNDERFLOWS,	"uflo",		NULL		},
61 	{ MAC_STAT_OVERFLOWS,	"oflo",		NULL		}
62 };
63 
64 #define	SOFTMAC_DRIVER_SI_SZ						\
65 	(sizeof (i_softmac_driver_si) / sizeof (i_softmac_driver_si[0]))
66 
67 /*
68  * Must be the same order as ether_stat.
69  */
70 static i_softmac_stat_info_t	i_softmac_ether_si[] = {
71 	{ ETHER_STAT_ALIGN_ERRORS,	"align_errors",
72 	    "alignment_err" },
73 	{ ETHER_STAT_FCS_ERRORS,	"fcs_errors",		"crc_err" },
74 	{ ETHER_STAT_FIRST_COLLISIONS,	"first_collisions",	NULL },
75 	{ ETHER_STAT_MULTI_COLLISIONS,	"multi_collisions",	NULL },
76 	{ ETHER_STAT_SQE_ERRORS,	"sqe_errors",		NULL },
77 	{ ETHER_STAT_DEFER_XMTS,	"defer_xmts",		NULL },
78 	{ ETHER_STAT_TX_LATE_COLLISIONS, "tx_late_collisions",
79 	    "late_collisions" },
80 	{ ETHER_STAT_EX_COLLISIONS,	"ex_collisions",
81 	    "excessive_collisions" },
82 	{ ETHER_STAT_MACXMT_ERRORS,	"macxmt_errors",	NULL },
83 	{ ETHER_STAT_CARRIER_ERRORS,	"carrier_errors",	NULL },
84 	{ ETHER_STAT_TOOLONG_ERRORS,	"toolong_errors",	"length_err" },
85 	{ ETHER_STAT_MACRCV_ERRORS,	"macrcv_errors",
86 	    "Rx Error Count" },
87 
88 	{ ETHER_STAT_XCVR_ADDR,		"xcvr_addr",		NULL },
89 	{ ETHER_STAT_XCVR_ID,		"xcvr_id",		NULL },
90 	{ ETHER_STAT_XCVR_INUSE,	"xcvr_inuse",		NULL },
91 
92 	{ ETHER_STAT_CAP_1000FDX,	"cap_1000fdx",		NULL },
93 	{ ETHER_STAT_CAP_1000HDX,	"cap_1000hdx",		NULL },
94 	{ ETHER_STAT_CAP_100FDX,	"cap_100fdx",		NULL },
95 	{ ETHER_STAT_CAP_100HDX,	"cap_100hdx",		NULL },
96 	{ ETHER_STAT_CAP_10FDX,		"cap_10fdx",		NULL },
97 	{ ETHER_STAT_CAP_10HDX,		"cap_10hdx",		NULL },
98 	{ ETHER_STAT_CAP_ASMPAUSE,	"cap_asmpause",		NULL },
99 	{ ETHER_STAT_CAP_PAUSE,		"cap_pause",		NULL },
100 	{ ETHER_STAT_CAP_AUTONEG,	"cap_autoneg",		NULL },
101 
102 	{ ETHER_STAT_ADV_CAP_1000FDX,	"adv_cap_1000fdx",	NULL },
103 	{ ETHER_STAT_ADV_CAP_1000HDX,	"adv_cap_1000hdx",	NULL },
104 	{ ETHER_STAT_ADV_CAP_100FDX,	"adv_cap_100fdx",	NULL },
105 	{ ETHER_STAT_ADV_CAP_100HDX,	"adv_cap_100hdx",	NULL },
106 	{ ETHER_STAT_ADV_CAP_10FDX,	"adv_cap_10fdx",	NULL },
107 	{ ETHER_STAT_ADV_CAP_10HDX,	"adv_cap_10hdx",	NULL },
108 	{ ETHER_STAT_ADV_CAP_ASMPAUSE,	"adv_cap_asmpause",	NULL },
109 	{ ETHER_STAT_ADV_CAP_PAUSE,	"adv_cap_pause",	NULL },
110 	{ ETHER_STAT_ADV_CAP_AUTONEG,	"adv_cap_autoneg",	NULL },
111 
112 	{ ETHER_STAT_LP_CAP_1000FDX,	"lp_cap_1000fdx",	NULL },
113 	{ ETHER_STAT_LP_CAP_1000HDX,	"lp_cap_1000hdx",	NULL },
114 	{ ETHER_STAT_LP_CAP_100FDX,	"lp_cap_100fdx",	NULL },
115 	{ ETHER_STAT_LP_CAP_100HDX,	"lp_cap_100hdx",	NULL },
116 	{ ETHER_STAT_LP_CAP_10FDX,	"lp_cap_10fdx",		NULL },
117 	{ ETHER_STAT_LP_CAP_10HDX,	"lp_cap_10hdx",		NULL },
118 	{ ETHER_STAT_LP_CAP_ASMPAUSE,	"lp_cap_asmpause",	NULL },
119 	{ ETHER_STAT_LP_CAP_PAUSE,	"lp_cap_pause",		NULL },
120 	{ ETHER_STAT_LP_CAP_AUTONEG,	"lp_cap_autoneg",	NULL },
121 
122 	{ ETHER_STAT_LINK_ASMPAUSE,	"link_asmpause",	NULL },
123 	{ ETHER_STAT_LINK_PAUSE,	"link_pause",		NULL },
124 	{ ETHER_STAT_LINK_AUTONEG,	"link_autoneg",		NULL },
125 	{ ETHER_STAT_LINK_DUPLEX,	"link_duplex",		"duplex" },
126 
127 	{ ETHER_STAT_TOOSHORT_ERRORS,	"runt_errors",		NULL },
128 	{ ETHER_STAT_CAP_REMFAULT,	"cap_rem_fault",	NULL },
129 	{ ETHER_STAT_ADV_REMFAULT,	"adv_rem_fault",	NULL },
130 	{ ETHER_STAT_LP_REMFAULT,	"lp_rem_fault",		NULL },
131 
132 	{ ETHER_STAT_JABBER_ERRORS,	"jabber_errors",	NULL },
133 	{ ETHER_STAT_CAP_100T4,		"cap_100T4",		NULL },
134 	{ ETHER_STAT_ADV_CAP_100T4,	"adv_cap_100T4",	NULL },
135 	{ ETHER_STAT_LP_CAP_100T4,	"lp_cap_100T4",		NULL },
136 
137 	{ ETHER_STAT_CAP_10GFDX,	"cap_10gfdx",		NULL },
138 	{ ETHER_STAT_ADV_CAP_10GFDX,	"adv_cap_10gfdx",	NULL },
139 	{ ETHER_STAT_LP_CAP_1000FDX,	"lp_cap_10gfdx",	NULL },
140 
141 	{ ETHER_STAT_CAP_40GFDX,	"cap_40gfdx",		NULL },
142 	{ ETHER_STAT_ADV_CAP_40GFDX,	"adv_cap_40gfdx",	NULL },
143 	{ ETHER_STAT_LP_CAP_40GFDX,	"lp_cap_40gfdx",	NULL },
144 
145 	{ ETHER_STAT_CAP_100GFDX,	"cap_100gfdx",		NULL },
146 	{ ETHER_STAT_ADV_CAP_100GFDX,	"adv_cap_100gfdx",	NULL },
147 	{ ETHER_STAT_LP_CAP_100GFDX,	"lp_cap_100gfdx",	NULL },
148 
149 	{ ETHER_STAT_CAP_2500FDX,	"cap_2500fdx",		NULL },
150 	{ ETHER_STAT_ADV_CAP_2500FDX,	"adv_cap_2500fdx",	NULL },
151 	{ ETHER_STAT_LP_CAP_2500FDX,	"lp_cap_2500fdx",	NULL },
152 
153 	{ ETHER_STAT_CAP_5000FDX,	"cap_5000fdx",		NULL },
154 	{ ETHER_STAT_ADV_CAP_5000FDX,	"adv_cap_5000fdx",	NULL },
155 	{ ETHER_STAT_LP_CAP_5000FDX,	"lp_cap_5000fdx",	NULL },
156 
157 	{ ETHER_STAT_CAP_25GFDX,	"cap_25gfdx",		NULL },
158 	{ ETHER_STAT_ADV_CAP_25GFDX,	"adv_cap_25gfdx",	NULL },
159 	{ ETHER_STAT_LP_CAP_25GFDX,	"lp_cap_25gfdx",	NULL },
160 
161 	{ ETHER_STAT_CAP_50GFDX,	"cap_50gfdx",		NULL },
162 	{ ETHER_STAT_ADV_CAP_50GFDX,	"adv_cap_50gfdx",	NULL },
163 	{ ETHER_STAT_LP_CAP_50GFDX,	"lp_cap_50gfdx",	NULL },
164 
165 	{ ETHER_STAT_CAP_200GFDX,	"cap_200gfdx",		NULL },
166 	{ ETHER_STAT_ADV_CAP_200GFDX,	"adv_cap_200gfdx",	NULL },
167 	{ ETHER_STAT_LP_CAP_200GFDX,	"lp_cap_200gfdx",	NULL },
168 
169 	{ ETHER_STAT_CAP_400GFDX,	"cap_400gfdx",		NULL },
170 	{ ETHER_STAT_ADV_CAP_400GFDX,	"adv_cap_400gfdx",	NULL },
171 	{ ETHER_STAT_LP_CAP_400GFDX,	"lp_cap_400gfdx",	NULL },
172 };
173 
174 #define	SOFTMAC_ETHER_SI_SZ						\
175 	(sizeof (i_softmac_ether_si) / sizeof (i_softmac_ether_si[0]))
176 
177 static kstat_t	*softmac_hold_dev_kstat(softmac_t *);
178 static void	softmac_rele_dev_kstat(kstat_t *);
179 static int	softmac_get_kstat(kstat_t *, char *, uint64_t *);
180 
181 static kstat_t *
182 softmac_hold_dev_kstat(softmac_t *softmac)
183 {
184 	char		drv[MAXLINKNAMELEN];
185 	uint_t		ppa;
186 	kstat_t		*ksp;
187 
188 	if (ddi_parse_dlen(softmac->smac_devname, drv, MAXLINKNAMELEN, &ppa) !=
189 	    DDI_SUCCESS) {
190 		return (NULL);
191 	}
192 
193 	/*
194 	 * Find the kstat by the module name and the instance number.
195 	 */
196 	ksp = kstat_hold_byname(drv, ppa, softmac->smac_devname, ALL_ZONES);
197 	if (ksp != NULL) {
198 		KSTAT_ENTER(ksp);
199 
200 		if ((ksp->ks_data != NULL) &&
201 		    (ksp->ks_type == KSTAT_TYPE_NAMED)) {
202 			/*
203 			 * Update the kstat to get the latest statistics.
204 			 */
205 			if (KSTAT_UPDATE(ksp, KSTAT_READ) == 0)
206 				return (ksp);
207 		}
208 
209 		KSTAT_EXIT(ksp);
210 		kstat_rele(ksp);
211 	}
212 	return (NULL);
213 }
214 
215 static void
216 softmac_rele_dev_kstat(kstat_t *ksp)
217 {
218 	KSTAT_EXIT(ksp);
219 	kstat_rele(ksp);
220 }
221 
222 /*
223  * The kstat needs to be held when calling this function.
224  */
225 static int
226 softmac_get_kstat(kstat_t *ksp, char *name, uint64_t *valp)
227 {
228 	kstat_named_t	*knp;
229 	int		i;
230 	int		ret = ENOTSUP;
231 
232 	if (name == NULL)
233 		return (ret);
234 
235 	/*
236 	 * Search the kstat with the given name.
237 	 */
238 	for (i = 0, knp = KSTAT_NAMED_PTR(ksp); i < ksp->ks_ndata; i++, knp++) {
239 		if (strcmp(knp->name, name) == 0) {
240 			switch (knp->data_type) {
241 			case KSTAT_DATA_INT32:
242 			case KSTAT_DATA_UINT32:
243 				*valp = (uint64_t)(knp->value.ui32);
244 				ret = 0;
245 				break;
246 			case KSTAT_DATA_INT64:
247 			case KSTAT_DATA_UINT64:
248 				*valp = knp->value.ui64;
249 				ret = 0;
250 				break;
251 #ifdef _LP64
252 			case KSTAT_DATA_LONG:
253 			case KSTAT_DATA_ULONG:
254 				*valp = (uint64_t)knp->value.ul;
255 				ret = 0;
256 				break;
257 #endif
258 			case KSTAT_DATA_CHAR:
259 				if (strcmp(name, "duplex") != 0)
260 					break;
261 				if (strncmp(knp->value.c, "full", 4) == 0)
262 					*valp = LINK_DUPLEX_FULL;
263 				else if (strncmp(knp->value.c, "half", 4) == 0)
264 					*valp = LINK_DUPLEX_HALF;
265 				else
266 					*valp = LINK_DUPLEX_UNKNOWN;
267 				ret = 0;
268 				break;
269 			}
270 			break;
271 		}
272 	}
273 
274 	return (ret);
275 }
276 
277 int
278 softmac_m_stat(void *arg, uint_t stat, uint64_t *val)
279 {
280 	softmac_t	*softmac = arg;
281 	kstat_t		*ksp;
282 	uint_t		index;
283 	int		ret;
284 
285 	if ((ksp = softmac_hold_dev_kstat(softmac)) == NULL)
286 		return (ENOTSUP);
287 
288 	if (IS_MAC_STAT(stat)) {
289 		i_softmac_stat_info_t *ssip = NULL;
290 
291 		for (index = 0; index < SOFTMAC_DRIVER_SI_SZ; index++) {
292 			if (stat == i_softmac_driver_si[index].ssi_stat) {
293 				ssip = &i_softmac_driver_si[index];
294 				break;
295 			}
296 		}
297 
298 		if (ssip == NULL) {
299 			ret = ENOTSUP;
300 		} else {
301 			if ((ret = softmac_get_kstat(ksp, ssip->ssi_name,
302 			    val)) != 0)
303 				ret = softmac_get_kstat(ksp, ssip->ssi_alias,
304 				    val);
305 		}
306 	} else {
307 		ASSERT(IS_MACTYPE_STAT(stat));
308 
309 		switch (softmac->smac_media) {
310 		case DL_ETHER: {
311 			i_softmac_stat_info_t *ssip = NULL;
312 
313 			for (index = 0; index < SOFTMAC_ETHER_SI_SZ; index++) {
314 				if (stat ==
315 				    i_softmac_ether_si[index].ssi_stat) {
316 					ssip = &i_softmac_ether_si[index];
317 					break;
318 				}
319 			}
320 
321 			if (ssip == NULL) {
322 				ret = ENOTSUP;
323 			} else {
324 				if ((ret = softmac_get_kstat(ksp,
325 				    ssip->ssi_name, val)) != 0)
326 					ret = softmac_get_kstat(ksp,
327 					    ssip->ssi_alias, val);
328 			}
329 
330 			break;
331 		}
332 		default:
333 			ret = ENOTSUP;
334 			break;
335 		}
336 	}
337 
338 	softmac_rele_dev_kstat(ksp);
339 	return (ret);
340 }
341