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