xref: /freebsd/contrib/ofed/infiniband-diags/src/perfquery.c (revision 5f4c09dd85bff675e0ca63c55ea3c517e0fddfcc)
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 
53 struct ibmad_port *srcport;
54 
55 static ibmad_gid_t dgid;
56 static int with_grh;
57 
58 struct 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 
81 struct 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 
110 static uint8_t pc[1024];
111 
112 struct perf_count perf_count = {0};
113 struct 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 
125 static 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 
133 static 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 
142 static 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 
151 static 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 
159 static 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 
167 static 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 
215 static 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 
257 static 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 
320 static 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 
390 static 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 
454 static 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 
469 static 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;
473 static int ports[MAX_PORTS];
474 static int ports_count;
475 
476 static 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 
501 static 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 
508 static 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 
515 static 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 
522 static 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 
529 static 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 
566 static 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 
594 static 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 
617 static 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 
624 static 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 
631 static 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 
638 static 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 
645 static 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 
652 static 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 
659 static 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 
666 static 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 
673 static 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 
680 static 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 
687 static 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 
694 static 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 
701 void 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 
715 static 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 
802 int 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 
1094 do_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 
1119 done:
1120 	mad_rpc_close_port(srcport);
1121 	exit(0);
1122 }
1123