1/*
2 * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
3 * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
4 * Copyright (c) 2009 HNR Consulting.  All rights reserved.
5 * Copyright (c) 2011 Mellanox Technologies LTD.  All rights reserved.
6 *
7 * This software is available to you under a choice of one of two
8 * licenses.  You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
12 *
13 *     Redistribution and use in source and binary forms, with or
14 *     without modification, are permitted provided that the following
15 *     conditions are met:
16 *
17 *      - Redistributions of source code must retain the above
18 *        copyright notice, this list of conditions and the following
19 *        disclaimer.
20 *
21 *      - Redistributions in binary form must reproduce the above
22 *        copyright notice, this list of conditions and the following
23 *        disclaimer in the documentation and/or other materials
24 *        provided with the distribution.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE.
34 *
35 */
36
37#if HAVE_CONFIG_H
38#  include <config.h>
39#endif				/* HAVE_CONFIG_H */
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <unistd.h>
44#include <getopt.h>
45#include <netinet/in.h>
46
47#include <infiniband/umad.h>
48#include <infiniband/mad.h>
49#include <infiniband/iba/ib_types.h>
50
51#include "ibdiag_common.h"
52
53struct ibmad_port *srcport;
54
55static ibmad_gid_t dgid;
56static int with_grh;
57
58struct perf_count {
59	uint32_t portselect;
60	uint32_t counterselect;
61	uint32_t symbolerrors;
62	uint32_t linkrecovers;
63	uint32_t linkdowned;
64	uint32_t rcverrors;
65	uint32_t rcvremotephyerrors;
66	uint32_t rcvswrelayerrors;
67	uint32_t xmtdiscards;
68	uint32_t xmtconstrainterrors;
69	uint32_t rcvconstrainterrors;
70	uint32_t linkintegrityerrors;
71	uint32_t excbufoverrunerrors;
72	uint32_t qp1dropped;
73	uint32_t vl15dropped;
74	uint32_t xmtdata;
75	uint32_t rcvdata;
76	uint32_t xmtpkts;
77	uint32_t rcvpkts;
78	uint32_t xmtwait;
79};
80
81struct perf_count_ext {
82	uint32_t portselect;
83	uint32_t counterselect;
84	uint64_t portxmitdata;
85	uint64_t portrcvdata;
86	uint64_t portxmitpkts;
87	uint64_t portrcvpkts;
88	uint64_t portunicastxmitpkts;
89	uint64_t portunicastrcvpkts;
90	uint64_t portmulticastxmitpkits;
91	uint64_t portmulticastrcvpkts;
92
93	uint32_t counterSelect2;
94	uint64_t symbolErrorCounter;
95	uint64_t linkErrorRecoveryCounter;
96	uint64_t linkDownedCounter;
97	uint64_t portRcvErrors;
98	uint64_t portRcvRemotePhysicalErrors;
99	uint64_t portRcvSwitchRelayErrors;
100	uint64_t portXmitDiscards;
101	uint64_t portXmitConstraintErrors;
102	uint64_t portRcvConstraintErrors;
103	uint64_t localLinkIntegrityErrors;
104	uint64_t excessiveBufferOverrunErrors;
105	uint64_t VL15Dropped;
106	uint64_t portXmitWait;
107	uint64_t QP1Dropped;
108};
109
110static uint8_t pc[1024];
111
112struct perf_count perf_count = {0};
113struct perf_count_ext perf_count_ext = {0};
114
115#define ALL_PORTS 0xFF
116#define MAX_PORTS 255
117
118/* Notes: IB semantics is to cap counters if count has exceeded limits.
119 * Therefore we must check for overflows and cap the counters if necessary.
120 *
121 * mad_decode_field and mad_encode_field assume 32 bit integers passed in
122 * for fields < 32 bits in length.
123 */
124
125static void aggregate_4bit(uint32_t * dest, uint32_t val)
126{
127	if ((((*dest) + val) < (*dest)) || ((*dest) + val) > 0xf)
128		(*dest) = 0xf;
129	else
130		(*dest) = (*dest) + val;
131}
132
133static void aggregate_8bit(uint32_t * dest, uint32_t val)
134{
135	if ((((*dest) + val) < (*dest))
136	    || ((*dest) + val) > 0xff)
137		(*dest) = 0xff;
138	else
139		(*dest) = (*dest) + val;
140}
141
142static void aggregate_16bit(uint32_t * dest, uint32_t val)
143{
144	if ((((*dest) + val) < (*dest))
145	    || ((*dest) + val) > 0xffff)
146		(*dest) = 0xffff;
147	else
148		(*dest) = (*dest) + val;
149}
150
151static void aggregate_32bit(uint32_t * dest, uint32_t val)
152{
153	if (((*dest) + val) < (*dest))
154		(*dest) = 0xffffffff;
155	else
156		(*dest) = (*dest) + val;
157}
158
159static void aggregate_64bit(uint64_t * dest, uint64_t val)
160{
161	if (((*dest) + val) < (*dest))
162		(*dest) = 0xffffffffffffffffULL;
163	else
164		(*dest) = (*dest) + val;
165}
166
167static void aggregate_perfcounters(void)
168{
169	uint32_t val;
170
171	mad_decode_field(pc, IB_PC_PORT_SELECT_F, &val);
172	perf_count.portselect = val;
173	mad_decode_field(pc, IB_PC_COUNTER_SELECT_F, &val);
174	perf_count.counterselect = val;
175	mad_decode_field(pc, IB_PC_ERR_SYM_F, &val);
176	aggregate_16bit(&perf_count.symbolerrors, val);
177	mad_decode_field(pc, IB_PC_LINK_RECOVERS_F, &val);
178	aggregate_8bit(&perf_count.linkrecovers, val);
179	mad_decode_field(pc, IB_PC_LINK_DOWNED_F, &val);
180	aggregate_8bit(&perf_count.linkdowned, val);
181	mad_decode_field(pc, IB_PC_ERR_RCV_F, &val);
182	aggregate_16bit(&perf_count.rcverrors, val);
183	mad_decode_field(pc, IB_PC_ERR_PHYSRCV_F, &val);
184	aggregate_16bit(&perf_count.rcvremotephyerrors, val);
185	mad_decode_field(pc, IB_PC_ERR_SWITCH_REL_F, &val);
186	aggregate_16bit(&perf_count.rcvswrelayerrors, val);
187	mad_decode_field(pc, IB_PC_XMT_DISCARDS_F, &val);
188	aggregate_16bit(&perf_count.xmtdiscards, val);
189	mad_decode_field(pc, IB_PC_ERR_XMTCONSTR_F, &val);
190	aggregate_8bit(&perf_count.xmtconstrainterrors, val);
191	mad_decode_field(pc, IB_PC_ERR_RCVCONSTR_F, &val);
192	aggregate_8bit(&perf_count.rcvconstrainterrors, val);
193	mad_decode_field(pc, IB_PC_ERR_LOCALINTEG_F, &val);
194	aggregate_4bit(&perf_count.linkintegrityerrors, val);
195	mad_decode_field(pc, IB_PC_ERR_EXCESS_OVR_F, &val);
196	aggregate_4bit(&perf_count.excbufoverrunerrors, val);
197#ifdef HAVE_IB_PC_QP1_DROP_F
198	mad_decode_field(pc, IB_PC_QP1_DROP_F, &val);
199	aggregate_16bit(&perf_count.qp1dropped, val);
200#endif
201	mad_decode_field(pc, IB_PC_VL15_DROPPED_F, &val);
202	aggregate_16bit(&perf_count.vl15dropped, val);
203	mad_decode_field(pc, IB_PC_XMT_BYTES_F, &val);
204	aggregate_32bit(&perf_count.xmtdata, val);
205	mad_decode_field(pc, IB_PC_RCV_BYTES_F, &val);
206	aggregate_32bit(&perf_count.rcvdata, val);
207	mad_decode_field(pc, IB_PC_XMT_PKTS_F, &val);
208	aggregate_32bit(&perf_count.xmtpkts, val);
209	mad_decode_field(pc, IB_PC_RCV_PKTS_F, &val);
210	aggregate_32bit(&perf_count.rcvpkts, val);
211	mad_decode_field(pc, IB_PC_XMT_WAIT_F, &val);
212	aggregate_32bit(&perf_count.xmtwait, val);
213}
214
215static void output_aggregate_perfcounters(ib_portid_t * portid,
216					  uint16_t cap_mask)
217{
218	char buf[1024];
219	uint32_t val = ALL_PORTS;
220
221	/* set port_select to 255 to emulate AllPortSelect */
222	mad_encode_field(pc, IB_PC_PORT_SELECT_F, &val);
223	mad_encode_field(pc, IB_PC_COUNTER_SELECT_F, &perf_count.counterselect);
224	mad_encode_field(pc, IB_PC_ERR_SYM_F, &perf_count.symbolerrors);
225	mad_encode_field(pc, IB_PC_LINK_RECOVERS_F, &perf_count.linkrecovers);
226	mad_encode_field(pc, IB_PC_LINK_DOWNED_F, &perf_count.linkdowned);
227	mad_encode_field(pc, IB_PC_ERR_RCV_F, &perf_count.rcverrors);
228	mad_encode_field(pc, IB_PC_ERR_PHYSRCV_F,
229			 &perf_count.rcvremotephyerrors);
230	mad_encode_field(pc, IB_PC_ERR_SWITCH_REL_F,
231			 &perf_count.rcvswrelayerrors);
232	mad_encode_field(pc, IB_PC_XMT_DISCARDS_F, &perf_count.xmtdiscards);
233	mad_encode_field(pc, IB_PC_ERR_XMTCONSTR_F,
234			 &perf_count.xmtconstrainterrors);
235	mad_encode_field(pc, IB_PC_ERR_RCVCONSTR_F,
236			 &perf_count.rcvconstrainterrors);
237	mad_encode_field(pc, IB_PC_ERR_LOCALINTEG_F,
238			 &perf_count.linkintegrityerrors);
239	mad_encode_field(pc, IB_PC_ERR_EXCESS_OVR_F,
240			 &perf_count.excbufoverrunerrors);
241#ifdef HAVE_IB_PC_QP1_DROP_F
242	mad_encode_field(pc, IB_PC_QP1_DROP_F, &perf_count.qp1dropped);
243#endif
244	mad_encode_field(pc, IB_PC_VL15_DROPPED_F, &perf_count.vl15dropped);
245	mad_encode_field(pc, IB_PC_XMT_BYTES_F, &perf_count.xmtdata);
246	mad_encode_field(pc, IB_PC_RCV_BYTES_F, &perf_count.rcvdata);
247	mad_encode_field(pc, IB_PC_XMT_PKTS_F, &perf_count.xmtpkts);
248	mad_encode_field(pc, IB_PC_RCV_PKTS_F, &perf_count.rcvpkts);
249	mad_encode_field(pc, IB_PC_XMT_WAIT_F, &perf_count.xmtwait);
250
251	mad_dump_perfcounters(buf, sizeof buf, pc, sizeof pc);
252
253	printf("# Port counters: %s port %d (CapMask: 0x%02X)\n%s",
254	       portid2str(portid), ALL_PORTS, ntohs(cap_mask), buf);
255}
256
257static void aggregate_perfcounters_ext(uint16_t cap_mask, uint32_t cap_mask2)
258{
259	uint32_t val;
260	uint64_t val64;
261
262	mad_decode_field(pc, IB_PC_EXT_PORT_SELECT_F, &val);
263	perf_count_ext.portselect = val;
264	mad_decode_field(pc, IB_PC_EXT_COUNTER_SELECT_F, &val);
265	perf_count_ext.counterselect = val;
266	mad_decode_field(pc, IB_PC_EXT_XMT_BYTES_F, &val64);
267	aggregate_64bit(&perf_count_ext.portxmitdata, val64);
268	mad_decode_field(pc, IB_PC_EXT_RCV_BYTES_F, &val64);
269	aggregate_64bit(&perf_count_ext.portrcvdata, val64);
270	mad_decode_field(pc, IB_PC_EXT_XMT_PKTS_F, &val64);
271	aggregate_64bit(&perf_count_ext.portxmitpkts, val64);
272	mad_decode_field(pc, IB_PC_EXT_RCV_PKTS_F, &val64);
273	aggregate_64bit(&perf_count_ext.portrcvpkts, val64);
274
275	if (cap_mask & IB_PM_EXT_WIDTH_SUPPORTED) {
276		mad_decode_field(pc, IB_PC_EXT_XMT_UPKTS_F, &val64);
277		aggregate_64bit(&perf_count_ext.portunicastxmitpkts, val64);
278		mad_decode_field(pc, IB_PC_EXT_RCV_UPKTS_F, &val64);
279		aggregate_64bit(&perf_count_ext.portunicastrcvpkts, val64);
280		mad_decode_field(pc, IB_PC_EXT_XMT_MPKTS_F, &val64);
281		aggregate_64bit(&perf_count_ext.portmulticastxmitpkits, val64);
282		mad_decode_field(pc, IB_PC_EXT_RCV_MPKTS_F, &val64);
283		aggregate_64bit(&perf_count_ext.portmulticastrcvpkts, val64);
284	}
285
286	if (htonl(cap_mask2) & IB_PM_IS_ADDL_PORT_CTRS_EXT_SUP) {
287		mad_decode_field(pc, IB_PC_EXT_COUNTER_SELECT2_F, &val);
288		perf_count_ext.counterSelect2 = val;
289		mad_decode_field(pc, IB_PC_EXT_ERR_SYM_F, &val64);
290		aggregate_64bit(&perf_count_ext.symbolErrorCounter, val64);
291		mad_decode_field(pc, IB_PC_EXT_LINK_RECOVERS_F, &val64);
292		aggregate_64bit(&perf_count_ext.linkErrorRecoveryCounter, val64);
293		mad_decode_field(pc, IB_PC_EXT_LINK_DOWNED_F, &val64);
294		aggregate_64bit(&perf_count_ext.linkDownedCounter, val64);
295		mad_decode_field(pc, IB_PC_EXT_ERR_RCV_F, &val64);
296		aggregate_64bit(&perf_count_ext.portRcvErrors, val64);
297		mad_decode_field(pc, IB_PC_EXT_ERR_PHYSRCV_F, &val64);
298		aggregate_64bit(&perf_count_ext.portRcvRemotePhysicalErrors, val64);
299		mad_decode_field(pc, IB_PC_EXT_ERR_SWITCH_REL_F, &val64);
300		aggregate_64bit(&perf_count_ext.portRcvSwitchRelayErrors, val64);
301		mad_decode_field(pc, IB_PC_EXT_XMT_DISCARDS_F, &val64);
302		aggregate_64bit(&perf_count_ext.portXmitDiscards, val64);
303		mad_decode_field(pc, IB_PC_EXT_ERR_XMTCONSTR_F, &val64);
304		aggregate_64bit(&perf_count_ext.portXmitConstraintErrors, val64);
305		mad_decode_field(pc, IB_PC_EXT_ERR_RCVCONSTR_F, &val64);
306		aggregate_64bit(&perf_count_ext.portRcvConstraintErrors, val64);
307		mad_decode_field(pc, IB_PC_EXT_ERR_LOCALINTEG_F, &val64);
308		aggregate_64bit(&perf_count_ext.localLinkIntegrityErrors, val64);
309		mad_decode_field(pc, IB_PC_EXT_ERR_EXCESS_OVR_F, &val64);
310		aggregate_64bit(&perf_count_ext.excessiveBufferOverrunErrors, val64);
311		mad_decode_field(pc, IB_PC_EXT_VL15_DROPPED_F, &val64);
312		aggregate_64bit(&perf_count_ext.VL15Dropped, val64);
313		mad_decode_field(pc, IB_PC_EXT_XMT_WAIT_F, &val64);
314		aggregate_64bit(&perf_count_ext.portXmitWait, val64);
315		mad_decode_field(pc, IB_PC_EXT_QP1_DROP_F, &val64);
316		aggregate_64bit(&perf_count_ext.QP1Dropped, val64);
317	}
318}
319
320static void output_aggregate_perfcounters_ext(ib_portid_t * portid,
321					      uint16_t cap_mask, uint32_t cap_mask2)
322{
323	char buf[1536];
324	uint32_t val = ALL_PORTS;
325
326	memset(buf, 0, sizeof(buf));
327
328	/* set port_select to 255 to emulate AllPortSelect */
329	mad_encode_field(pc, IB_PC_EXT_PORT_SELECT_F, &val);
330	mad_encode_field(pc, IB_PC_EXT_COUNTER_SELECT_F,
331			 &perf_count_ext.counterselect);
332	mad_encode_field(pc, IB_PC_EXT_XMT_BYTES_F,
333			 &perf_count_ext.portxmitdata);
334	mad_encode_field(pc, IB_PC_EXT_RCV_BYTES_F,
335			 &perf_count_ext.portrcvdata);
336	mad_encode_field(pc, IB_PC_EXT_XMT_PKTS_F,
337			 &perf_count_ext.portxmitpkts);
338	mad_encode_field(pc, IB_PC_EXT_RCV_PKTS_F, &perf_count_ext.portrcvpkts);
339
340	if (cap_mask & IB_PM_EXT_WIDTH_SUPPORTED) {
341		mad_encode_field(pc, IB_PC_EXT_XMT_UPKTS_F,
342				 &perf_count_ext.portunicastxmitpkts);
343		mad_encode_field(pc, IB_PC_EXT_RCV_UPKTS_F,
344				 &perf_count_ext.portunicastrcvpkts);
345		mad_encode_field(pc, IB_PC_EXT_XMT_MPKTS_F,
346				 &perf_count_ext.portmulticastxmitpkits);
347		mad_encode_field(pc, IB_PC_EXT_RCV_MPKTS_F,
348				 &perf_count_ext.portmulticastrcvpkts);
349	}
350
351	if (htonl(cap_mask2) & IB_PM_IS_ADDL_PORT_CTRS_EXT_SUP) {
352		mad_encode_field(pc, IB_PC_EXT_COUNTER_SELECT2_F,
353				 &perf_count_ext.counterSelect2);
354		mad_encode_field(pc, IB_PC_EXT_ERR_SYM_F,
355				 &perf_count_ext.symbolErrorCounter);
356		mad_encode_field(pc, IB_PC_EXT_LINK_RECOVERS_F,
357				 &perf_count_ext.linkErrorRecoveryCounter);
358		mad_encode_field(pc, IB_PC_EXT_LINK_DOWNED_F,
359				 &perf_count_ext.linkDownedCounter);
360		mad_encode_field(pc, IB_PC_EXT_ERR_RCV_F,
361				 &perf_count_ext.portRcvErrors);
362		mad_encode_field(pc, IB_PC_EXT_ERR_PHYSRCV_F,
363				 &perf_count_ext.portRcvRemotePhysicalErrors);
364		mad_encode_field(pc, IB_PC_EXT_ERR_SWITCH_REL_F,
365				 &perf_count_ext.portRcvSwitchRelayErrors);
366		mad_encode_field(pc, IB_PC_EXT_XMT_DISCARDS_F,
367				 &perf_count_ext.portXmitDiscards);
368		mad_encode_field(pc, IB_PC_EXT_ERR_XMTCONSTR_F,
369				 &perf_count_ext.portXmitConstraintErrors);
370		mad_encode_field(pc, IB_PC_EXT_ERR_RCVCONSTR_F,
371				 &perf_count_ext.portRcvConstraintErrors);
372		mad_encode_field(pc, IB_PC_EXT_ERR_LOCALINTEG_F,
373				 &perf_count_ext.localLinkIntegrityErrors);
374		mad_encode_field(pc, IB_PC_EXT_ERR_EXCESS_OVR_F,
375				 &perf_count_ext.excessiveBufferOverrunErrors);
376		mad_encode_field(pc, IB_PC_EXT_VL15_DROPPED_F,
377				 &perf_count_ext.VL15Dropped);
378		mad_encode_field(pc, IB_PC_EXT_XMT_WAIT_F,
379				 &perf_count_ext.portXmitWait);
380		mad_encode_field(pc, IB_PC_EXT_QP1_DROP_F,
381				 &perf_count_ext.QP1Dropped);
382	}
383
384	mad_dump_perfcounters_ext(buf, sizeof buf, pc, sizeof pc);
385
386	printf("# Port extended counters: %s port %d (CapMask: 0x%02X CapMask2: 0x%07X)\n%s",
387	       portid2str(portid), ALL_PORTS, ntohs(cap_mask), cap_mask2, buf);
388}
389
390static void dump_perfcounters(int extended, int timeout, uint16_t cap_mask,
391			      uint32_t cap_mask2, ib_portid_t * portid,
392			      int port, int aggregate)
393{
394	char buf[1536];
395
396	if (extended != 1) {
397		memset(pc, 0, sizeof(pc));
398		if (!pma_query_via(pc, portid, port, timeout,
399				   IB_GSI_PORT_COUNTERS, srcport))
400			IBEXIT("perfquery");
401		if (!(cap_mask & IB_PM_PC_XMIT_WAIT_SUP)) {
402			/* if PortCounters:PortXmitWait not supported clear this counter */
403			VERBOSE("PortXmitWait not indicated"
404				" so ignore this counter");
405			perf_count.xmtwait = 0;
406			mad_encode_field(pc, IB_PC_XMT_WAIT_F,
407					 &perf_count.xmtwait);
408		}
409		if (aggregate)
410			aggregate_perfcounters();
411		else {
412#ifdef HAVE_IB_PC_QP1_DROP_F
413			mad_dump_perfcounters(buf, sizeof buf, pc, sizeof pc);
414#else
415			mad_dump_fields(buf, sizeof buf, pc, sizeof pc,
416							IB_PC_FIRST_F,
417							(cap_mask & IB_PM_PC_XMIT_WAIT_SUP)?IB_PC_LAST_F:(IB_PC_RCV_PKTS_F+1));
418#endif
419		}
420	} else {
421		/* 1.2 errata: bit 9 is extended counter support
422		 * bit 10 is extended counter NoIETF
423		 */
424		if (!(cap_mask & IB_PM_EXT_WIDTH_SUPPORTED) &&
425		    !(cap_mask & IB_PM_EXT_WIDTH_NOIETF_SUP))
426			IBWARN
427			    ("PerfMgt ClassPortInfo CapMask 0x%02X; No extended counter support indicated\n",
428			     ntohs(cap_mask));
429
430		memset(pc, 0, sizeof(pc));
431		if (!pma_query_via(pc, portid, port, timeout,
432				   IB_GSI_PORT_COUNTERS_EXT, srcport))
433			IBEXIT("perfextquery");
434		if (aggregate)
435			aggregate_perfcounters_ext(cap_mask, cap_mask2);
436		else
437			mad_dump_perfcounters_ext(buf, sizeof buf, pc,
438						  sizeof pc);
439	}
440
441	if (!aggregate) {
442		if (extended)
443			printf("# Port extended counters: %s port %d "
444			       "(CapMask: 0x%02X CapMask2: 0x%07X)\n%s",
445			       portid2str(portid), port, ntohs(cap_mask),
446			       cap_mask2, buf);
447		else
448			printf("# Port counters: %s port %d "
449			       "(CapMask: 0x%02X)\n%s",
450			       portid2str(portid), port, ntohs(cap_mask), buf);
451	}
452}
453
454static void reset_counters(int extended, int timeout, int mask,
455			   ib_portid_t * portid, int port)
456{
457	memset(pc, 0, sizeof(pc));
458	if (extended != 1) {
459		if (!performance_reset_via(pc, portid, port, mask, timeout,
460					   IB_GSI_PORT_COUNTERS, srcport))
461			IBEXIT("perf reset");
462	} else {
463		if (!performance_reset_via(pc, portid, port, mask, timeout,
464					   IB_GSI_PORT_COUNTERS_EXT, srcport))
465			IBEXIT("perf ext reset");
466	}
467}
468
469static int reset, reset_only, all_ports, loop_ports, port, extended, xmt_sl,
470    rcv_sl, xmt_disc, rcv_err, extended_speeds, smpl_ctl, oprcvcounters, flowctlcounters,
471    vloppackets, vlopdata, vlxmitflowctlerrors, vlxmitcounters, swportvlcong,
472    rcvcc, slrcvfecn, slrcvbecn, xmitcc, vlxmittimecc;
473static int ports[MAX_PORTS];
474static int ports_count;
475
476static void common_func(ib_portid_t * portid, int port_num, int mask,
477			unsigned query, unsigned reset,
478			const char *name, uint16_t attr,
479			void dump_func(char *, int, void *, int))
480{
481	char buf[1536];
482
483	if (query) {
484		memset(pc, 0, sizeof(pc));
485		if (!pma_query_via(pc, portid, port_num, ibd_timeout, attr,
486				   srcport))
487			IBEXIT("cannot query %s", name);
488
489		dump_func(buf, sizeof(buf), pc, sizeof(pc));
490
491		printf("# %s counters: %s port %d\n%s", name,
492		       portid2str(portid), port_num, buf);
493	}
494
495	memset(pc, 0, sizeof(pc));
496	if (reset && !performance_reset_via(pc, portid, port, mask, ibd_timeout,
497					    attr, srcport))
498		IBEXIT("cannot reset %s", name);
499}
500
501static void xmt_sl_query(ib_portid_t * portid, int port, int mask)
502{
503	common_func(portid, port, mask, !reset_only, (reset_only || reset),
504		    "PortXmitDataSL", IB_GSI_PORT_XMIT_DATA_SL,
505		    mad_dump_perfcounters_xmt_sl);
506}
507
508static void rcv_sl_query(ib_portid_t * portid, int port, int mask)
509{
510	common_func(portid, port, mask, !reset_only, (reset_only || reset),
511		    "PortRcvDataSL", IB_GSI_PORT_RCV_DATA_SL,
512		    mad_dump_perfcounters_rcv_sl);
513}
514
515static void xmt_disc_query(ib_portid_t * portid, int port, int mask)
516{
517	common_func(portid, port, mask, !reset_only, (reset_only || reset),
518		    "PortXmitDiscardDetails", IB_GSI_PORT_XMIT_DISCARD_DETAILS,
519		    mad_dump_perfcounters_xmt_disc);
520}
521
522static void rcv_err_query(ib_portid_t * portid, int port, int mask)
523{
524	common_func(portid, port, mask, !reset_only, (reset_only || reset),
525		    "PortRcvErrorDetails", IB_GSI_PORT_RCV_ERROR_DETAILS,
526		    mad_dump_perfcounters_rcv_err);
527}
528
529static uint8_t *ext_speeds_reset_via(void *rcvbuf, ib_portid_t * dest,
530				     int port, uint64_t mask, unsigned timeout,
531				     const struct ibmad_port * srcport)
532{
533	ib_rpc_t rpc = { 0 };
534	int lid = dest->lid;
535
536	DEBUG("lid %u port %d mask 0x%" PRIx64, lid, port, mask);
537
538	if (lid == -1) {
539		IBWARN("only lid routed is supported");
540		return NULL;
541	}
542
543	if (!mask)
544		mask = ~0;
545
546	rpc.mgtclass = IB_PERFORMANCE_CLASS;
547	rpc.method = IB_MAD_METHOD_SET;
548	rpc.attr.id = IB_GSI_PORT_EXT_SPEEDS_COUNTERS;
549
550	memset(rcvbuf, 0, IB_MAD_SIZE);
551
552	mad_set_field(rcvbuf, 0, IB_PESC_PORT_SELECT_F, port);
553	mad_set_field64(rcvbuf, 0, IB_PESC_COUNTER_SELECT_F, mask);
554	rpc.attr.mod = 0;
555	rpc.timeout = timeout;
556	rpc.datasz = IB_PC_DATA_SZ;
557	rpc.dataoffs = IB_PC_DATA_OFFS;
558	if (!dest->qp)
559		dest->qp = 1;
560	if (!dest->qkey)
561		dest->qkey = IB_DEFAULT_QP1_QKEY;
562
563	return mad_rpc(srcport, &rpc, dest, rcvbuf, rcvbuf);
564}
565
566static uint8_t is_rsfec_mode_active(ib_portid_t * portid, int port,
567				  uint16_t cap_mask)
568{
569	uint8_t data[IB_SMP_DATA_SIZE] = { 0 };
570	uint32_t fec_mode_active = 0;
571	uint32_t pie_capmask = 0;
572	if (cap_mask & IS_PM_RSFEC_COUNTERS_SUP) {
573		if (!is_port_info_extended_supported(portid, port, srcport)) {
574			IBWARN("Port Info Extended not supported");
575			return 0;
576		}
577
578		if (!smp_query_via(data, portid, IB_ATTR_PORT_INFO_EXT, port, 0,
579				   srcport))
580			IBEXIT("smp query portinfo extended failed");
581
582		mad_decode_field(data, IB_PORT_EXT_CAPMASK_F, &pie_capmask);
583		mad_decode_field(data, IB_PORT_EXT_FEC_MODE_ACTIVE_F,
584				 &fec_mode_active);
585		if((pie_capmask &
586		    CL_NTOH32(IB_PORT_EXT_CAP_IS_FEC_MODE_SUPPORTED)) &&
587		   (CL_NTOH16(IB_PORT_EXT_RS_FEC_MODE_ACTIVE) == (fec_mode_active & 0xffff)))
588			return 1;
589	}
590
591	return 0;
592}
593
594static void extended_speeds_query(ib_portid_t * portid, int port,
595				  uint64_t ext_mask, uint16_t cap_mask)
596{
597	int mask = ext_mask;
598
599	if (!reset_only) {
600		if (is_rsfec_mode_active(portid, port, cap_mask))
601			common_func(portid, port, mask, 1, 0,
602				    "PortExtendedSpeedsCounters with RS-FEC Active",
603				    IB_GSI_PORT_EXT_SPEEDS_COUNTERS,
604				    mad_dump_port_ext_speeds_counters_rsfec_active);
605		else
606			common_func(portid, port, mask, 1, 0,
607			    "PortExtendedSpeedsCounters",
608			    IB_GSI_PORT_EXT_SPEEDS_COUNTERS,
609			    mad_dump_port_ext_speeds_counters);
610	}
611
612	if ((reset_only || reset) &&
613	    !ext_speeds_reset_via(pc, portid, port, ext_mask, ibd_timeout, srcport))
614		IBEXIT("cannot reset PortExtendedSpeedsCounters");
615}
616
617static void oprcvcounters_query(ib_portid_t * portid, int port, int mask)
618{
619	common_func(portid, port, mask, !reset_only, (reset_only || reset),
620		    "PortOpRcvCounters", IB_GSI_PORT_PORT_OP_RCV_COUNTERS,
621		    mad_dump_perfcounters_port_op_rcv_counters);
622}
623
624static void flowctlcounters_query(ib_portid_t * portid, int port, int mask)
625{
626	common_func(portid, port, mask, !reset_only, (reset_only || reset),
627		    "PortFlowCtlCounters", IB_GSI_PORT_PORT_FLOW_CTL_COUNTERS,
628		    mad_dump_perfcounters_port_flow_ctl_counters);
629}
630
631static void vloppackets_query(ib_portid_t * portid, int port, int mask)
632{
633	common_func(portid, port, mask, !reset_only, (reset_only || reset),
634		    "PortVLOpPackets", IB_GSI_PORT_PORT_VL_OP_PACKETS,
635		    mad_dump_perfcounters_port_vl_op_packet);
636}
637
638static void vlopdata_query(ib_portid_t * portid, int port, int mask)
639{
640	common_func(portid, port, mask, !reset_only, (reset_only || reset),
641		    "PortVLOpData", IB_GSI_PORT_PORT_VL_OP_DATA,
642		    mad_dump_perfcounters_port_vl_op_data);
643}
644
645static void vlxmitflowctlerrors_query(ib_portid_t * portid, int port, int mask)
646{
647	common_func(portid, port, mask, !reset_only, (reset_only || reset),
648		    "PortVLXmitFlowCtlUpdateErrors", IB_GSI_PORT_PORT_VL_XMIT_FLOW_CTL_UPDATE_ERRORS,
649		    mad_dump_perfcounters_port_vl_xmit_flow_ctl_update_errors);
650}
651
652static void vlxmitcounters_query(ib_portid_t * portid, int port, int mask)
653{
654	common_func(portid, port, mask, !reset_only, (reset_only || reset),
655		    "PortVLXmitWaitCounters", IB_GSI_PORT_PORT_VL_XMIT_WAIT_COUNTERS,
656		    mad_dump_perfcounters_port_vl_xmit_wait_counters);
657}
658
659static void swportvlcong_query(ib_portid_t * portid, int port, int mask)
660{
661	common_func(portid, port, mask, !reset_only, (reset_only || reset),
662		    "SwPortVLCongestion", IB_GSI_SW_PORT_VL_CONGESTION,
663		    mad_dump_perfcounters_sw_port_vl_congestion);
664}
665
666static void rcvcc_query(ib_portid_t * portid, int port, int mask)
667{
668	common_func(portid, port, mask, !reset_only, (reset_only || reset),
669		    "PortRcvConCtrl", IB_GSI_PORT_RCV_CON_CTRL,
670		    mad_dump_perfcounters_rcv_con_ctrl);
671}
672
673static void slrcvfecn_query(ib_portid_t * portid, int port, int mask)
674{
675	common_func(portid, port, mask, !reset_only, (reset_only || reset),
676		    "PortSLRcvFECN", IB_GSI_PORT_SL_RCV_FECN,
677		    mad_dump_perfcounters_sl_rcv_fecn);
678}
679
680static void slrcvbecn_query(ib_portid_t * portid, int port, int mask)
681{
682	common_func(portid, port, mask, !reset_only, (reset_only || reset),
683		    "PortSLRcvBECN", IB_GSI_PORT_SL_RCV_BECN,
684		    mad_dump_perfcounters_sl_rcv_becn);
685}
686
687static void xmitcc_query(ib_portid_t * portid, int port, int mask)
688{
689	common_func(portid, port, mask, !reset_only, (reset_only || reset),
690		    "PortXmitConCtrl", IB_GSI_PORT_XMIT_CON_CTRL,
691		    mad_dump_perfcounters_xmit_con_ctrl);
692}
693
694static void vlxmittimecc_query(ib_portid_t * portid, int port, int mask)
695{
696	common_func(portid, port, mask, !reset_only, (reset_only || reset),
697		    "PortVLXmitTimeCong", IB_GSI_PORT_VL_XMIT_TIME_CONG,
698		    mad_dump_perfcounters_vl_xmit_time_cong);
699}
700
701void dump_portsamples_control(ib_portid_t * portid, int port)
702{
703	char buf[1280];
704
705	memset(pc, 0, sizeof(pc));
706	if (!pma_query_via(pc, portid, port, ibd_timeout,
707			   IB_GSI_PORT_SAMPLES_CONTROL, srcport))
708		IBEXIT("sampctlquery");
709
710	mad_dump_portsamples_control(buf, sizeof buf, pc, sizeof pc);
711	printf("# PortSamplesControl: %s port %d\n%s", portid2str(portid),
712	       port, buf);
713}
714
715static int process_opt(void *context, int ch, char *optarg)
716{
717	switch (ch) {
718	case 'x':
719		extended = 1;
720		break;
721	case 'X':
722		xmt_sl = 1;
723		break;
724	case 'S':
725		rcv_sl = 1;
726		break;
727	case 'D':
728		xmt_disc = 1;
729		break;
730	case 'E':
731		rcv_err = 1;
732		break;
733	case 'T':
734		extended_speeds = 1;
735		break;
736	case 'c':
737		smpl_ctl = 1;
738		break;
739	case 1:
740		oprcvcounters = 1;
741		break;
742	case 2:
743		flowctlcounters = 1;
744		break;
745	case 3:
746		vloppackets = 1;
747		break;
748	case 4:
749		vlopdata = 1;
750		break;
751	case 5:
752		vlxmitflowctlerrors = 1;
753		break;
754	case 6:
755		vlxmitcounters = 1;
756		break;
757	case 7:
758		swportvlcong = 1;
759		break;
760	case 8:
761		rcvcc = 1;
762		break;
763	case 9:
764		slrcvfecn = 1;
765		break;
766	case 10:
767		slrcvbecn = 1;
768		break;
769	case 11:
770		xmitcc = 1;
771		break;
772	case 12:
773		vlxmittimecc = 1;
774		break;
775	case 'a':
776		all_ports++;
777		port = ALL_PORTS;
778		break;
779	case 'l':
780		loop_ports++;
781		break;
782	case 'r':
783		reset++;
784		break;
785	case 'R':
786		reset_only++;
787		break;
788	case 25:
789		if (!inet_pton(AF_INET6, optarg, &dgid)) {
790			fprintf(stderr, "dgid format is wrong!\n");
791			ibdiag_show_usage();
792			return 1;
793		}
794		with_grh = 1;
795		break;
796	default:
797		return -1;
798	}
799	return 0;
800}
801
802int main(int argc, char **argv)
803{
804	int mgmt_classes[3] = { IB_SMI_CLASS, IB_SA_CLASS, IB_PERFORMANCE_CLASS };
805	ib_portid_t portid = { 0 };
806	int mask = 0xffff;
807	uint64_t ext_mask = 0xffffffffffffffffULL;
808	uint32_t cap_mask2;
809	uint16_t cap_mask;
810	int all_ports_loop = 0;
811	int node_type, num_ports = 0;
812	uint8_t data[IB_SMP_DATA_SIZE] = { 0 };
813	int start_port = 1;
814	int enhancedport0;
815	char *tmpstr;
816	int i;
817
818	const struct ibdiag_opt opts[] = {
819		{"extended", 'x', 0, NULL, "show extended port counters"},
820		{"xmtsl", 'X', 0, NULL, "show Xmt SL port counters"},
821		{"rcvsl", 'S', 0, NULL, "show Rcv SL port counters"},
822		{"xmtdisc", 'D', 0, NULL, "show Xmt Discard Details"},
823		{"rcverr", 'E', 0, NULL, "show Rcv Error Details"},
824		{"extended_speeds", 'T', 0, NULL, "show port extended speeds counters"},
825		{"oprcvcounters", 1, 0, NULL, "show Rcv Counters per Op code"},
826		{"flowctlcounters", 2, 0, NULL, "show flow control counters"},
827		{"vloppackets", 3, 0, NULL, "show packets received per Op code per VL"},
828		{"vlopdata", 4, 0, NULL, "show data received per Op code per VL"},
829		{"vlxmitflowctlerrors", 5, 0, NULL, "show flow control update errors per VL"},
830		{"vlxmitcounters", 6, 0, NULL, "show ticks waiting to transmit counters per VL"},
831		{"swportvlcong", 7, 0, NULL, "show sw port VL congestion"},
832		{"rcvcc", 8, 0, NULL, "show Rcv congestion control counters"},
833		{"slrcvfecn", 9, 0, NULL, "show SL Rcv FECN counters"},
834		{"slrcvbecn", 10, 0, NULL, "show SL Rcv BECN counters"},
835		{"xmitcc", 11, 0, NULL, "show Xmit congestion control counters"},
836		{"vlxmittimecc", 12, 0, NULL, "show VL Xmit Time congestion control counters"},
837		{"smplctl", 'c', 0, NULL, "show samples control"},
838		{"all_ports", 'a', 0, NULL, "show aggregated counters"},
839		{"loop_ports", 'l', 0, NULL, "iterate through each port"},
840		{"reset_after_read", 'r', 0, NULL, "reset counters after read"},
841		{"Reset_only", 'R', 0, NULL, "only reset counters"},
842		{"dgid", 25, 1, NULL, "remote gid (IPv6 format)"},
843		{0}
844	};
845	char usage_args[] = " [<lid|guid> [[port(s)] [reset_mask]]]";
846	const char *usage_examples[] = {
847		"\t\t# read local port's performance counters",
848		"32 1\t\t# read performance counters from lid 32, port 1",
849		"-x 32 1\t# read extended performance counters from lid 32, port 1",
850		"-a 32\t\t# read performance counters from lid 32, all ports",
851		"-r 32 1\t# read performance counters and reset",
852		"-x -r 32 1\t# read extended performance counters and reset",
853		"-R 0x20 1\t# reset performance counters of port 1 only",
854		"-x -R 0x20 1\t# reset extended performance counters of port 1 only",
855		"-R -a 32\t# reset performance counters of all ports",
856		"-R 32 2 0x0fff\t# reset only error counters of port 2",
857		"-R 32 2 0xf000\t# reset only non-error counters of port 2",
858		"-a 32 1-10\t# read performance counters from lid 32, port 1-10, aggregate output",
859		"-l 32 1-10\t# read performance counters from lid 32, port 1-10, output each port",
860		"-a 32 1,4,8\t# read performance counters from lid 32, port 1, 4, and 8, aggregate output",
861		"-l 32 1,4,8\t# read performance counters from lid 32, port 1, 4, and 8, output each port",
862		NULL,
863	};
864
865	ibdiag_process_opts(argc, argv, NULL, "DK", opts, process_opt,
866			    usage_args, usage_examples);
867
868	argc -= optind;
869	argv += optind;
870
871	if (argc > 1) {
872		if (strchr(argv[1], ',')) {
873			tmpstr = strtok(argv[1], ",");
874			while (tmpstr) {
875				ports[ports_count++] = strtoul(tmpstr, 0, 0);
876				tmpstr = strtok(NULL, ",");
877			}
878			port = ports[0];
879		}
880		else if ((tmpstr = strchr(argv[1], '-'))) {
881			int pmin, pmax;
882
883			*tmpstr = '\0';
884			tmpstr++;
885
886			pmin = strtoul(argv[1], 0, 0);
887			pmax = strtoul(tmpstr, 0, 0);
888
889			if (pmin >= pmax)
890				IBEXIT("max port must be greater than min port in range");
891
892			while (pmin <= pmax)
893				ports[ports_count++] = pmin++;
894
895			port = ports[0];
896		}
897		else
898			port = strtoul(argv[1], 0, 0);
899	}
900	if (argc > 2) {
901		ext_mask = strtoull(argv[2], 0, 0);
902		mask = ext_mask;
903	}
904
905	srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3);
906	if (!srcport)
907		IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port);
908
909	smp_mkey_set(srcport, ibd_mkey);
910
911	if (argc) {
912		if (with_grh && ibd_dest_type != IB_DEST_LID)
913			IBEXIT("When using GRH, LID should be provided");
914		if (resolve_portid_str(ibd_ca, ibd_ca_port, &portid, argv[0],
915				       ibd_dest_type, ibd_sm_id, srcport) < 0)
916			IBEXIT("can't resolve destination port %s", argv[0]);
917		if (with_grh) {
918			portid.grh_present = 1;
919			memcpy(&portid.gid, &dgid, sizeof(portid.gid));
920		}
921	} else {
922		if (resolve_self(ibd_ca, ibd_ca_port, &portid, &port, 0) < 0)
923			IBEXIT("can't resolve self port %s", argv[0]);
924	}
925
926	/* PerfMgt ClassPortInfo is a required attribute */
927	memset(pc, 0, sizeof(pc));
928	if (!pma_query_via(pc, &portid, port, ibd_timeout, CLASS_PORT_INFO,
929			   srcport))
930		IBEXIT("classportinfo query");
931	/* ClassPortInfo should be supported as part of libibmad */
932	memcpy(&cap_mask, pc + 2, sizeof(cap_mask));	/* CapabilityMask */
933	memcpy(&cap_mask2, pc + 4, sizeof(cap_mask2));	/* CapabilityMask2 */
934	cap_mask2 = ntohl(cap_mask2) >> 5;
935
936	if (!(cap_mask & IB_PM_ALL_PORT_SELECT)) {	/* bit 8 is AllPortSelect */
937		if (!all_ports && port == ALL_PORTS)
938			IBEXIT("AllPortSelect not supported");
939		if (all_ports && port == ALL_PORTS)
940			all_ports_loop = 1;
941	}
942
943	if (xmt_sl) {
944		xmt_sl_query(&portid, port, mask);
945		goto done;
946	}
947
948	if (rcv_sl) {
949		rcv_sl_query(&portid, port, mask);
950		goto done;
951	}
952
953	if (xmt_disc) {
954		xmt_disc_query(&portid, port, mask);
955		goto done;
956	}
957
958	if (rcv_err) {
959		rcv_err_query(&portid, port, mask);
960		goto done;
961	}
962
963	if (extended_speeds) {
964		extended_speeds_query(&portid, port, ext_mask, cap_mask);
965		goto done;
966	}
967
968	if (oprcvcounters) {
969		oprcvcounters_query(&portid, port, mask);
970		goto done;
971	}
972
973	if (flowctlcounters) {
974		flowctlcounters_query(&portid, port, mask);
975		goto done;
976	}
977
978	if (vloppackets) {
979		vloppackets_query(&portid, port, mask);
980		goto done;
981	}
982
983	if (vlopdata) {
984		vlopdata_query(&portid, port, mask);
985		goto done;
986	}
987
988	if (vlxmitflowctlerrors) {
989		vlxmitflowctlerrors_query(&portid, port, mask);
990		goto done;
991	}
992
993	if (vlxmitcounters) {
994		vlxmitcounters_query(&portid, port, mask);
995		goto done;
996	}
997
998	if (swportvlcong) {
999		swportvlcong_query(&portid, port, mask);
1000		goto done;
1001	}
1002
1003	if (rcvcc) {
1004		rcvcc_query(&portid, port, mask);
1005		goto done;
1006	}
1007
1008	if (slrcvfecn) {
1009		slrcvfecn_query(&portid, port, mask);
1010		goto done;
1011	}
1012
1013	if (slrcvbecn) {
1014		slrcvbecn_query(&portid, port, mask);
1015		goto done;
1016	}
1017
1018	if (xmitcc) {
1019		xmitcc_query(&portid, port, mask);
1020		goto done;
1021	}
1022
1023	if (vlxmittimecc) {
1024		vlxmittimecc_query(&portid, port, mask);
1025		goto done;
1026	}
1027
1028	if (smpl_ctl) {
1029		dump_portsamples_control(&portid, port);
1030		goto done;
1031	}
1032
1033
1034	if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) {
1035		if (!smp_query_via(data, &portid, IB_ATTR_NODE_INFO, 0, 0,
1036				   srcport))
1037			IBEXIT("smp query nodeinfo failed");
1038		node_type = mad_get_field(data, 0, IB_NODE_TYPE_F);
1039		mad_decode_field(data, IB_NODE_NPORTS_F, &num_ports);
1040		if (!num_ports)
1041			IBEXIT("smp query nodeinfo: num ports invalid");
1042
1043		if (node_type == IB_NODE_SWITCH) {
1044			if (!smp_query_via(data, &portid, IB_ATTR_SWITCH_INFO,
1045					   0, 0, srcport))
1046				IBEXIT("smp query nodeinfo failed");
1047			enhancedport0 =
1048			    mad_get_field(data, 0, IB_SW_ENHANCED_PORT0_F);
1049			if (enhancedport0)
1050				start_port = 0;
1051		}
1052		if (all_ports_loop && !loop_ports)
1053			IBWARN
1054			    ("Emulating AllPortSelect by iterating through all ports");
1055	}
1056
1057	if (reset_only)
1058		goto do_reset;
1059
1060	if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) {
1061		for (i = start_port; i <= num_ports; i++)
1062			dump_perfcounters(extended, ibd_timeout,
1063					  cap_mask, cap_mask2,
1064					  &portid, i, (all_ports_loop
1065						       && !loop_ports));
1066		if (all_ports_loop && !loop_ports) {
1067			if (extended != 1)
1068				output_aggregate_perfcounters(&portid,
1069							      cap_mask);
1070			else
1071				output_aggregate_perfcounters_ext(&portid,
1072								  cap_mask, cap_mask2);
1073		}
1074	} else if (ports_count > 1) {
1075		for (i = 0; i < ports_count; i++)
1076			dump_perfcounters(extended, ibd_timeout, cap_mask,
1077					  cap_mask2, &portid, ports[i],
1078					  (all_ports && !loop_ports));
1079		if (all_ports && !loop_ports) {
1080			if (extended != 1)
1081				output_aggregate_perfcounters(&portid,
1082							      cap_mask);
1083			else
1084				output_aggregate_perfcounters_ext(&portid,
1085								  cap_mask, cap_mask2);
1086		}
1087	} else
1088		dump_perfcounters(extended, ibd_timeout, cap_mask, cap_mask2,
1089				  &portid, port, 0);
1090
1091	if (!reset)
1092		goto done;
1093
1094do_reset:
1095	if (argc <= 2 && !extended) {
1096		if (cap_mask & IB_PM_PC_XMIT_WAIT_SUP)
1097			mask |= (1 << 16);	/* reset portxmitwait */
1098		if (cap_mask & IB_PM_IS_QP1_DROP_SUP)
1099			mask |= (1 << 17);	/* reset qp1dropped */
1100	}
1101
1102	if (extended) {
1103		mask |= 0xfff0000;
1104		if (cap_mask & IB_PM_PC_XMIT_WAIT_SUP)
1105			mask |= (1 << 28);
1106		if (cap_mask & IB_PM_IS_QP1_DROP_SUP)
1107			mask |= (1 << 29);
1108	}
1109
1110	if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) {
1111		for (i = start_port; i <= num_ports; i++)
1112			reset_counters(extended, ibd_timeout, mask, &portid, i);
1113	} else if (ports_count > 1) {
1114		for (i = 0; i < ports_count; i++)
1115			reset_counters(extended, ibd_timeout, mask, &portid, ports[i]);
1116	} else
1117		reset_counters(extended, ibd_timeout, mask, &portid, port);
1118
1119done:
1120	mad_rpc_close_port(srcport);
1121	exit(0);
1122}
1123