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
36int 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 */
52static int
53oce_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 */
166int
167oce_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 */
272void
273oce_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 */
285int
286oce_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