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