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#define _GNU_SOURCE
35219820Sjeff
36219820Sjeff#if HAVE_CONFIG_H
37219820Sjeff#  include <config.h>
38219820Sjeff#endif /* HAVE_CONFIG_H */
39219820Sjeff
40219820Sjeff#include <inttypes.h>
41219820Sjeff#include <string.h>
42219820Sjeff#include <errno.h>
43219820Sjeff#include <stdio.h>
44219820Sjeff#include <stdlib.h>
45219820Sjeff#include <unistd.h>
46219820Sjeff#include <stdarg.h>
47219820Sjeff#include <sys/types.h>
48219820Sjeff#include <sys/stat.h>
49219820Sjeff#include <fcntl.h>
50219820Sjeff#include <sys/ioctl.h>
51219820Sjeff#include <unistd.h>
52219820Sjeff#include <string.h>
53219820Sjeff#include <getopt.h>
54219820Sjeff#include <endian.h>
55219820Sjeff#include <byteswap.h>
56219820Sjeff#include <sys/poll.h>
57219820Sjeff#include <syslog.h>
58219820Sjeff#include <netinet/in.h>
59219820Sjeff
60219820Sjeff#include <infiniband/common.h>
61219820Sjeff#include <infiniband/umad.h>
62219820Sjeff#include <infiniband/mad.h>
63219820Sjeff
64219820Sjeff#include <ibdiag_common.h>
65219820Sjeff
66219820Sjeffstatic int debug;
67219820Sjeff
68219820Sjeffchar *argv0 = "ibstat";
69219820Sjeff
70219820Sjeffstatic char *node_type_str[] = {
71219820Sjeff	"???",
72219820Sjeff	"CA",
73219820Sjeff	"Switch",
74219820Sjeff	"Router",
75219820Sjeff	"iWARP RNIC"
76219820Sjeff};
77219820Sjeff
78219820Sjeffstatic void
79219820Sjeffca_dump(umad_ca_t *ca)
80219820Sjeff{
81219820Sjeff	if (!ca->node_type)
82219820Sjeff		return;
83219820Sjeff	printf("%s '%s'\n", ((uint)ca->node_type <= IB_NODE_MAX ? node_type_str[ca->node_type] : "???"), ca->ca_name);
84219820Sjeff	printf("\t%s type: %s\n", ((uint)ca->node_type <= IB_NODE_MAX ? node_type_str[ca->node_type] : "???"),ca->ca_type);
85219820Sjeff	printf("\tNumber of ports: %d\n", ca->numports);
86219820Sjeff	printf("\tFirmware version: %s\n", ca->fw_ver);
87219820Sjeff	printf("\tHardware version: %s\n", ca->hw_ver);
88219820Sjeff	printf("\tNode GUID: 0x%016llx\n", (long long unsigned)ntohll(ca->node_guid));
89219820Sjeff	printf("\tSystem image GUID: 0x%016llx\n", (long long unsigned)ntohll(ca->system_guid));
90219820Sjeff}
91219820Sjeff
92219820Sjeffstatic char *port_state_str[] = {
93219820Sjeff	"???",
94219820Sjeff	"Down",
95219820Sjeff	"Initializing",
96219820Sjeff	"Armed",
97219820Sjeff	"Active"
98219820Sjeff};
99219820Sjeff
100219820Sjeffstatic char *port_phy_state_str[] = {
101219820Sjeff	"No state change",
102219820Sjeff	"Sleep",
103219820Sjeff	"Polling",
104219820Sjeff	"Disabled",
105219820Sjeff	"PortConfigurationTraining",
106219820Sjeff	"LinkUp",
107219820Sjeff	"LinkErrorRecovery",
108219820Sjeff	"PhyTest"
109219820Sjeff};
110219820Sjeff
111219820Sjeffstatic int
112219820Sjeffport_dump(umad_port_t *port, int alone)
113219820Sjeff{
114219820Sjeff	char *pre = "";
115219820Sjeff	char *hdrpre = "";
116219820Sjeff
117219820Sjeff	if (!port)
118219820Sjeff		return -1;
119219820Sjeff
120219820Sjeff	if (!alone) {
121219820Sjeff		pre = "		";
122219820Sjeff		hdrpre = "	";
123219820Sjeff	}
124219820Sjeff
125219820Sjeff	printf("%sPort %d:\n", hdrpre, port->portnum);
126219820Sjeff	printf("%sState: %s\n", pre, (uint)port->state <= 4 ? port_state_str[port->state] : "???");
127219820Sjeff	printf("%sPhysical state: %s\n", pre, (uint)port->state <= 7 ? port_phy_state_str[port->phys_state] : "???");
128219820Sjeff	printf("%sRate: %d\n", pre, port->rate);
129219820Sjeff	printf("%sBase lid: %d\n", pre, port->base_lid);
130219820Sjeff	printf("%sLMC: %d\n", pre, port->lmc);
131219820Sjeff	printf("%sSM lid: %d\n", pre, port->sm_lid);
132219820Sjeff	printf("%sCapability mask: 0x%08x\n", pre, (unsigned)ntohl(port->capmask));
133219820Sjeff	printf("%sPort GUID: 0x%016llx\n", pre, (long long unsigned)ntohll(port->port_guid));
134219820Sjeff	return 0;
135219820Sjeff}
136219820Sjeff
137219820Sjeffstatic int
138219820Sjeffca_stat(char *ca_name, int portnum, int no_ports)
139219820Sjeff{
140219820Sjeff	umad_ca_t ca;
141219820Sjeff	int r;
142219820Sjeff
143219820Sjeff	if ((r = umad_get_ca(ca_name, &ca)) < 0)
144219820Sjeff		return r;
145219820Sjeff
146219820Sjeff	if (!ca.node_type)
147219820Sjeff		return 0;
148219820Sjeff
149219820Sjeff	if (!no_ports && portnum >= 0) {
150219820Sjeff		if (portnum > ca.numports || !ca.ports[portnum]) {
151219820Sjeff			IBWARN("%s: '%s' has no port number %d - max (%d)",
152219820Sjeff				((uint)ca.node_type <= IB_NODE_MAX ? node_type_str[ca.node_type] : "???"),
153219820Sjeff				ca_name, portnum, ca.numports);
154219820Sjeff			return -1;
155219820Sjeff		}
156219820Sjeff		printf("%s: '%s'\n", ((uint)ca.node_type <= IB_NODE_MAX ? node_type_str[ca.node_type] : "???"), ca.ca_name);
157219820Sjeff		port_dump(ca.ports[portnum], 1);
158219820Sjeff		return 0;
159219820Sjeff	}
160219820Sjeff
161219820Sjeff	/* print ca header */
162219820Sjeff	ca_dump(&ca);
163219820Sjeff
164219820Sjeff	if (no_ports)
165219820Sjeff		return 0;
166219820Sjeff
167219820Sjeff	for (portnum = 0; portnum <= ca.numports; portnum++)
168219820Sjeff		port_dump(ca.ports[portnum], 0);
169219820Sjeff
170219820Sjeff	return 0;
171219820Sjeff}
172219820Sjeff
173219820Sjeffstatic int
174219820Sjeffports_list(char names[][UMAD_CA_NAME_LEN], int n)
175219820Sjeff{
176219820Sjeff	uint64_t guids[64];
177219820Sjeff	int found, ports, i;
178219820Sjeff
179219820Sjeff	for (i = 0, found = 0; i < n && found < 64; i++) {
180219820Sjeff		if ((ports = umad_get_ca_portguids(names[i], guids + found, 64 - found)) < 0)
181219820Sjeff			return -1;
182219820Sjeff		found += ports;
183219820Sjeff	}
184219820Sjeff
185219820Sjeff	for (i = 0; i < found; i++)
186219820Sjeff		if (guids[i])
187219820Sjeff			printf("0x%016llx\n", (long long unsigned)ntohll(guids[i]));
188219820Sjeff	return found;
189219820Sjeff}
190219820Sjeff
191219820Sjeffvoid
192219820Sjeffusage(void)
193219820Sjeff{
194219820Sjeff	fprintf(stderr, "Usage: %s [-d(ebug) -l(ist_of_cas) -s(hort) -p(ort_list) -V(ersion)] <ca_name> [portnum]\n", argv0);
195219820Sjeff	fprintf(stderr, "\tExamples:\n");
196219820Sjeff	fprintf(stderr, "\t\t%s -l	  # list all IB devices\n", argv0);
197219820Sjeff	fprintf(stderr, "\t\t%s mthca0 2 # stat port 2 of 'mthca0'\n", argv0);
198219820Sjeff	exit(-1);
199219820Sjeff}
200219820Sjeff
201219820Sjeffint
202219820Sjeffmain(int argc, char *argv[])
203219820Sjeff{
204219820Sjeff	char names[UMAD_MAX_DEVICES][UMAD_CA_NAME_LEN];
205219820Sjeff	int dev_port = -1;
206219820Sjeff	int list_only = 0, short_format = 0, list_ports = 0;
207219820Sjeff	int n, i;
208219820Sjeff
209219820Sjeff	static char const str_opts[] = "dlspVhu";
210219820Sjeff	static const struct option long_opts[] = {
211219820Sjeff		{ "debug", 0, 0, 'd'},
212219820Sjeff		{ "list_of_cas", 0, 0, 'l'},
213219820Sjeff		{ "short", 0, 0, 's'},
214219820Sjeff		{ "port_list", 0, 0, 'p'},
215219820Sjeff		{ "Version", 0, 0, 'V'},
216219820Sjeff		{ "help", 0, 0, 'h'},
217219820Sjeff		{ "usage", 0, 0, 'u'},
218219820Sjeff		{ }
219219820Sjeff	};
220219820Sjeff
221219820Sjeff	argv0 = argv[0];
222219820Sjeff
223219820Sjeff	while (1) {
224219820Sjeff		int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
225219820Sjeff		if ( ch == -1 )
226219820Sjeff			break;
227219820Sjeff		switch(ch) {
228219820Sjeff		case 'd':
229219820Sjeff			debug++;
230219820Sjeff			break;
231219820Sjeff		case 'l':
232219820Sjeff			list_only++;
233219820Sjeff			break;
234219820Sjeff		case 's':
235219820Sjeff			short_format++;
236219820Sjeff			break;
237219820Sjeff		case 'p':
238219820Sjeff			list_ports++;
239219820Sjeff			break;
240219820Sjeff		case 'V':
241219820Sjeff			fprintf(stderr, "%s %s\n", argv0, get_build_version() );
242219820Sjeff			exit(-1);
243219820Sjeff		default:
244219820Sjeff			usage();
245219820Sjeff			break;
246219820Sjeff		}
247219820Sjeff	}
248219820Sjeff	argc -= optind;
249219820Sjeff	argv += optind;
250219820Sjeff
251219820Sjeff	if (argc > 1)
252219820Sjeff		dev_port = strtol(argv[1], 0, 0);
253219820Sjeff
254219820Sjeff	if (umad_init() < 0)
255219820Sjeff		IBPANIC("can't init UMAD library");
256219820Sjeff
257219820Sjeff	if ((n = umad_get_cas_names(names, UMAD_MAX_DEVICES)) < 0)
258219820Sjeff		IBPANIC("can't list IB device names");
259219820Sjeff
260219820Sjeff	if (argc) {
261219820Sjeff		for (i = 0; i < n; i++)
262219820Sjeff			if (!strncmp(names[i], argv[0], sizeof names[i]))
263219820Sjeff				break;
264219820Sjeff		if (i >= n)
265219820Sjeff			IBPANIC("'%s' IB device can't be found", argv[0]);
266219820Sjeff
267219820Sjeff		strncpy(names[i], argv[0], sizeof names[i]);
268219820Sjeff		n = 1;
269219820Sjeff	}
270219820Sjeff
271219820Sjeff	if (list_ports) {
272219820Sjeff		if (ports_list(names, n) < 0)
273219820Sjeff			IBPANIC("can't list ports");
274219820Sjeff		return 0;
275219820Sjeff	}
276219820Sjeff
277219820Sjeff	if (!list_only && argc) {
278219820Sjeff		if (ca_stat(argv[0], dev_port, short_format) < 0)
279219820Sjeff			IBPANIC("stat of IB device '%s' failed", argv[0]);
280219820Sjeff		return 0;
281219820Sjeff	}
282219820Sjeff
283219820Sjeff	for (i = 0; i < n; i++) {
284219820Sjeff		if (list_only)
285219820Sjeff			printf("%s\n", names[i]);
286219820Sjeff		else
287219820Sjeff			if (ca_stat(names[i], -1, short_format) < 0)
288219820Sjeff				IBPANIC("stat of IB device '%s' failed", names[i]);
289219820Sjeff	}
290219820Sjeff
291219820Sjeff	return 0;
292219820Sjeff}
293