11558Srgrimes/*
21558Srgrimes * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
31558Srgrimes *
41558Srgrimes * This software is available to you under a choice of one of two
51558Srgrimes * licenses.  You may choose to be licensed under the terms of the GNU
61558Srgrimes * General Public License (GPL) Version 2, available from the file
71558Srgrimes * COPYING in the main directory of this source tree, or the
81558Srgrimes * OpenIB.org BSD license below:
91558Srgrimes *
101558Srgrimes *     Redistribution and use in source and binary forms, with or
111558Srgrimes *     without modification, are permitted provided that the following
121558Srgrimes *     conditions are met:
131558Srgrimes *
141558Srgrimes *      - Redistributions of source code must retain the above
151558Srgrimes *        copyright notice, this list of conditions and the following
161558Srgrimes *        disclaimer.
171558Srgrimes *
181558Srgrimes *      - Redistributions in binary form must reproduce the above
191558Srgrimes *        copyright notice, this list of conditions and the following
201558Srgrimes *        disclaimer in the documentation and/or other materials
211558Srgrimes *        provided with the distribution.
221558Srgrimes *
231558Srgrimes * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
241558Srgrimes * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
251558Srgrimes * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
261558Srgrimes * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
271558Srgrimes * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
281558Srgrimes * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
291558Srgrimes * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
301558Srgrimes * SOFTWARE.
311558Srgrimes *
321558Srgrimes */
331558Srgrimes
3437663Scharnier#define _GNU_SOURCE
351558Srgrimes
361558Srgrimes#if HAVE_CONFIG_H
372999Swollman#  include <config.h>
381558Srgrimes#endif /* HAVE_CONFIG_H */
39105267Scharnier
401558Srgrimes#include <inttypes.h>
4137663Scharnier#include <string.h>
42105267Scharnier#include <errno.h>
4337663Scharnier#include <stdio.h>
441558Srgrimes#include <stdlib.h>
45105267Scharnier#include <unistd.h>
46105267Scharnier#include <stdarg.h>
47105267Scharnier#include <sys/types.h>
481558Srgrimes#include <sys/stat.h>
491558Srgrimes#include <fcntl.h>
5074462Salfred#include <sys/ioctl.h>
511558Srgrimes#include <unistd.h>
521558Srgrimes#include <string.h>
5324330Sguido#include <getopt.h>
5496622Siedowse#include <endian.h>
5596622Siedowse#include <byteswap.h>
561558Srgrimes#include <sys/poll.h>
571558Srgrimes#include <syslog.h>
58109363Smbr#include <netinet/in.h>
591558Srgrimes
6074462Salfred#include <infiniband/common.h>
6174462Salfred#include <infiniband/umad.h>
621558Srgrimes#include <infiniband/mad.h>
639336Sdfr
6483653Speter#include <ibdiag_common.h>
6523681Speter
6677162Srustatic int debug;
6777223Sru
6823681Speterchar *argv0 = "ibstat";
691558Srgrimes
701558Srgrimesstatic char *node_type_str[] = {
711558Srgrimes	"???",
721558Srgrimes	"CA",
7337663Scharnier	"Switch",
741558Srgrimes	"Router",
751558Srgrimes	"iWARP RNIC"
76103949Smike};
771558Srgrimes
781558Srgrimesstatic void
791558Srgrimesca_dump(umad_ca_t *ca)
801558Srgrimes{
811558Srgrimes	if (!ca->node_type)
821558Srgrimes		return;
831558Srgrimes	printf("%s '%s'\n", ((uint)ca->node_type <= IB_NODE_MAX ? node_type_str[ca->node_type] : "???"), ca->ca_name);
841558Srgrimes	printf("\t%s type: %s\n", ((uint)ca->node_type <= IB_NODE_MAX ? node_type_str[ca->node_type] : "???"),ca->ca_type);
851558Srgrimes	printf("\tNumber of ports: %d\n", ca->numports);
861558Srgrimes	printf("\tFirmware version: %s\n", ca->fw_ver);
871558Srgrimes	printf("\tHardware version: %s\n", ca->hw_ver);
881558Srgrimes	printf("\tNode GUID: 0x%016llx\n", (long long unsigned)ntohll(ca->node_guid));
891558Srgrimes	printf("\tSystem image GUID: 0x%016llx\n", (long long unsigned)ntohll(ca->system_guid));
9074462Salfred}
9174462Salfred
9274462Salfredstatic char *port_state_str[] = {
9374462Salfred	"???",
941558Srgrimes	"Down",
951558Srgrimes	"Initializing",
961558Srgrimes	"Armed",
971558Srgrimes	"Active"
981558Srgrimes};
991558Srgrimes
1001558Srgrimesstatic char *port_phy_state_str[] = {
1011558Srgrimes	"No state change",
1021558Srgrimes	"Sleep",
1031558Srgrimes	"Polling",
1041558Srgrimes	"Disabled",
1051558Srgrimes	"PortConfigurationTraining",
1061558Srgrimes	"LinkUp",
1071558Srgrimes	"LinkErrorRecovery",
1081558Srgrimes	"PhyTest"
1091558Srgrimes};
1101558Srgrimes
1111558Srgrimesstatic int
1129336Sdfrport_dump(umad_port_t *port, int alone)
1131558Srgrimes{
1141558Srgrimes	char *pre = "";
1151558Srgrimes	char *hdrpre = "";
1161558Srgrimes
1171558Srgrimes	if (!port)
1181558Srgrimes		return -1;
1191558Srgrimes
1201558Srgrimes	if (!alone) {
12127447Sdfr		pre = "		";
1221558Srgrimes		hdrpre = "	";
1231558Srgrimes	}
1241558Srgrimes
1251558Srgrimes	printf("%sPort %d:\n", hdrpre, port->portnum);
1261558Srgrimes	printf("%sState: %s\n", pre, (uint)port->state <= 4 ? port_state_str[port->state] : "???");
12774462Salfred	printf("%sPhysical state: %s\n", pre, (uint)port->state <= 7 ? port_phy_state_str[port->phys_state] : "???");
12875801Siedowse	printf("%sRate: %d\n", pre, port->rate);
12942144Sdfr	printf("%sBase lid: %d\n", pre, port->base_lid);
1301558Srgrimes	printf("%sLMC: %d\n", pre, port->lmc);
1311558Srgrimes	printf("%sSM lid: %d\n", pre, port->sm_lid);
1321558Srgrimes	printf("%sCapability mask: 0x%08x\n", pre, (unsigned)ntohl(port->capmask));
13374462Salfred	printf("%sPort GUID: 0x%016llx\n", pre, (long long unsigned)ntohll(port->port_guid));
1341558Srgrimes	return 0;
1351558Srgrimes}
1361558Srgrimes
1371558Srgrimesstatic int
1381558Srgrimesca_stat(char *ca_name, int portnum, int no_ports)
1391558Srgrimes{
1401558Srgrimes	umad_ca_t ca;
1411558Srgrimes	int r;
1421558Srgrimes
1431558Srgrimes	if ((r = umad_get_ca(ca_name, &ca)) < 0)
1441558Srgrimes		return r;
1451558Srgrimes
14675641Siedowse	if (!ca.node_type)
1477401Swpaul		return 0;
1481558Srgrimes
1491558Srgrimes	if (!no_ports && portnum >= 0) {
1509336Sdfr		if (portnum > ca.numports || !ca.ports[portnum]) {
1511558Srgrimes			IBWARN("%s: '%s' has no port number %d - max (%d)",
1521558Srgrimes				((uint)ca.node_type <= IB_NODE_MAX ? node_type_str[ca.node_type] : "???"),
1531558Srgrimes				ca_name, portnum, ca.numports);
1541558Srgrimes			return -1;
1559336Sdfr		}
1569336Sdfr		printf("%s: '%s'\n", ((uint)ca.node_type <= IB_NODE_MAX ? node_type_str[ca.node_type] : "???"), ca.ca_name);
1579336Sdfr		port_dump(ca.ports[portnum], 1);
1589336Sdfr		return 0;
1599336Sdfr	}
1609336Sdfr
1611558Srgrimes	/* print ca header */
16292882Simp	ca_dump(&ca);
16392882Simp
16492882Simp	if (no_ports)
16592882Simp		return 0;
16692882Simp
16792882Simp	for (portnum = 0; portnum <= ca.numports; portnum++)
16875801Siedowse		port_dump(ca.ports[portnum], 0);
16992882Simp
17075635Siedowse	return 0;
17192882Simp}
17292882Simp
17392882Simpstatic int
17492882Simpports_list(char names[][UMAD_CA_NAME_LEN], int n)
17592882Simp{
17692882Simp	uint64_t guids[64];
17792882Simp	int found, ports, i;
17892882Simp
17992882Simp	for (i = 0, found = 0; i < n && found < 64; i++) {
18092882Simp		if ((ports = umad_get_ca_portguids(names[i], guids + found, 64 - found)) < 0)
18192882Simp			return -1;
18292882Simp		found += ports;
18392882Simp	}
18492882Simp
18592882Simp	for (i = 0; i < found; i++)
18692882Simp		if (guids[i])
18792882Simp			printf("0x%016llx\n", (long long unsigned)ntohll(guids[i]));
18892882Simp	return found;
18992882Simp}
19092882Simp
19192882Simpvoid
19275754Siedowseusage(void)
19375801Siedowse{
19492882Simp	fprintf(stderr, "Usage: %s [-d(ebug) -l(ist_of_cas) -s(hort) -p(ort_list) -V(ersion)] <ca_name> [portnum]\n", argv0);
19592882Simp	fprintf(stderr, "\tExamples:\n");
19692882Simp	fprintf(stderr, "\t\t%s -l	  # list all IB devices\n", argv0);
19792882Simp	fprintf(stderr, "\t\t%s mthca0 2 # stat port 2 of 'mthca0'\n", argv0);
198100117Salfred	exit(-1);
19975801Siedowse}
20075801Siedowse
20175801Siedowseint
20292882Simpmain(int argc, char *argv[])
20392882Simp{
20492882Simp	char names[UMAD_MAX_DEVICES][UMAD_CA_NAME_LEN];
20592882Simp	int dev_port = -1;
206100117Salfred	int list_only = 0, short_format = 0, list_ports = 0;
20792882Simp	int n, i;
20892882Simp
20992882Simp	static char const str_opts[] = "dlspVhu";
2101558Srgrimes	static const struct option long_opts[] = {
2111558Srgrimes		{ "debug", 0, 0, 'd'},
2121558Srgrimes		{ "list_of_cas", 0, 0, 'l'},
2131558Srgrimes		{ "short", 0, 0, 's'},
2141558Srgrimes		{ "port_list", 0, 0, 'p'},
21572650Sgreen		{ "Version", 0, 0, 'V'},
21691354Sdd		{ "help", 0, 0, 'h'},
21772650Sgreen		{ "usage", 0, 0, 'u'},
2181558Srgrimes		{ }
21972650Sgreen	};
22072650Sgreen
2211558Srgrimes	argv0 = argv[0];
22225087Sdfr
2239336Sdfr	while (1) {
2249336Sdfr		int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
225121767Speter		if ( ch == -1 )
22675754Siedowse			break;
22774462Salfred		switch(ch) {
2281558Srgrimes		case 'd':
22974462Salfred			debug++;
23074462Salfred			break;
23174462Salfred		case 'l':
23274462Salfred			list_only++;
23374462Salfred			break;
23474462Salfred		case 's':
23574462Salfred			short_format++;
23674462Salfred			break;
23775801Siedowse		case 'p':
2381558Srgrimes			list_ports++;
2391558Srgrimes			break;
24083653Speter		case 'V':
2411558Srgrimes			fprintf(stderr, "%s %s\n", argv0, get_build_version() );
2421558Srgrimes			exit(-1);
2431558Srgrimes		default:
24475801Siedowse			usage();
245100336Sjoerg			break;
24674462Salfred		}
2471558Srgrimes	}
2481558Srgrimes	argc -= optind;
2491558Srgrimes	argv += optind;
25092882Simp
2511558Srgrimes	if (argc > 1)
2521558Srgrimes		dev_port = strtol(argv[1], 0, 0);
2531558Srgrimes
2541558Srgrimes	if (umad_init() < 0)
2551558Srgrimes		IBPANIC("can't init UMAD library");
2561558Srgrimes
2571558Srgrimes	if ((n = umad_get_cas_names(names, UMAD_MAX_DEVICES)) < 0)
2581558Srgrimes		IBPANIC("can't list IB device names");
2591558Srgrimes
2601558Srgrimes	if (argc) {
2611558Srgrimes		for (i = 0; i < n; i++)
2621558Srgrimes			if (!strncmp(names[i], argv[0], sizeof names[i]))
2631558Srgrimes				break;
2641558Srgrimes		if (i >= n)
2651558Srgrimes			IBPANIC("'%s' IB device can't be found", argv[0]);
2661558Srgrimes
2671558Srgrimes		strncpy(names[i], argv[0], sizeof names[i]);
26875754Siedowse		n = 1;
269126572Sbms	}
270126572Sbms
271126572Sbms	if (list_ports) {
27274462Salfred		if (ports_list(names, n) < 0)
27374462Salfred			IBPANIC("can't list ports");
27474462Salfred		return 0;
27574462Salfred	}
276109363Smbr
27774462Salfred	if (!list_only && argc) {
278126572Sbms		if (ca_stat(argv[0], dev_port, short_format) < 0)
279126572Sbms			IBPANIC("stat of IB device '%s' failed", argv[0]);
2801558Srgrimes		return 0;
28175635Siedowse	}
282126643Smarkm
28375635Siedowse	for (i = 0; i < n; i++) {
28474462Salfred		if (list_only)
28574462Salfred			printf("%s\n", names[i]);
28674462Salfred		else
28774462Salfred			if (ca_stat(names[i], -1, short_format) < 0)
28874462Salfred				IBPANIC("stat of IB device '%s' failed", names[i]);
289105267Scharnier	}
29074462Salfred
29174462Salfred	return 0;
29274462Salfred}
29374462Salfred