1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
3219820Sjeff *
4219820Sjeff * This software is available to you under a choice of one of two
5219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
6219820Sjeff * General Public License (GPL) Version 2, available from the file
7219820Sjeff * COPYING in the main directory of this source tree, or the
8219820Sjeff * OpenIB.org BSD license below:
9219820Sjeff *
10219820Sjeff *     Redistribution and use in source and binary forms, with or
11219820Sjeff *     without modification, are permitted provided that the following
12219820Sjeff *     conditions are met:
13219820Sjeff *
14219820Sjeff *      - Redistributions of source code must retain the above
15219820Sjeff *        copyright notice, this list of conditions and the following
16219820Sjeff *        disclaimer.
17219820Sjeff *
18219820Sjeff *      - Redistributions in binary form must reproduce the above
19219820Sjeff *        copyright notice, this list of conditions and the following
20219820Sjeff *        disclaimer in the documentation and/or other materials
21219820Sjeff *        provided with the distribution.
22219820Sjeff *
23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30219820Sjeff * SOFTWARE.
31219820Sjeff *
32219820Sjeff */
33219820Sjeff
34219820Sjeff#if HAVE_CONFIG_H
35219820Sjeff#  include <config.h>
36219820Sjeff#endif /* HAVE_CONFIG_H */
37219820Sjeff
38219820Sjeff#include <stdio.h>
39219820Sjeff#include <stdlib.h>
40219820Sjeff#include <unistd.h>
41219820Sjeff#include <stdarg.h>
42219820Sjeff#include <time.h>
43219820Sjeff#include <string.h>
44219820Sjeff#include <getopt.h>
45219820Sjeff#include <netinet/in.h>
46219820Sjeff
47219820Sjeff#define __STDC_FORMAT_MACROS
48219820Sjeff#include <inttypes.h>
49219820Sjeff
50219820Sjeff#include <infiniband/common.h>
51219820Sjeff#include <infiniband/umad.h>
52219820Sjeff#include <infiniband/mad.h>
53219820Sjeff#include <infiniband/complib/cl_nodenamemap.h>
54219820Sjeff
55219820Sjeff#include "ibdiag_common.h"
56219820Sjeff
57219820Sjeff#undef DEBUG
58219820Sjeff#define	DEBUG	if (verbose>1) IBWARN
59219820Sjeff
60219820Sjeffstatic int dest_type = IB_DEST_LID;
61219820Sjeffstatic int verbose;
62219820Sjeff
63219820Sjefftypedef char *(op_fn_t)(ib_portid_t *dest, char **argv, int argc);
64219820Sjeff
65219820Sjefftypedef struct match_rec {
66219820Sjeff	char *name;
67219820Sjeff	op_fn_t *fn;
68219820Sjeff	unsigned opt_portnum;
69219820Sjeff} match_rec_t;
70219820Sjeff
71219820Sjeffstatic op_fn_t	node_desc, node_info, port_info, switch_info, pkey_table,
72219820Sjeff	sl2vl_table, vlarb_table, guid_info;
73219820Sjeff
74219820Sjeffstatic const match_rec_t match_tbl[] = {
75219820Sjeff	{ "nodeinfo", node_info },
76219820Sjeff	{ "nodedesc", node_desc },
77219820Sjeff	{ "portinfo", port_info, 1 },
78219820Sjeff	{ "switchinfo", switch_info },
79219820Sjeff	{ "pkeys", pkey_table, 1 },
80219820Sjeff	{ "sl2vl", sl2vl_table, 1 },
81219820Sjeff	{ "vlarb", vlarb_table, 1 },
82219820Sjeff	{ "guids", guid_info },
83219820Sjeff	{0}
84219820Sjeff};
85219820Sjeff
86219820Sjeffchar *argv0 = "smpquery";
87219820Sjeffstatic char *node_name_map_file = NULL;
88219820Sjeffstatic nn_map_t *node_name_map = NULL;
89219820Sjeff
90219820Sjeff/*******************************************/
91219820Sjeffstatic char *
92219820Sjeffnode_desc(ib_portid_t *dest, char **argv, int argc)
93219820Sjeff{
94219820Sjeff	int       node_type, l;
95219820Sjeff	uint64_t  node_guid;
96219820Sjeff	char      nd[IB_SMP_DATA_SIZE];
97219820Sjeff	uint8_t   data[IB_SMP_DATA_SIZE];
98219820Sjeff	char      dots[128];
99219820Sjeff	char     *nodename = NULL;
100219820Sjeff
101219820Sjeff	if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0))
102219820Sjeff		return "node info query failed";
103219820Sjeff
104219820Sjeff	mad_decode_field(data, IB_NODE_TYPE_F, &node_type);
105219820Sjeff	mad_decode_field(data, IB_NODE_GUID_F, &node_guid);
106219820Sjeff
107219820Sjeff	if (!smp_query(nd, dest, IB_ATTR_NODE_DESC, 0, 0))
108219820Sjeff		return "node desc query failed";
109219820Sjeff
110219820Sjeff	nodename = remap_node_name(node_name_map, node_guid, nd);
111219820Sjeff
112219820Sjeff	l = strlen(nodename);
113219820Sjeff	if (l < 32) {
114219820Sjeff		memset(dots, '.', 32 - l);
115219820Sjeff		dots[32 - l] = '\0';
116219820Sjeff	} else {
117219820Sjeff		dots[0] = '.';
118219820Sjeff		dots[1] = '\0';
119219820Sjeff	}
120219820Sjeff
121219820Sjeff	printf("Node Description:%s%s\n", dots, nodename);
122219820Sjeff	free(nodename);
123219820Sjeff	return 0;
124219820Sjeff}
125219820Sjeff
126219820Sjeffstatic char *
127219820Sjeffnode_info(ib_portid_t *dest, char **argv, int argc)
128219820Sjeff{
129219820Sjeff	char buf[2048];
130219820Sjeff	char data[IB_SMP_DATA_SIZE];
131219820Sjeff
132219820Sjeff	if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0))
133219820Sjeff		return "node info query failed";
134219820Sjeff
135219820Sjeff	mad_dump_nodeinfo(buf, sizeof buf, data, sizeof data);
136219820Sjeff
137219820Sjeff	printf("# Node info: %s\n%s", portid2str(dest), buf);
138219820Sjeff	return 0;
139219820Sjeff}
140219820Sjeff
141219820Sjeffstatic char *
142219820Sjeffport_info(ib_portid_t *dest, char **argv, int argc)
143219820Sjeff{
144219820Sjeff	char buf[2048];
145219820Sjeff	char data[IB_SMP_DATA_SIZE];
146219820Sjeff	int portnum = 0;
147219820Sjeff
148219820Sjeff	if (argc > 0)
149219820Sjeff		portnum = strtol(argv[0], 0, 0);
150219820Sjeff
151219820Sjeff	if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0))
152219820Sjeff		return "port info query failed";
153219820Sjeff
154219820Sjeff	mad_dump_portinfo(buf, sizeof buf, data, sizeof data);
155219820Sjeff
156219820Sjeff	printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf);
157219820Sjeff	return 0;
158219820Sjeff}
159219820Sjeff
160219820Sjeffstatic char *
161219820Sjeffswitch_info(ib_portid_t *dest, char **argv, int argc)
162219820Sjeff{
163219820Sjeff	char buf[2048];
164219820Sjeff	char data[IB_SMP_DATA_SIZE];
165219820Sjeff
166219820Sjeff	if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0))
167219820Sjeff		return "switch info query failed";
168219820Sjeff
169219820Sjeff	mad_dump_switchinfo(buf, sizeof buf, data, sizeof data);
170219820Sjeff
171219820Sjeff	printf("# Switch info: %s\n%s", portid2str(dest), buf);
172219820Sjeff	return 0;
173219820Sjeff}
174219820Sjeff
175219820Sjeffstatic char *
176219820Sjeffpkey_table(ib_portid_t *dest, char **argv, int argc)
177219820Sjeff{
178219820Sjeff	uint8_t data[IB_SMP_DATA_SIZE];
179219820Sjeff	uint32_t i, j, k;
180219820Sjeff	uint16_t *p;
181219820Sjeff	unsigned mod;
182219820Sjeff	int n, t, phy_ports;
183219820Sjeff	int portnum = 0;
184219820Sjeff
185219820Sjeff	if (argc > 0)
186219820Sjeff		portnum = strtol(argv[0], 0, 0);
187219820Sjeff
188219820Sjeff	/* Get the partition capacity */
189219820Sjeff	if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0))
190219820Sjeff		return "node info query failed";
191219820Sjeff
192219820Sjeff	mad_decode_field(data, IB_NODE_TYPE_F, &t);
193219820Sjeff	mad_decode_field(data, IB_NODE_NPORTS_F, &phy_ports);
194219820Sjeff	if (portnum > phy_ports)
195219820Sjeff		return "invalid port number";
196219820Sjeff
197219820Sjeff	if ((t == IB_NODE_SWITCH) && (portnum != 0)) {
198219820Sjeff		if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0))
199219820Sjeff			return "switch info failed";
200219820Sjeff		mad_decode_field(data, IB_SW_PARTITION_ENFORCE_CAP_F, &n);
201219820Sjeff	} else
202219820Sjeff		mad_decode_field(data, IB_NODE_PARTITION_CAP_F, &n);
203219820Sjeff
204219820Sjeff	for (i = 0; i < (n + 31) / 32; i++) {
205219820Sjeff		mod =  i | (portnum << 16);
206219820Sjeff		if (!smp_query(data, dest, IB_ATTR_PKEY_TBL, mod, 0))
207219820Sjeff			return "pkey table query failed";
208219820Sjeff		if (i + 1 == (n + 31) / 32)
209219820Sjeff			k = ((n + 7 - i * 32) / 8) * 8;
210219820Sjeff		else
211219820Sjeff			k = 32;
212219820Sjeff		p = (uint16_t *) data;
213219820Sjeff		for (j = 0; j < k; j += 8, p += 8) {
214219820Sjeff			printf("%4u: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n",
215219820Sjeff				(i * 32) + j,
216219820Sjeff				ntohs(p[0]), ntohs(p[1]),
217219820Sjeff				ntohs(p[2]), ntohs(p[3]),
218219820Sjeff				ntohs(p[4]), ntohs(p[5]),
219219820Sjeff				ntohs(p[6]), ntohs(p[7]));
220219820Sjeff		}
221219820Sjeff	}
222219820Sjeff	printf("%d pkeys capacity for this port\n", n);
223219820Sjeff
224219820Sjeff	return 0;
225219820Sjeff}
226219820Sjeff
227219820Sjeffstatic char *sl2vl_dump_table_entry(ib_portid_t *dest, int in, int out)
228219820Sjeff{
229219820Sjeff	char buf[2048];
230219820Sjeff	char data[IB_SMP_DATA_SIZE];
231219820Sjeff	int portnum = (in << 8) | out;
232219820Sjeff
233219820Sjeff	if (!smp_query(data, dest, IB_ATTR_SLVL_TABLE, portnum, 0))
234219820Sjeff		return "slvl query failed";
235219820Sjeff
236219820Sjeff	mad_dump_sltovl(buf, sizeof buf, data, sizeof data);
237219820Sjeff	printf("ports: in %2d, out %2d: ", in, out);
238219820Sjeff	printf("%s", buf);
239219820Sjeff	return 0;
240219820Sjeff}
241219820Sjeff
242219820Sjeffstatic char *
243219820Sjeffsl2vl_table(ib_portid_t *dest, char **argv, int argc)
244219820Sjeff{
245219820Sjeff	uint8_t data[IB_SMP_DATA_SIZE];
246219820Sjeff	int type, num_ports, portnum = 0;
247219820Sjeff	int i;
248219820Sjeff	char *ret;
249219820Sjeff
250219820Sjeff	if (argc > 0)
251219820Sjeff		portnum = strtol(argv[0], 0, 0);
252219820Sjeff
253219820Sjeff	if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0))
254219820Sjeff		return "node info query failed";
255219820Sjeff
256219820Sjeff	mad_decode_field(data, IB_NODE_TYPE_F, &type);
257219820Sjeff	mad_decode_field(data, IB_NODE_NPORTS_F, &num_ports);
258219820Sjeff	if (portnum > num_ports)
259219820Sjeff		return "invalid port number";
260219820Sjeff
261219820Sjeff	printf("# SL2VL table: %s\n", portid2str(dest));
262219820Sjeff	printf("#                 SL: |");
263219820Sjeff	for (i = 0 ; i < 16 ; i++)
264219820Sjeff		printf("%2d|", i);
265219820Sjeff	printf("\n");
266219820Sjeff
267219820Sjeff	if (type != IB_NODE_SWITCH)
268219820Sjeff		return sl2vl_dump_table_entry(dest, 0, 0);
269219820Sjeff
270219820Sjeff	for (i = 0 ; i <= num_ports ; i++) {
271219820Sjeff		ret = sl2vl_dump_table_entry(dest, i, portnum);
272219820Sjeff		if (ret)
273219820Sjeff			return ret;
274219820Sjeff	}
275219820Sjeff	return 0;
276219820Sjeff}
277219820Sjeff
278219820Sjeffstatic char *vlarb_dump_table_entry(ib_portid_t *dest, int portnum, int offset, unsigned cap)
279219820Sjeff{
280219820Sjeff	char buf[2048];
281219820Sjeff	char data[IB_SMP_DATA_SIZE];
282219820Sjeff
283219820Sjeff	if (!smp_query(data, dest, IB_ATTR_VL_ARBITRATION,
284219820Sjeff			(offset << 16) | portnum, 0))
285219820Sjeff		return "vl arb query failed";
286219820Sjeff	mad_dump_vlarbitration(buf, sizeof(buf), data, cap * 2);
287219820Sjeff	printf("%s", buf);
288219820Sjeff	return 0;
289219820Sjeff}
290219820Sjeff
291219820Sjeffstatic char *vlarb_dump_table(ib_portid_t *dest, int portnum,
292219820Sjeff	char *name, int offset, int cap)
293219820Sjeff{
294219820Sjeff	char *ret;
295219820Sjeff
296219820Sjeff	printf("# %s priority VL Arbitration Table:", name);
297219820Sjeff	ret = vlarb_dump_table_entry(dest, portnum, offset,
298219820Sjeff				     cap < 32 ? cap : 32);
299219820Sjeff	if (!ret && cap > 32)
300219820Sjeff		ret = vlarb_dump_table_entry(dest, portnum, offset + 1,
301219820Sjeff					     cap - 32);
302219820Sjeff	return ret;
303219820Sjeff}
304219820Sjeff
305219820Sjeffstatic char *
306219820Sjeffvlarb_table(ib_portid_t *dest, char **argv, int argc)
307219820Sjeff{
308219820Sjeff	uint8_t data[IB_SMP_DATA_SIZE];
309219820Sjeff	int portnum = 0;
310219820Sjeff	int type, enhsp0, lowcap, highcap;
311219820Sjeff	char *ret = 0;
312219820Sjeff
313219820Sjeff	if (argc > 0)
314219820Sjeff		portnum = strtol(argv[0], 0, 0);
315219820Sjeff
316219820Sjeff	/* port number of 0 could mean SP0 or port MAD arrives on */
317219820Sjeff	if (portnum == 0) {
318219820Sjeff		if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0))
319219820Sjeff			return "node info query failed";
320219820Sjeff
321219820Sjeff		mad_decode_field(data, IB_NODE_TYPE_F, &type);
322219820Sjeff		if (type == IB_NODE_SWITCH) {
323219820Sjeff			if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0))
324219820Sjeff				return "switch info query failed";
325219820Sjeff			mad_decode_field(data, IB_SW_ENHANCED_PORT0_F, &enhsp0);
326219820Sjeff			if (!enhsp0) {
327219820Sjeff				printf("# No VLArbitration tables (BSP0): %s port %d\n",
328219820Sjeff                        		portid2str(dest), 0);
329219820Sjeff				return 0;
330219820Sjeff			}
331219820Sjeff		}
332219820Sjeff	}
333219820Sjeff
334219820Sjeff	if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0))
335219820Sjeff		return "port info query failed";
336219820Sjeff
337219820Sjeff	mad_decode_field(data, IB_PORT_VL_ARBITRATION_LOW_CAP_F, &lowcap);
338219820Sjeff	mad_decode_field(data, IB_PORT_VL_ARBITRATION_HIGH_CAP_F,&highcap);
339219820Sjeff
340219820Sjeff	printf("# VLArbitration tables: %s port %d LowCap %d HighCap %d\n",
341219820Sjeff			portid2str(dest), portnum, lowcap, highcap);
342219820Sjeff
343219820Sjeff	if (lowcap > 0)
344219820Sjeff		ret = vlarb_dump_table(dest, portnum, "Low", 1, lowcap);
345219820Sjeff
346219820Sjeff	if (!ret && highcap > 0)
347219820Sjeff		ret = vlarb_dump_table(dest, portnum, "High", 3, highcap);
348219820Sjeff
349219820Sjeff	return ret;
350219820Sjeff}
351219820Sjeff
352219820Sjeffstatic char *
353219820Sjeffguid_info(ib_portid_t *dest, char **argv, int argc)
354219820Sjeff{
355219820Sjeff	uint8_t data[IB_SMP_DATA_SIZE];
356219820Sjeff	uint32_t i, j, k;
357219820Sjeff	uint64_t *p;
358219820Sjeff	unsigned mod;
359219820Sjeff	int n;
360219820Sjeff
361219820Sjeff	/* Get the guid capacity */
362219820Sjeff	if (!smp_query(data, dest, IB_ATTR_PORT_INFO, 0, 0))
363219820Sjeff		return "port info failed";
364219820Sjeff	mad_decode_field(data, IB_PORT_GUID_CAP_F, &n);
365219820Sjeff
366219820Sjeff	for (i = 0; i < (n + 7) / 8; i++) {
367219820Sjeff		mod =  i;
368219820Sjeff		if (!smp_query(data, dest, IB_ATTR_GUID_INFO, mod, 0))
369219820Sjeff			return "guid info query failed";
370219820Sjeff		if (i + 1 == (n + 7) / 8)
371219820Sjeff			k = ((n + 1 - i * 8) / 2) * 2;
372219820Sjeff		else
373219820Sjeff			k = 8;
374219820Sjeff		p = (uint64_t *) data;
375219820Sjeff		for (j = 0; j < k; j += 2, p += 2) {
376219820Sjeff			printf("%4u: 0x%016"PRIx64" 0x%016"PRIx64"\n",
377219820Sjeff				(i * 8) + j,
378219820Sjeff				ntohll(p[0]), ntohll(p[1]));
379219820Sjeff		}
380219820Sjeff	}
381219820Sjeff	printf("%d guids capacity for this port\n", n);
382219820Sjeff
383219820Sjeff	return 0;
384219820Sjeff}
385219820Sjeff
386219820Sjeffstatic op_fn_t *
387219820Sjeffmatch_op(char *name)
388219820Sjeff{
389219820Sjeff	const match_rec_t *r;
390219820Sjeff	for (r = match_tbl; r->name; r++)
391219820Sjeff		if (!strcmp(r->name, name))
392219820Sjeff			return r->fn;
393219820Sjeff	return 0;
394219820Sjeff}
395219820Sjeff
396219820Sjeffstatic void
397219820Sjeffusage(void)
398219820Sjeff{
399219820Sjeff	char *basename;
400219820Sjeff	const match_rec_t *r;
401219820Sjeff
402219820Sjeff	if (!(basename = strrchr(argv0, '/')))
403219820Sjeff		basename = argv0;
404219820Sjeff	else
405219820Sjeff		basename++;
406219820Sjeff
407219820Sjeff	fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -D(irect) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port "
408219820Sjeff			"-t(imeout) timeout_ms --node-name-map node-name-map] <op> <dest dr_path|lid|guid> [op params]\n",
409219820Sjeff			basename);
410219820Sjeff	fprintf(stderr, "\tsupported ops:\n");
411219820Sjeff	for (r = match_tbl ; r->name ; r++) {
412219820Sjeff		fprintf(stderr, "\t\t%s <addr>%s\n", r->name,
413219820Sjeff				r->opt_portnum ? " [<portnum>]" : "");
414219820Sjeff	}
415219820Sjeff	fprintf(stderr, "\n\texamples:\n");
416219820Sjeff	fprintf(stderr, "\t\t%s portinfo 3 1\t\t\t\t# portinfo by lid, with port modifier\n", basename);
417219820Sjeff	fprintf(stderr, "\t\t%s -G switchinfo 0x2C9000100D051 1\t# switchinfo by guid\n", basename);
418219820Sjeff	fprintf(stderr, "\t\t%s -D nodeinfo 0\t\t\t\t# nodeinfo by direct route\n", basename);
419219820Sjeff	fprintf(stderr, "\t\t%s -c nodeinfo 6 0,12\t\t\t# nodeinfo by combined route\n", basename);
420219820Sjeff	exit(-1);
421219820Sjeff}
422219820Sjeff
423219820Sjeffint
424219820Sjeffmain(int argc, char **argv)
425219820Sjeff{
426219820Sjeff	int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS};
427219820Sjeff	ib_portid_t portid = {0};
428219820Sjeff	ib_portid_t *sm_id = 0, sm_portid = {0};
429219820Sjeff	extern int ibdebug;
430219820Sjeff	int timeout = 0, udebug = 0;
431219820Sjeff	char *ca = 0;
432219820Sjeff	int ca_port = 0;
433219820Sjeff	char *err;
434219820Sjeff	op_fn_t *fn;
435219820Sjeff
436219820Sjeff	static char const str_opts[] = "C:P:t:s:devDcGVhu";
437219820Sjeff	static const struct option long_opts[] = {
438219820Sjeff		{ "C", 1, 0, 'C'},
439219820Sjeff		{ "P", 1, 0, 'P'},
440219820Sjeff		{ "debug", 0, 0, 'd'},
441219820Sjeff		{ "err_show", 0, 0, 'e'},
442219820Sjeff		{ "verbose", 0, 0, 'v'},
443219820Sjeff		{ "Direct", 0, 0, 'D'},
444219820Sjeff		{ "combined", 0, 0, 'c'},
445219820Sjeff		{ "Guid", 0, 0, 'G'},
446219820Sjeff		{ "smlid", 1, 0, 's'},
447219820Sjeff		{ "timeout", 1, 0, 't'},
448219820Sjeff		{ "node-name-map", 1, 0, 1},
449219820Sjeff		{ "Version", 0, 0, 'V'},
450219820Sjeff		{ "help", 0, 0, 'h'},
451219820Sjeff		{ "usage", 0, 0, 'u'},
452219820Sjeff		{ }
453219820Sjeff	};
454219820Sjeff
455219820Sjeff	argv0 = argv[0];
456219820Sjeff
457219820Sjeff	while (1) {
458219820Sjeff		int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
459219820Sjeff		if ( ch == -1 )
460219820Sjeff			break;
461219820Sjeff		switch(ch) {
462219820Sjeff		case 1:
463219820Sjeff			node_name_map_file = strdup(optarg);
464219820Sjeff			break;
465219820Sjeff		case 'd':
466219820Sjeff			ibdebug++;
467219820Sjeff			madrpc_show_errors(1);
468219820Sjeff			umad_debug(udebug);
469219820Sjeff			udebug++;
470219820Sjeff			break;
471219820Sjeff		case 'e':
472219820Sjeff			madrpc_show_errors(1);
473219820Sjeff			break;
474219820Sjeff		case 'D':
475219820Sjeff			dest_type = IB_DEST_DRPATH;
476219820Sjeff			break;
477219820Sjeff		case 'c':
478219820Sjeff			dest_type = IB_DEST_DRSLID;
479219820Sjeff			break;
480219820Sjeff		case 'G':
481219820Sjeff			dest_type = IB_DEST_GUID;
482219820Sjeff			break;
483219820Sjeff		case 'C':
484219820Sjeff			ca = optarg;
485219820Sjeff			break;
486219820Sjeff		case 'P':
487219820Sjeff			ca_port = strtoul(optarg, 0, 0);
488219820Sjeff			break;
489219820Sjeff		case 's':
490219820Sjeff			if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)
491219820Sjeff				IBERROR("can't resolve SM destination port %s", optarg);
492219820Sjeff			sm_id = &sm_portid;
493219820Sjeff			break;
494219820Sjeff		case 't':
495219820Sjeff			timeout = strtoul(optarg, 0, 0);
496219820Sjeff			madrpc_set_timeout(timeout);
497219820Sjeff			break;
498219820Sjeff		case 'v':
499219820Sjeff			verbose++;
500219820Sjeff			break;
501219820Sjeff		case 'V':
502219820Sjeff			fprintf(stderr, "%s %s\n", argv0, get_build_version() );
503219820Sjeff			exit(-1);
504219820Sjeff		default:
505219820Sjeff			usage();
506219820Sjeff			break;
507219820Sjeff		}
508219820Sjeff	}
509219820Sjeff	argc -= optind;
510219820Sjeff	argv += optind;
511219820Sjeff
512219820Sjeff	if (argc < 2)
513219820Sjeff		usage();
514219820Sjeff
515219820Sjeff	if (!(fn = match_op(argv[0])))
516219820Sjeff		IBERROR("operation '%s' not supported", argv[0]);
517219820Sjeff
518219820Sjeff	madrpc_init(ca, ca_port, mgmt_classes, 3);
519219820Sjeff	node_name_map = open_node_name_map(node_name_map_file);
520219820Sjeff
521219820Sjeff	if (dest_type != IB_DEST_DRSLID) {
522219820Sjeff		if (ib_resolve_portid_str(&portid, argv[1], dest_type, sm_id) < 0)
523219820Sjeff			IBERROR("can't resolve destination port %s", argv[1]);
524219820Sjeff		if ((err = fn(&portid, argv+2, argc-2)))
525219820Sjeff			IBERROR("operation %s: %s", argv[0], err);
526219820Sjeff	} else {
527219820Sjeff		char concat[64];
528219820Sjeff
529219820Sjeff		memset(concat, 0, 64);
530219820Sjeff		snprintf(concat, sizeof(concat), "%s %s", argv[1], argv[2]);
531219820Sjeff		if (ib_resolve_portid_str(&portid, concat, dest_type, sm_id) < 0)
532219820Sjeff			IBERROR("can't resolve destination port %s", concat);
533219820Sjeff		if ((err = fn(&portid, argv+3, argc-3)))
534219820Sjeff			IBERROR("operation %s: %s", argv[0], err);
535219820Sjeff	}
536219820Sjeff	close_node_name_map(node_name_map);
537219820Sjeff	exit(0);
538219820Sjeff}
539