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