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 2009 Emulex. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Source file containing the implementation of the driver statistics 29 * and related helper functions 30 */ 31 32 #include <oce_impl.h> 33 #include <oce_stat.h> 34 #include <oce_buf.h> 35 36 /* 37 * function called by kstat to update the stats counters 38 * 39 * ksp - pointer to the kstats structure 40 * rw - flags defining read/write 41 * 42 * return DDI_SUCCESS => success, failure otherwise 43 */ 44 static int 45 oce_update_stats(kstat_t *ksp, int rw) 46 { 47 struct oce_dev *dev; 48 struct oce_stat *stats; 49 struct rx_port_stats *port_stats; 50 clock_t new; 51 boolean_t is_update_stats = B_FALSE; 52 int ret; 53 54 if (rw == KSTAT_WRITE) { 55 return (EACCES); 56 } 57 58 dev = ksp->ks_private; 59 stats = (struct oce_stat *)ksp->ks_data; 60 port_stats = &dev->hw_stats->params.rsp.rx.port[dev->port_id]; 61 62 mutex_enter(&dev->dev_lock); 63 if (dev->suspended) { 64 mutex_exit(&dev->dev_lock); 65 return (EIO); 66 } 67 68 /* 69 * allow stats update only if enough 70 * time has elapsed since last update 71 */ 72 new = ddi_get_lbolt(); 73 if ((new - dev->stat_ticks) >= drv_usectohz(STAT_TIMEOUT)) { 74 dev->stat_ticks = new; 75 is_update_stats = B_TRUE; 76 } 77 78 mutex_exit(&dev->dev_lock); 79 80 /* fetch the latest stats from the adapter */ 81 if (is_update_stats) { 82 if (dev->in_stats) { 83 return (EIO); 84 } else { 85 atomic_add_32(&dev->in_stats, 1); 86 ret = oce_get_hw_stats(dev); 87 atomic_add_32(&dev->in_stats, -1); 88 if (ret != DDI_SUCCESS) { 89 oce_log(dev, CE_WARN, MOD_CONFIG, 90 "Failed to get stats:%d", ret); 91 return (EIO); 92 } 93 } 94 } 95 96 /* update the stats */ 97 stats->rx_bytes_lo.value.ul = port_stats->rx_bytes_lsd; 98 stats->rx_bytes_hi.value.ul = port_stats->rx_bytes_msd; 99 100 stats->rx_frames.value.ul = port_stats->rx_total_frames; 101 stats->rx_errors.value.ul = port_stats->rx_crc_errors + 102 port_stats->rx_alignment_symbol_errors + 103 port_stats->rx_in_range_errors + 104 port_stats->rx_out_range_errors + 105 port_stats->rx_frame_too_long + 106 port_stats->rx_ip_checksum_errs + 107 port_stats->rx_tcp_checksum_errs + 108 port_stats->rx_udp_checksum_errs; 109 110 stats->rx_drops.value.ul = port_stats->rx_dropped_too_small + 111 port_stats->rx_dropped_too_short + 112 port_stats->rx_dropped_header_too_small + 113 port_stats->rx_dropped_tcp_length + 114 port_stats->rx_dropped_runt; 115 116 stats->tx_bytes_lo.value.ul = port_stats->tx_bytes_lsd; 117 stats->tx_bytes_hi.value.ul = port_stats->tx_bytes_msd; 118 119 stats->tx_frames.value.ul = port_stats->tx_unicast_frames + 120 port_stats->tx_multicast_frames + 121 port_stats->tx_broadcast_frames + 122 port_stats->tx_pause_frames + 123 port_stats->tx_control_frames; 124 stats->tx_errors.value.ul = dev->tx_errors; 125 126 stats->rx_unicast_frames.value.ul = 127 port_stats->rx_unicast_frames; 128 stats->rx_multicast_frames.value.ul = 129 port_stats->rx_multicast_frames; 130 stats->rx_broadcast_frames.value.ul = 131 port_stats->rx_broadcast_frames; 132 stats->rx_crc_errors.value.ul = 133 port_stats->rx_crc_errors; 134 135 stats->rx_alignment_symbol_errors.value.ul = 136 port_stats->rx_alignment_symbol_errors; 137 stats->rx_in_range_errors.value.ul = 138 port_stats->rx_in_range_errors; 139 stats->rx_out_range_errors.value.ul = 140 port_stats->rx_out_range_errors; 141 stats->rx_frame_too_long.value.ul = 142 port_stats->rx_frame_too_long; 143 stats->rx_address_match_errors.value.ul = 144 port_stats->rx_address_match_errors; 145 146 stats->rx_pause_frames.value.ul = 147 port_stats->rx_pause_frames; 148 stats->rx_control_frames.value.ul = 149 port_stats->rx_control_frames; 150 stats->rx_ip_checksum_errs.value.ul = 151 port_stats->rx_ip_checksum_errs; 152 stats->rx_tcp_checksum_errs.value.ul = 153 port_stats->rx_tcp_checksum_errs; 154 stats->rx_udp_checksum_errs.value.ul = 155 port_stats->rx_udp_checksum_errs; 156 stats->rx_fifo_overflow.value.ul = port_stats->rx_fifo_overflow; 157 stats->rx_input_fifo_overflow.value.ul = 158 port_stats->rx_input_fifo_overflow; 159 160 stats->tx_unicast_frames.value.ul = 161 port_stats->tx_unicast_frames; 162 stats->tx_multicast_frames.value.ul = 163 port_stats->tx_multicast_frames; 164 stats->tx_broadcast_frames.value.ul = 165 port_stats->tx_broadcast_frames; 166 stats->tx_pause_frames.value.ul = 167 port_stats->tx_pause_frames; 168 stats->tx_control_frames.value.ul = 169 port_stats->tx_control_frames; 170 return (DDI_SUCCESS); 171 } /* oce_update_stats */ 172 173 /* 174 * function to setup the kstat_t structure for the device and install it 175 * 176 * dev - software handle to the device 177 * 178 * return DDI_SUCCESS => success, failure otherwise 179 */ 180 int 181 oce_stat_init(struct oce_dev *dev) 182 { 183 struct oce_stat *stats; 184 uint32_t num_stats = sizeof (struct oce_stat) / 185 sizeof (kstat_named_t); 186 187 /* allocate the kstat */ 188 dev->oce_kstats = kstat_create(OCE_MOD_NAME, dev->dev_id, "stats", 189 "net", KSTAT_TYPE_NAMED, 190 num_stats, 0); 191 if (dev->oce_kstats == NULL) { 192 oce_log(dev, CE_NOTE, MOD_CONFIG, 193 "kstat creation failed: 0x%p", 194 (void *)dev->oce_kstats); 195 return (DDI_FAILURE); 196 } 197 198 /* allocate the device copy of the stats */ 199 dev->stats_dbuf = oce_alloc_dma_buffer(dev, 200 sizeof (struct mbx_get_nic_stats), 201 DDI_DMA_CONSISTENT); 202 if (dev->stats_dbuf == NULL) { 203 oce_log(dev, CE_NOTE, MOD_CONFIG, 204 "Could not allocate stats_dbuf: %p", 205 (void *)dev->stats_dbuf); 206 kstat_delete(dev->oce_kstats); 207 return (DDI_FAILURE); 208 } 209 dev->hw_stats = (struct mbx_get_nic_stats *)DBUF_VA(dev->stats_dbuf); 210 211 /* initialize the counters */ 212 stats = (struct oce_stat *)dev->oce_kstats->ks_data; 213 kstat_named_init(&stats->rx_bytes_hi, "rx bytes msd", KSTAT_DATA_ULONG); 214 kstat_named_init(&stats->rx_bytes_lo, "rx bytes lsd", KSTAT_DATA_ULONG); 215 216 kstat_named_init(&stats->rx_frames, "rx frames", KSTAT_DATA_ULONG); 217 kstat_named_init(&stats->rx_errors, "rx errors", KSTAT_DATA_ULONG); 218 kstat_named_init(&stats->rx_drops, "rx drops", KSTAT_DATA_ULONG); 219 220 kstat_named_init(&stats->tx_bytes_hi, "tx bytes msd", KSTAT_DATA_ULONG); 221 kstat_named_init(&stats->tx_bytes_lo, "tx bytes lsd", KSTAT_DATA_ULONG); 222 223 kstat_named_init(&stats->tx_frames, "tx frames", KSTAT_DATA_ULONG); 224 kstat_named_init(&stats->tx_errors, "tx errors", KSTAT_DATA_ULONG); 225 226 kstat_named_init(&stats->rx_unicast_frames, 227 "rx unicast frames", KSTAT_DATA_ULONG); 228 kstat_named_init(&stats->rx_multicast_frames, 229 "rx multicast frames", KSTAT_DATA_ULONG); 230 kstat_named_init(&stats->rx_broadcast_frames, 231 "rx broadcast frames", KSTAT_DATA_ULONG); 232 kstat_named_init(&stats->rx_crc_errors, 233 "rx crc errors", KSTAT_DATA_ULONG); 234 235 kstat_named_init(&stats->rx_alignment_symbol_errors, 236 "rx alignment symbol errors", KSTAT_DATA_ULONG); 237 kstat_named_init(&stats->rx_in_range_errors, 238 "rx in range errors", KSTAT_DATA_ULONG); 239 kstat_named_init(&stats->rx_out_range_errors, 240 "rx out range errors", KSTAT_DATA_ULONG); 241 kstat_named_init(&stats->rx_frame_too_long, 242 "rx frame too long", KSTAT_DATA_ULONG); 243 kstat_named_init(&stats->rx_address_match_errors, 244 "rx address match errors", KSTAT_DATA_ULONG); 245 246 kstat_named_init(&stats->rx_pause_frames, 247 "rx pause frames", KSTAT_DATA_ULONG); 248 kstat_named_init(&stats->rx_control_frames, 249 "rx control frames", KSTAT_DATA_ULONG); 250 kstat_named_init(&stats->rx_ip_checksum_errs, 251 "rx ip checksum errors", KSTAT_DATA_ULONG); 252 kstat_named_init(&stats->rx_tcp_checksum_errs, 253 "rx tcp checksum errors", KSTAT_DATA_ULONG); 254 kstat_named_init(&stats->rx_udp_checksum_errs, 255 "rx udp checksum errors", KSTAT_DATA_ULONG); 256 kstat_named_init(&stats->rx_fifo_overflow, 257 "rx fifo overflow", KSTAT_DATA_ULONG); 258 kstat_named_init(&stats->rx_input_fifo_overflow, 259 "rx input fifo overflow", KSTAT_DATA_ULONG); 260 261 kstat_named_init(&stats->tx_unicast_frames, 262 "tx unicast frames", KSTAT_DATA_ULONG); 263 kstat_named_init(&stats->tx_multicast_frames, 264 "tx multicast frames", KSTAT_DATA_ULONG); 265 kstat_named_init(&stats->tx_broadcast_frames, 266 "tx broadcast frames", KSTAT_DATA_ULONG); 267 kstat_named_init(&stats->tx_pause_frames, 268 "tx pause frames", KSTAT_DATA_ULONG); 269 kstat_named_init(&stats->tx_control_frames, 270 "tx control frames", KSTAT_DATA_ULONG); 271 272 dev->oce_kstats->ks_update = oce_update_stats; 273 dev->oce_kstats->ks_private = (void *)dev; 274 kstat_install(dev->oce_kstats); 275 276 return (DDI_SUCCESS); 277 } /* oce_stat_init */ 278 279 /* 280 * function to undo initialization done in oce_stat_init 281 * 282 * dev - software handle to the device 283 * 284 * return none 285 */ 286 void 287 oce_stat_fini(struct oce_dev *dev) 288 { 289 oce_free_dma_buffer(dev, dev->stats_dbuf); 290 dev->hw_stats = NULL; 291 dev->stats_dbuf = NULL; 292 kstat_delete(dev->oce_kstats); 293 dev->oce_kstats = NULL; 294 } /* oce_stat_fini */ 295 296 /* 297 * GLDv3 entry for statistic query 298 */ 299 int 300 oce_m_stat(void *arg, uint_t stat, uint64_t *val) 301 { 302 struct oce_dev *dev = arg; 303 struct oce_stat *stats; 304 struct rx_port_stats *port_stats; 305 boolean_t is_update_stats = B_FALSE; 306 clock_t new; 307 308 stats = (struct oce_stat *)dev->oce_kstats->ks_data; 309 port_stats = &dev->hw_stats->params.rsp.rx.port[dev->port_id]; 310 311 mutex_enter(&dev->dev_lock); 312 313 if (dev->suspended || 314 (dev->state & STATE_MAC_STOPPING) || 315 !(dev->state & STATE_MAC_STARTED)) { 316 mutex_exit(&dev->dev_lock); 317 return (EIO); 318 } 319 320 /* 321 * allow stats update only if enough 322 * time has elapsed since last update 323 */ 324 new = ddi_get_lbolt(); 325 if ((new - dev->stat_ticks) >= drv_usectohz(STAT_TIMEOUT)) { 326 dev->stat_ticks = new; 327 is_update_stats = B_TRUE; 328 } 329 mutex_exit(&dev->dev_lock); 330 331 /* update hw stats. Required for netstat */ 332 if (is_update_stats) { 333 if (dev->in_stats == 0) { 334 atomic_add_32(&dev->in_stats, 1); 335 (void) oce_get_hw_stats(dev); 336 atomic_add_32(&dev->in_stats, -1); 337 } 338 } 339 340 switch (stat) { 341 case MAC_STAT_IFSPEED: 342 if (dev->state & STATE_MAC_STARTED) 343 *val = 10000000000ull; 344 else 345 *val = 0; 346 break; 347 348 case MAC_STAT_RBYTES: 349 stats->rx_bytes_lo.value.ul = port_stats->rx_bytes_lsd; 350 stats->rx_bytes_hi.value.ul = port_stats->rx_bytes_msd; 351 *val = (uint64_t)stats->rx_bytes_hi.value.ul << 32 | 352 (uint64_t)stats->rx_bytes_lo.value.ul; 353 break; 354 355 case MAC_STAT_IPACKETS: 356 stats->rx_frames.value.ul = port_stats->rx_total_frames; 357 *val = stats->rx_frames.value.ul; 358 break; 359 360 case MAC_STAT_OBYTES: 361 stats->tx_bytes_lo.value.ul = port_stats->tx_bytes_lsd; 362 stats->tx_bytes_hi.value.ul = port_stats->tx_bytes_msd; 363 *val = (uint64_t)stats->tx_bytes_hi.value.ul << 32 | 364 (uint64_t)stats->tx_bytes_lo.value.ul; 365 break; 366 367 case MAC_STAT_OPACKETS: 368 stats->tx_frames.value.ul = port_stats->tx_unicast_frames + 369 port_stats->tx_multicast_frames + 370 port_stats->tx_broadcast_frames + 371 port_stats->tx_pause_frames + 372 port_stats->tx_control_frames; 373 *val = stats->tx_frames.value.ul; 374 break; 375 376 case MAC_STAT_BRDCSTRCV: 377 stats->rx_broadcast_frames.value.ul = 378 port_stats->rx_broadcast_frames; 379 *val = stats->rx_broadcast_frames.value.ul; 380 break; 381 382 case MAC_STAT_MULTIRCV: 383 stats->rx_multicast_frames.value.ul = 384 port_stats->rx_multicast_frames; 385 *val = stats->rx_multicast_frames.value.ul; 386 break; 387 388 case MAC_STAT_MULTIXMT: 389 stats->tx_multicast_frames.value.ul = 390 port_stats->tx_multicast_frames; 391 *val = stats->tx_multicast_frames.value.ul; 392 break; 393 394 case MAC_STAT_BRDCSTXMT: 395 stats->tx_broadcast_frames.value.ul = 396 port_stats->tx_broadcast_frames; 397 *val = stats->tx_broadcast_frames.value.ul; 398 break; 399 400 case MAC_STAT_NORCVBUF: 401 stats->rx_fifo_overflow.value.ul = 402 port_stats->rx_fifo_overflow; 403 *val = stats->rx_fifo_overflow.value.ul; 404 break; 405 406 case MAC_STAT_IERRORS: 407 stats->rx_errors.value.ul = port_stats->rx_crc_errors + 408 port_stats->rx_alignment_symbol_errors + 409 port_stats->rx_in_range_errors + 410 port_stats->rx_out_range_errors + 411 port_stats->rx_frame_too_long + 412 port_stats->rx_ip_checksum_errs + 413 port_stats->rx_tcp_checksum_errs + 414 port_stats->rx_udp_checksum_errs; 415 *val = stats->rx_errors.value.ul; 416 break; 417 418 case MAC_STAT_NOXMTBUF: 419 *val = dev->tx_noxmtbuf; 420 break; 421 422 case MAC_STAT_OERRORS: 423 *val = stats->tx_errors.value.ul; 424 break; 425 426 case ETHER_STAT_LINK_DUPLEX: 427 if (dev->state & STATE_MAC_STARTED) 428 *val = LINK_DUPLEX_FULL; 429 else 430 *val = LINK_DUPLEX_UNKNOWN; 431 break; 432 433 case ETHER_STAT_ALIGN_ERRORS: 434 stats->rx_alignment_symbol_errors.value.ul = 435 port_stats->rx_alignment_symbol_errors; 436 *val = port_stats->rx_alignment_symbol_errors; 437 break; 438 439 case ETHER_STAT_FCS_ERRORS: 440 stats->rx_crc_errors.value.ul = 441 port_stats->rx_crc_errors; 442 *val = port_stats->rx_crc_errors; 443 break; 444 445 case ETHER_STAT_MACRCV_ERRORS: 446 stats->rx_errors.value.ul = port_stats->rx_crc_errors + 447 port_stats->rx_alignment_symbol_errors + 448 port_stats->rx_in_range_errors + 449 port_stats->rx_out_range_errors + 450 port_stats->rx_frame_too_long + 451 port_stats->rx_ip_checksum_errs + 452 port_stats->rx_tcp_checksum_errs + 453 port_stats->rx_udp_checksum_errs; 454 455 *val = stats->rx_errors.value.ul; 456 break; 457 458 case ETHER_STAT_MACXMT_ERRORS: 459 *val = stats->tx_errors.value.ul; 460 break; 461 462 case ETHER_STAT_TOOLONG_ERRORS: 463 stats->rx_frame_too_long.value.ul = 464 port_stats->rx_frame_too_long; 465 *val = port_stats->rx_frame_too_long; 466 break; 467 468 case ETHER_STAT_CAP_PAUSE: 469 case ETHER_STAT_LINK_PAUSE: 470 if (dev->flow_control & OCE_FC_TX && 471 dev->flow_control & OCE_FC_RX) 472 *val = LINK_FLOWCTRL_BI; 473 else if (dev->flow_control == OCE_FC_TX) 474 *val = LINK_FLOWCTRL_TX; 475 else if (dev->flow_control == OCE_FC_RX) 476 *val = LINK_FLOWCTRL_RX; 477 else if (dev->flow_control == 0) 478 *val = LINK_FLOWCTRL_NONE; 479 break; 480 481 default: 482 return (ENOTSUP); 483 } 484 return (0); 485 } /* oce_m_stat */ 486