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 *
softmac_hold_dev_kstat(softmac_t * softmac)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
softmac_rele_dev_kstat(kstat_t * ksp)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
softmac_get_kstat(kstat_t * ksp,char * name,uint64_t * valp)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
softmac_m_stat(void * arg,uint_t stat,uint64_t * val)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