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