15115240jeff/*
2c187222hselasky * Copyright (c) 2005-2009 Voltaire, Inc. All rights reserved.
3c187222hselasky * Copyright (c) 2009,2010 HNR Consulting. All rights reserved.
4c187222hselasky * Copyright (c) 2010,2011 Mellanox Technologies LTD. All rights reserved.
55115240jeff *
65115240jeff * This software is available to you under a choice of one of two
75115240jeff * licenses.  You may choose to be licensed under the terms of the GNU
85115240jeff * General Public License (GPL) Version 2, available from the file
95115240jeff * COPYING in the main directory of this source tree, or the
105115240jeff * OpenIB.org BSD license below:
115115240jeff *
125115240jeff *     Redistribution and use in source and binary forms, with or
135115240jeff *     without modification, are permitted provided that the following
145115240jeff *     conditions are met:
155115240jeff *
165115240jeff *      - Redistributions of source code must retain the above
175115240jeff *        copyright notice, this list of conditions and the following
185115240jeff *        disclaimer.
195115240jeff *
205115240jeff *      - Redistributions in binary form must reproduce the above
215115240jeff *        copyright notice, this list of conditions and the following
225115240jeff *        disclaimer in the documentation and/or other materials
235115240jeff *        provided with the distribution.
245115240jeff *
255115240jeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
265115240jeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
275115240jeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
285115240jeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
295115240jeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
305115240jeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
315115240jeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
325115240jeff * SOFTWARE.
335115240jeff *
345115240jeff */
355115240jeff
365115240jeff#if HAVE_CONFIG_H
375115240jeff#  include <config.h>
385115240jeff#endif				/* HAVE_CONFIG_H */
395115240jeff
40c187222hselasky#define	_WITH_GETLINE		/* for getline */
415115240jeff#include <stdio.h>
425115240jeff#include <stdlib.h>
435115240jeff#include <sys/poll.h>
445115240jeff#include <sys/types.h>
455115240jeff#include <sys/socket.h>
465115240jeff#include <netdb.h>
47c187222hselasky#include <regex.h>
48c187222hselasky#ifdef ENABLE_OSM_CONSOLE_LOOPBACK
495115240jeff#include <arpa/inet.h>
50c187222hselasky#include <netinet/in.h>
51c187222hselasky#include <sys/socket.h>
525115240jeff#endif
535115240jeff#include <unistd.h>
545115240jeff#include <errno.h>
555115240jeff#include <ctype.h>
565115240jeff#include <sys/time.h>
57c187222hselasky#include <opensm/osm_file_ids.h>
58c187222hselasky#define FILE_ID OSM_FILE_CONSOLE_C
595115240jeff#include <opensm/osm_console.h>
605115240jeff#include <complib/cl_passivelock.h>
615115240jeff#include <opensm/osm_perfmgr.h>
625115240jeff#include <opensm/osm_subnet.h>
635115240jeff
64c187222hselaskyextern void osm_update_node_desc(IN osm_opensm_t *osm);
65c187222hselasky
665115240jeffstruct command {
67c187222hselasky	const char *name;
685115240jeff	void (*help_function) (FILE * out, int detail);
695115240jeff	void (*parse_function) (char **p_last, osm_opensm_t * p_osm,
705115240jeff				FILE * out);
715115240jeff};
725115240jeff
735115240jeffstatic struct {
745115240jeff	int on;
755115240jeff	int delay_s;
765115240jeff	time_t previous;
775115240jeff	void (*loop_function) (osm_opensm_t * p_osm, FILE * out);
785115240jeff} loop_command = {
79c187222hselasky.on = 0, .delay_s = 2, .loop_function = NULL};
805115240jeff
815115240jeffstatic const struct command console_cmds[];
825115240jeff
83c187222hselaskystatic char *next_token(char **p_last)
845115240jeff{
855115240jeff	return strtok_r(NULL, " \t\n\r", p_last);
865115240jeff}
875115240jeff
88c187222hselasky#ifdef ENABLE_OSM_PERF_MGR
89c187222hselaskystatic char *name_token(char **p_last)
90c187222hselasky{
91c187222hselasky	return strtok_r(NULL, "\t\n\r", p_last);
92c187222hselasky}
93c187222hselasky#endif
94c187222hselasky
955115240jeffstatic void help_command(FILE * out, int detail)
965115240jeff{
975115240jeff	int i;
985115240jeff
995115240jeff	fprintf(out, "Supported commands and syntax:\n");
1005115240jeff	fprintf(out, "help [<command>]\n");
1015115240jeff	/* skip help command */
1025115240jeff	for (i = 1; console_cmds[i].name; i++)
1035115240jeff		console_cmds[i].help_function(out, 0);
1045115240jeff}
1055115240jeff
1065115240jeffstatic void help_quit(FILE * out, int detail)
1075115240jeff{
1085115240jeff	fprintf(out, "quit (not valid in local mode; use ctl-c)\n");
1095115240jeff}
1105115240jeff
1115115240jeffstatic void help_loglevel(FILE * out, int detail)
1125115240jeff{
1135115240jeff	fprintf(out, "loglevel [<log-level>]\n");
1145115240jeff	if (detail) {
1155115240jeff		fprintf(out, "   log-level is OR'ed from the following\n");
1165115240jeff		fprintf(out, "   OSM_LOG_NONE             0x%02X\n",
1175115240jeff			OSM_LOG_NONE);
1185115240jeff		fprintf(out, "   OSM_LOG_ERROR            0x%02X\n",
1195115240jeff			OSM_LOG_ERROR);
1205115240jeff		fprintf(out, "   OSM_LOG_INFO             0x%02X\n",
1215115240jeff			OSM_LOG_INFO);
1225115240jeff		fprintf(out, "   OSM_LOG_VERBOSE          0x%02X\n",
1235115240jeff			OSM_LOG_VERBOSE);
1245115240jeff		fprintf(out, "   OSM_LOG_DEBUG            0x%02X\n",
1255115240jeff			OSM_LOG_DEBUG);
1265115240jeff		fprintf(out, "   OSM_LOG_FUNCS            0x%02X\n",
1275115240jeff			OSM_LOG_FUNCS);
1285115240jeff		fprintf(out, "   OSM_LOG_FRAMES           0x%02X\n",
1295115240jeff			OSM_LOG_FRAMES);
1305115240jeff		fprintf(out, "   OSM_LOG_ROUTING          0x%02X\n",
1315115240jeff			OSM_LOG_ROUTING);
1325115240jeff		fprintf(out, "   OSM_LOG_SYS              0x%02X\n",
1335115240jeff			OSM_LOG_SYS);
1345115240jeff		fprintf(out, "\n");
1355115240jeff		fprintf(out, "   OSM_LOG_DEFAULT_LEVEL    0x%02X\n",
1365115240jeff			OSM_LOG_DEFAULT_LEVEL);
1375115240jeff	}
1385115240jeff}
1395115240jeff
140c187222hselaskystatic void help_permodlog(FILE * out, int detail)
141c187222hselasky{
142c187222hselasky	fprintf(out, "permodlog\n");
143c187222hselasky}
144c187222hselasky
1455115240jeffstatic void help_priority(FILE * out, int detail)
1465115240jeff{
1475115240jeff	fprintf(out, "priority [<sm-priority>]\n");
1485115240jeff}
1495115240jeff
1505115240jeffstatic void help_resweep(FILE * out, int detail)
1515115240jeff{
1525115240jeff	fprintf(out, "resweep [heavy|light]\n");
1535115240jeff}
1545115240jeff
1555115240jeffstatic void help_reroute(FILE * out, int detail)
1565115240jeff{
1575115240jeff	fprintf(out, "reroute\n");
1585115240jeff	if (detail) {
1595115240jeff		fprintf(out, "reroute the fabric\n");
1605115240jeff	}
1615115240jeff}
1625115240jeff
163c187222hselaskystatic void help_sweep(FILE * out, int detail)
164c187222hselasky{
165c187222hselasky	fprintf(out, "sweep [on|off]\n");
166c187222hselasky	if (detail) {
167c187222hselasky		fprintf(out, "enable or disable sweeping\n");
168c187222hselasky		fprintf(out, "   [on] sweep normally\n");
169c187222hselasky		fprintf(out, "   [off] inhibit all sweeping\n");
170c187222hselasky	}
171c187222hselasky}
172c187222hselasky
1735115240jeffstatic void help_status(FILE * out, int detail)
1745115240jeff{
1755115240jeff	fprintf(out, "status [loop]\n");
1765115240jeff	if (detail) {
1775115240jeff		fprintf(out, "   loop -- type \"q<ret>\" to quit\n");
1785115240jeff	}
1795115240jeff}
1805115240jeff
1815115240jeffstatic void help_logflush(FILE * out, int detail)
1825115240jeff{
183c187222hselasky	fprintf(out, "logflush [on|off] -- toggle opensm.log file flushing\n");
1845115240jeff}
1855115240jeff
1865115240jeffstatic void help_querylid(FILE * out, int detail)
1875115240jeff{
1885115240jeff	fprintf(out,
1895115240jeff		"querylid lid -- print internal information about the lid specified\n");
1905115240jeff}
1915115240jeff
1925115240jeffstatic void help_portstatus(FILE * out, int detail)
1935115240jeff{
1945115240jeff	fprintf(out, "portstatus [ca|switch|router]\n");
1955115240jeff	if (detail) {
1965115240jeff		fprintf(out, "summarize port status\n");
1975115240jeff		fprintf(out,
1985115240jeff			"   [ca|switch|router] -- limit the results to the node type specified\n");
1995115240jeff	}
2005115240jeff
2015115240jeff}
2025115240jeff
2035115240jeffstatic void help_switchbalance(FILE * out, int detail)
2045115240jeff{
2055115240jeff	fprintf(out, "switchbalance [verbose] [guid]\n");
2065115240jeff	if (detail) {
2075115240jeff		fprintf(out, "output switch balancing information\n");
2085115240jeff		fprintf(out,
2095115240jeff			"  [verbose] -- verbose output\n"
2105115240jeff			"  [guid] -- limit results to specified guid\n");
2115115240jeff	}
2125115240jeff}
2135115240jeff
2145115240jeffstatic void help_lidbalance(FILE * out, int detail)
2155115240jeff{
2165115240jeff	fprintf(out, "lidbalance [switchguid]\n");
2175115240jeff	if (detail) {
2185115240jeff		fprintf(out, "output lid balanced forwarding information\n");
2195115240jeff		fprintf(out,
2205115240jeff			"  [switchguid] -- limit results to specified switch guid\n");
2215115240jeff	}
2225115240jeff}
2235115240jeff
2245115240jeffstatic void help_dump_conf(FILE *out, int detail)
2255115240jeff{
2265115240jeff	fprintf(out, "dump_conf\n");
2275115240jeff	if (detail) {
2285115240jeff		fprintf(out, "dump current opensm configuration\n");
2295115240jeff	}
2305115240jeff}
2315115240jeff
232c187222hselaskystatic void help_update_desc(FILE *out, int detail)
233c187222hselasky{
234c187222hselasky	fprintf(out, "update_desc\n");
235c187222hselasky	if (detail) {
236c187222hselasky		fprintf(out, "update node description for all nodes\n");
237c187222hselasky	}
238c187222hselasky}
239c187222hselasky
2405115240jeff#ifdef ENABLE_OSM_PERF_MGR
2415115240jeffstatic void help_perfmgr(FILE * out, int detail)
2425115240jeff{
2435115240jeff	fprintf(out,
244c187222hselasky		"perfmgr(pm) [enable|disable\n"
245c187222hselasky		"             |clear_counters|dump_counters|print_counters(pc)|print_errors(pe)\n"
246c187222hselasky		"             |set_rm_nodes|clear_rm_nodes|clear_inactive\n"
247c187222hselasky		"             |set_query_cpi|clear_query_cpi\n"
248c187222hselasky		"             |dump_redir|clear_redir\n"
249c187222hselasky		"             |sweep|sweep_time[seconds]]\n");
2505115240jeff	if (detail) {
2515115240jeff		fprintf(out,
2525115240jeff			"perfmgr -- print the performance manager state\n");
2535115240jeff		fprintf(out,
2545115240jeff			"   [enable|disable] -- change the perfmgr state\n");
2555115240jeff		fprintf(out,
256c187222hselasky			"   [sweep] -- Initiate a sweep of the fabric\n");
257c187222hselasky		fprintf(out,
2585115240jeff			"   [sweep_time] -- change the perfmgr sweep time (requires [seconds] option)\n");
2595115240jeff		fprintf(out,
2605115240jeff			"   [clear_counters] -- clear the counters stored\n");
2615115240jeff		fprintf(out,
2625115240jeff			"   [dump_counters [mach]] -- dump the counters (optionally in [mach]ine readable format)\n");
2635115240jeff		fprintf(out,
264c187222hselasky			"   [print_counters [<nodename|nodeguid>][:<port>]] -- print the internal counters\n"
265c187222hselasky			"                                                      Optionally limit output by name, guid, or port\n");
266c187222hselasky		fprintf(out,
267c187222hselasky			"   [pc [<nodename|nodeguid>][:<port>]] -- same as print_counters\n");
268c187222hselasky		fprintf(out,
269c187222hselasky			"   [print_errors [<nodename|nodeguid>]] -- print only ports with errors\n"
270c187222hselasky			"                                           Optionally limit output by name or guid\n");
271c187222hselasky		fprintf(out,
272c187222hselasky			"   [pe [<nodename|nodeguid>]] -- same as print_errors\n");
273c187222hselasky		fprintf(out,
274c187222hselasky			"   [dump_redir [<nodename|nodeguid>]] -- dump the redirection table\n");
275c187222hselasky		fprintf(out,
276c187222hselasky			"   [clear_redir [<nodename|nodeguid>]] -- clear the redirection table\n");
277c187222hselasky		fprintf(out,
278c187222hselasky			"   [[set|clear]_rm_nodes] -- enable/disable the removal of \"inactive\" nodes from the DB\n"
279c187222hselasky			"                             Inactive nodes are those which no longer appear on the fabric\n");
280c187222hselasky		fprintf(out,
281c187222hselasky			"   [[set|clear]_query_cpi] -- enable/disable PerfMgrGet(ClassPortInfo)\n"
282c187222hselasky			"                             ClassPortInfo indicates hardware support for extended attributes such as PortCountersExtended\n");
283c187222hselasky		fprintf(out,
284c187222hselasky			"   [clear_inactive] -- Delete inactive nodes from the DB\n");
2855115240jeff	}
2865115240jeff}
287c187222hselaskystatic void help_pm(FILE *out, int detail)
288c187222hselasky{
289c187222hselasky	if (detail)
290c187222hselasky		help_perfmgr(out, detail);
291c187222hselasky}
2925115240jeff#endif				/* ENABLE_OSM_PERF_MGR */
2935115240jeff
2945115240jeff/* more help routines go here */
2955115240jeff
2965115240jeffstatic void help_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
2975115240jeff{
2985115240jeff	char *p_cmd;
2995115240jeff	int i, found = 0;
3005115240jeff
3015115240jeff	p_cmd = next_token(p_last);
3025115240jeff	if (!p_cmd)
3035115240jeff		help_command(out, 0);
3045115240jeff	else {
3055115240jeff		for (i = 1; console_cmds[i].name; i++) {
3065115240jeff			if (!strcmp(p_cmd, console_cmds[i].name)) {
3075115240jeff				found = 1;
3085115240jeff				console_cmds[i].help_function(out, 1);
3095115240jeff				break;
3105115240jeff			}
3115115240jeff		}
3125115240jeff		if (!found) {
3135115240jeff			fprintf(out, "%s : Command not found\n\n", p_cmd);
3145115240jeff			help_command(out, 0);
3155115240jeff		}
3165115240jeff	}
3175115240jeff}
3185115240jeff
3195115240jeffstatic void loglevel_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
3205115240jeff{
3215115240jeff	char *p_cmd;
3225115240jeff	int level;
3235115240jeff
3245115240jeff	p_cmd = next_token(p_last);
3255115240jeff	if (!p_cmd)
3265115240jeff		fprintf(out, "Current log level is 0x%x\n",
3275115240jeff			osm_log_get_level(&p_osm->log));
3285115240jeff	else {
3295115240jeff		/* Handle x, 0x, and decimal specification of log level */
3305115240jeff		if (!strncmp(p_cmd, "x", 1)) {
3315115240jeff			p_cmd++;
3325115240jeff			level = strtoul(p_cmd, NULL, 16);
3335115240jeff		} else {
3345115240jeff			if (!strncmp(p_cmd, "0x", 2)) {
3355115240jeff				p_cmd += 2;
3365115240jeff				level = strtoul(p_cmd, NULL, 16);
3375115240jeff			} else
3385115240jeff				level = strtol(p_cmd, NULL, 10);
3395115240jeff		}
3405115240jeff		if ((level >= 0) && (level < 256)) {
3415115240jeff			fprintf(out, "Setting log level to 0x%x\n", level);
3425115240jeff			osm_log_set_level(&p_osm->log, level);
3435115240jeff		} else
3445115240jeff			fprintf(out, "Invalid log level 0x%x\n", level);
3455115240jeff	}
3465115240jeff}
3475115240jeff
348c187222hselaskystatic void permodlog_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
349c187222hselasky{
350c187222hselasky	FILE *fp;
351c187222hselasky	char buf[1024];
352c187222hselasky
353c187222hselasky	if (p_osm->subn.opt.per_module_logging_file != NULL) {
354c187222hselasky		fp = fopen(p_osm->subn.opt.per_module_logging_file, "r");
355c187222hselasky		if (!fp) {
356c187222hselasky			if (errno == ENOENT)
357c187222hselasky				return;
358c187222hselasky			fprintf(out, "fopen(%s) failed: %s\n",
359c187222hselasky				p_osm->subn.opt.per_module_logging_file,
360c187222hselasky				strerror(errno));
361c187222hselasky			return;
362c187222hselasky		}
363c187222hselasky
364c187222hselasky		fprintf(out, "Per module logging file: %s\n",
365c187222hselasky			p_osm->subn.opt.per_module_logging_file);
366c187222hselasky		while (fgets(buf, sizeof buf, fp) != NULL)
367c187222hselasky			fprintf(out, "%s", buf);
368c187222hselasky		fclose(fp);
369c187222hselasky		fprintf(out, "\n");
370c187222hselasky	}
371c187222hselasky}
372c187222hselasky
3735115240jeffstatic void priority_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
3745115240jeff{
3755115240jeff	char *p_cmd;
3765115240jeff	int priority;
3775115240jeff
3785115240jeff	p_cmd = next_token(p_last);
3795115240jeff	if (!p_cmd)
3805115240jeff		fprintf(out, "Current sm-priority is %d\n",
3815115240jeff			p_osm->subn.opt.sm_priority);
3825115240jeff	else {
3835115240jeff		priority = strtol(p_cmd, NULL, 0);
3845115240jeff		if (0 > priority || 15 < priority)
3855115240jeff			fprintf(out,
3865115240jeff				"Invalid sm-priority %d; must be between 0 and 15\n",
3875115240jeff				priority);
3885115240jeff		else {
3895115240jeff			fprintf(out, "Setting sm-priority to %d\n", priority);
3905115240jeff			osm_set_sm_priority(&p_osm->sm, (uint8_t)priority);
3915115240jeff		}
3925115240jeff	}
3935115240jeff}
3945115240jeff
395c187222hselaskystatic const char *sm_state_str(int state)
3965115240jeff{
3975115240jeff	switch (state) {
3985115240jeff	case IB_SMINFO_STATE_DISCOVERING:
399c187222hselasky		return "Discovering";
4005115240jeff	case IB_SMINFO_STATE_STANDBY:
401c187222hselasky		return "Standby    ";
4025115240jeff	case IB_SMINFO_STATE_NOTACTIVE:
403c187222hselasky		return "Not Active ";
4045115240jeff	case IB_SMINFO_STATE_MASTER:
405c187222hselasky		return "Master     ";
4065115240jeff	}
407c187222hselasky	return "UNKNOWN    ";
4085115240jeff}
4095115240jeff
410c187222hselaskystatic const char *sa_state_str(osm_sa_state_t state)
4115115240jeff{
4125115240jeff	switch (state) {
4135115240jeff	case OSM_SA_STATE_INIT:
414c187222hselasky		return "Init";
4155115240jeff	case OSM_SA_STATE_READY:
416c187222hselasky		return "Ready";
4175115240jeff	}
418c187222hselasky	return "UNKNOWN";
419c187222hselasky}
420c187222hselasky
421c187222hselaskystatic void dump_sms(osm_opensm_t * p_osm, FILE * out)
422c187222hselasky{
423c187222hselasky	osm_subn_t *p_subn = &p_osm->subn;
424c187222hselasky	osm_remote_sm_t *p_rsm;
425c187222hselasky
426c187222hselasky	fprintf(out, "\n   Known SMs\n"
427c187222hselasky		     "   ---------\n");
428c187222hselasky	fprintf(out, "   Port GUID       SM State    Priority\n");
429c187222hselasky	fprintf(out, "   ---------       --------    --------\n");
430c187222hselasky	fprintf(out, "   0x%" PRIx64 " %s %d        SELF\n",
431c187222hselasky		cl_ntoh64(p_subn->sm_port_guid),
432c187222hselasky		sm_state_str(p_subn->sm_state),
433c187222hselasky		p_subn->opt.sm_priority);
434c187222hselasky
435c187222hselasky	CL_PLOCK_ACQUIRE(p_osm->sm.p_lock);
436c187222hselasky	p_rsm = (osm_remote_sm_t *) cl_qmap_head(&p_subn->sm_guid_tbl);
437c187222hselasky	while (p_rsm != (osm_remote_sm_t *) cl_qmap_end(&p_subn->sm_guid_tbl)) {
438c187222hselasky		fprintf(out, "   0x%" PRIx64 " %s %d\n",
439c187222hselasky			cl_ntoh64(p_rsm->smi.guid),
440c187222hselasky			sm_state_str(ib_sminfo_get_state(&p_rsm->smi)),
441c187222hselasky			ib_sminfo_get_priority(&p_rsm->smi));
442c187222hselasky		p_rsm = (osm_remote_sm_t *) cl_qmap_next(&p_rsm->map_item);
443c187222hselasky	}
444c187222hselasky	CL_PLOCK_RELEASE(p_osm->sm.p_lock);
4455115240jeff}
4465115240jeff
4475115240jeffstatic void print_status(osm_opensm_t * p_osm, FILE * out)
4485115240jeff{
4495115240jeff	cl_list_item_t *item;
4505115240jeff
4515115240jeff	if (out) {
452c187222hselasky		const char *re_str;
453c187222hselasky
4545115240jeff		cl_plock_acquire(&p_osm->lock);
4555115240jeff		fprintf(out, "   OpenSM Version       : %s\n", p_osm->osm_version);
4565115240jeff		fprintf(out, "   SM State             : %s\n",
4575115240jeff			sm_state_str(p_osm->subn.sm_state));
458c187222hselasky		fprintf(out, "   SM Priority          : %d\n",
459c187222hselasky			p_osm->subn.opt.sm_priority);
4605115240jeff		fprintf(out, "   SA State             : %s\n",
4615115240jeff			sa_state_str(p_osm->sa.state));
462c187222hselasky
463c187222hselasky		re_str = p_osm->routing_engine_used ?
464c187222hselasky			osm_routing_engine_type_str(p_osm->routing_engine_used->type) :
465c187222hselasky			osm_routing_engine_type_str(OSM_ROUTING_ENGINE_TYPE_NONE);
466c187222hselasky		fprintf(out, "   Routing Engine       : %s\n", re_str);
4675115240jeff
4685115240jeff		fprintf(out, "   Loaded event plugins :");
4695115240jeff		if (cl_qlist_head(&p_osm->plugin_list) ==
4705115240jeff			cl_qlist_end(&p_osm->plugin_list)) {
4715115240jeff			fprintf(out, " <none>");
4725115240jeff		}
4735115240jeff		for (item = cl_qlist_head(&p_osm->plugin_list);
4745115240jeff		     item != cl_qlist_end(&p_osm->plugin_list);
4755115240jeff		     item = cl_qlist_next(item))
4765115240jeff			fprintf(out, " %s",
4775115240jeff				((osm_epi_plugin_t *)item)->plugin_name);
4785115240jeff		fprintf(out, "\n");
4795115240jeff
4805115240jeff#ifdef ENABLE_OSM_PERF_MGR
4815115240jeff		fprintf(out, "\n   PerfMgr state/sweep state : %s/%s\n",
482c187222hselasky			osm_perfmgr_get_state_str(&p_osm->perfmgr),
483c187222hselasky			osm_perfmgr_get_sweep_state_str(&p_osm->perfmgr));
4845115240jeff#endif
4855115240jeff		fprintf(out, "\n   MAD stats\n"
4865115240jeff			"   ---------\n"
487c187222hselasky			"   QP0 MADs outstanding           : %u\n"
488c187222hselasky			"   QP0 MADs outstanding (on wire) : %u\n"
489c187222hselasky			"   QP0 MADs rcvd                  : %u\n"
490c187222hselasky			"   QP0 MADs sent                  : %u\n"
491c187222hselasky			"   QP0 unicasts sent              : %u\n"
492c187222hselasky			"   QP0 unknown MADs rcvd          : %u\n"
493c187222hselasky			"   SA MADs outstanding            : %u\n"
494c187222hselasky			"   SA MADs rcvd                   : %u\n"
495c187222hselasky			"   SA MADs sent                   : %u\n"
496c187222hselasky			"   SA unknown MADs rcvd           : %u\n"
497c187222hselasky			"   SA MADs ignored                : %u\n",
498c187222hselasky			(uint32_t)p_osm->stats.qp0_mads_outstanding,
499c187222hselasky			(uint32_t)p_osm->stats.qp0_mads_outstanding_on_wire,
500c187222hselasky			(uint32_t)p_osm->stats.qp0_mads_rcvd,
501c187222hselasky			(uint32_t)p_osm->stats.qp0_mads_sent,
502c187222hselasky			(uint32_t)p_osm->stats.qp0_unicasts_sent,
503c187222hselasky			(uint32_t)p_osm->stats.qp0_mads_rcvd_unknown,
504c187222hselasky			(uint32_t)p_osm->stats.sa_mads_outstanding,
505c187222hselasky			(uint32_t)p_osm->stats.sa_mads_rcvd,
506c187222hselasky			(uint32_t)p_osm->stats.sa_mads_sent,
507c187222hselasky			(uint32_t)p_osm->stats.sa_mads_rcvd_unknown,
508c187222hselasky			(uint32_t)p_osm->stats.sa_mads_ignored);
5095115240jeff		fprintf(out, "\n   Subnet flags\n"
5105115240jeff			"   ------------\n"
511c187222hselasky			"   Sweeping enabled               : %d\n"
512c187222hselasky			"   Sweep interval (seconds)       : %u\n"
5135115240jeff			"   Ignore existing lfts           : %d\n"
5145115240jeff			"   Subnet Init errors             : %d\n"
5155115240jeff			"   In sweep hop 0                 : %d\n"
5165115240jeff			"   First time master sweep        : %d\n"
5175115240jeff			"   Coming out of standby          : %d\n",
518c187222hselasky			p_osm->subn.sweeping_enabled,
519c187222hselasky			p_osm->subn.opt.sweep_interval,
5205115240jeff			p_osm->subn.ignore_existing_lfts,
5215115240jeff			p_osm->subn.subnet_initialization_error,
5225115240jeff			p_osm->subn.in_sweep_hop_0,
5235115240jeff			p_osm->subn.first_time_master_sweep,
5245115240jeff			p_osm->subn.coming_out_of_standby);
525c187222hselasky		dump_sms(p_osm, out);
5265115240jeff		fprintf(out, "\n");
5275115240jeff		cl_plock_release(&p_osm->lock);
5285115240jeff	}
5295115240jeff}
5305115240jeff
5315115240jeffstatic int loop_command_check_time(void)
5325115240jeff{
5335115240jeff	time_t cur = time(NULL);
5345115240jeff	if ((loop_command.previous + loop_command.delay_s) < cur) {
5355115240jeff		loop_command.previous = cur;
536c187222hselasky		return 1;
5375115240jeff	}
538c187222hselasky	return 0;
5395115240jeff}
5405115240jeff
5415115240jeffstatic void status_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
5425115240jeff{
5435115240jeff	char *p_cmd;
5445115240jeff
5455115240jeff	p_cmd = next_token(p_last);
5465115240jeff	if (p_cmd) {
5475115240jeff		if (strcmp(p_cmd, "loop") == 0) {
5485115240jeff			fprintf(out, "Looping on status command...\n");
5495115240jeff			fflush(out);
5505115240jeff			loop_command.on = 1;
5515115240jeff			loop_command.previous = time(NULL);
5525115240jeff			loop_command.loop_function = print_status;
5535115240jeff		} else {
5545115240jeff			help_status(out, 1);
5555115240jeff			return;
5565115240jeff		}
5575115240jeff	}
5585115240jeff	print_status(p_osm, out);
5595115240jeff}
5605115240jeff
5615115240jeffstatic void resweep_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
5625115240jeff{
5635115240jeff	char *p_cmd;
5645115240jeff
5655115240jeff	p_cmd = next_token(p_last);
5665115240jeff	if (!p_cmd ||
5675115240jeff	    (strcmp(p_cmd, "heavy") != 0 && strcmp(p_cmd, "light") != 0)) {
5685115240jeff		fprintf(out, "Invalid resweep command\n");
5695115240jeff		help_resweep(out, 1);
5705115240jeff	} else {
5715115240jeff		if (strcmp(p_cmd, "heavy") == 0)
5725115240jeff			p_osm->subn.force_heavy_sweep = TRUE;
5735115240jeff		osm_opensm_sweep(p_osm);
5745115240jeff	}
5755115240jeff}
5765115240jeff
5775115240jeffstatic void reroute_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
5785115240jeff{
5795115240jeff	p_osm->subn.force_reroute = TRUE;
5805115240jeff	osm_opensm_sweep(p_osm);
5815115240jeff}
5825115240jeff
583c187222hselaskystatic void sweep_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
584c187222hselasky{
585c187222hselasky	char *p_cmd;
586c187222hselasky
587c187222hselasky	p_cmd = next_token(p_last);
588c187222hselasky	if (!p_cmd ||
589c187222hselasky	    (strcmp(p_cmd, "on") != 0 && strcmp(p_cmd, "off") != 0)) {
590c187222hselasky		fprintf(out, "Invalid sweep command\n");
591c187222hselasky		help_sweep(out, 1);
592c187222hselasky	} else {
593c187222hselasky		if (strcmp(p_cmd, "on") == 0)
594c187222hselasky			p_osm->subn.sweeping_enabled = TRUE;
595c187222hselasky		else
596c187222hselasky			p_osm->subn.sweeping_enabled = FALSE;
597c187222hselasky	}
598c187222hselasky}
599c187222hselasky
6005115240jeffstatic void logflush_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
6015115240jeff{
602c187222hselasky	char *p_cmd;
603c187222hselasky
604c187222hselasky	p_cmd = next_token(p_last);
605c187222hselasky	if (!p_cmd ||
606c187222hselasky	    (strcmp(p_cmd, "on") != 0 && strcmp(p_cmd, "off") != 0)) {
607c187222hselasky		fprintf(out, "Invalid logflush command\n");
608c187222hselasky		help_sweep(out, 1);
609c187222hselasky	} else {
610c187222hselasky		if (strcmp(p_cmd, "on") == 0) {
611c187222hselasky			p_osm->log.flush = TRUE;
612c187222hselasky	                fflush(p_osm->log.out_port);
613c187222hselasky		} else
614c187222hselasky			p_osm->log.flush = FALSE;
615c187222hselasky	}
6165115240jeff}
6175115240jeff
6185115240jeffstatic void querylid_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
6195115240jeff{
620c187222hselasky	unsigned int p = 0;
6215115240jeff	uint16_t lid = 0;
6225115240jeff	osm_port_t *p_port = NULL;
6235115240jeff	char *p_cmd = next_token(p_last);
6245115240jeff
6255115240jeff	if (!p_cmd) {
6265115240jeff		fprintf(out, "no LID specified\n");
6275115240jeff		help_querylid(out, 1);
6285115240jeff		return;
6295115240jeff	}
6305115240jeff
6315115240jeff	lid = (uint16_t) strtoul(p_cmd, NULL, 0);
6325115240jeff	cl_plock_acquire(&p_osm->lock);
633c187222hselasky	p_port = osm_get_port_by_lid_ho(&p_osm->subn, lid);
6345115240jeff	if (!p_port)
6355115240jeff		goto invalid_lid;
6365115240jeff
6375115240jeff	fprintf(out, "Query results for LID %u\n", lid);
6385115240jeff	fprintf(out,
6395115240jeff		"   GUID                : 0x%016" PRIx64 "\n"
6405115240jeff		"   Node Desc           : %s\n"
6415115240jeff		"   Node Type           : %s\n"
6425115240jeff		"   Num Ports           : %d\n",
6435115240jeff		cl_ntoh64(p_port->guid),
6445115240jeff		p_port->p_node->print_desc,
6455115240jeff		ib_get_node_type_str(osm_node_get_type(p_port->p_node)),
6465115240jeff		p_port->p_node->node_info.num_ports);
6475115240jeff
6485115240jeff	if (p_port->p_node->sw)
6495115240jeff		p = 0;
6505115240jeff	else
6515115240jeff		p = 1;
6525115240jeff	for ( /* see above */ ; p < p_port->p_node->physp_tbl_size; p++) {
6535115240jeff		fprintf(out,
654c187222hselasky			"   Port %u health       : %s\n",
6555115240jeff			p,
6565115240jeff			p_port->p_node->physp_table[p].
6575115240jeff			healthy ? "OK" : "ERROR");
6585115240jeff	}
6595115240jeff
6605115240jeff	cl_plock_release(&p_osm->lock);
6615115240jeff	return;
6625115240jeff
6635115240jeffinvalid_lid:
6645115240jeff	cl_plock_release(&p_osm->lock);
6655115240jeff	fprintf(out, "Invalid lid %d\n", lid);
6665115240jeff	return;
6675115240jeff}
6685115240jeff
6695115240jeff/**
6705115240jeff * Data structures for the portstatus command
6715115240jeff */
6725115240jefftypedef struct _port_report {
6735115240jeff	struct _port_report *next;
6745115240jeff	uint64_t node_guid;
6755115240jeff	uint8_t port_num;
6765115240jeff	char print_desc[IB_NODE_DESCRIPTION_SIZE + 1];
6775115240jeff} port_report_t;
6785115240jeff
6795115240jeffstatic void
6805115240jeff__tag_port_report(port_report_t ** head, uint64_t node_guid,
6815115240jeff		  uint8_t port_num, char *print_desc)
6825115240jeff{
6835115240jeff	port_report_t *rep = malloc(sizeof(*rep));
6845115240jeff	if (!rep)
6855115240jeff		return;
6865115240jeff
6875115240jeff	rep->node_guid = node_guid;
6885115240jeff	rep->port_num = port_num;
6895115240jeff	memcpy(rep->print_desc, print_desc, IB_NODE_DESCRIPTION_SIZE + 1);
6905115240jeff	rep->next = NULL;
6915115240jeff	if (*head) {
6925115240jeff		rep->next = *head;
6935115240jeff		*head = rep;
6945115240jeff	} else
6955115240jeff		*head = rep;
6965115240jeff}
6975115240jeff
6985115240jeffstatic void __print_port_report(FILE * out, port_report_t * head)
6995115240jeff{
7005115240jeff	port_report_t *item = head;
7015115240jeff	while (item != NULL) {
7025115240jeff		fprintf(out, "      0x%016" PRIx64 " %d (%s)\n",
7035115240jeff			item->node_guid, item->port_num, item->print_desc);
7045115240jeff		port_report_t *next = item->next;
7055115240jeff		free(item);
7065115240jeff		item = next;
7075115240jeff	}
7085115240jeff}
7095115240jeff
7105115240jefftypedef struct {
7115115240jeff	uint8_t node_type_lim;	/* limit the results; 0 == ALL */
7125115240jeff	uint64_t total_nodes;
7135115240jeff	uint64_t total_ports;
7145115240jeff	uint64_t ports_down;
7155115240jeff	uint64_t ports_active;
7165115240jeff	uint64_t ports_disabled;
7175115240jeff	port_report_t *disabled_ports;
7185115240jeff	uint64_t ports_1X;
7195115240jeff	uint64_t ports_4X;
7205115240jeff	uint64_t ports_8X;
7215115240jeff	uint64_t ports_12X;
722c187222hselasky	uint64_t ports_2X;
7235115240jeff	uint64_t ports_unknown_width;
724c187222hselasky	port_report_t *unknown_width_ports;
725c187222hselasky	uint64_t ports_unenabled_width;
726c187222hselasky	port_report_t *unenabled_width_ports;
7275115240jeff	uint64_t ports_reduced_width;
7285115240jeff	port_report_t *reduced_width_ports;
7295115240jeff	uint64_t ports_sdr;
7305115240jeff	uint64_t ports_ddr;
7315115240jeff	uint64_t ports_qdr;
732c187222hselasky	uint64_t ports_fdr10;
733c187222hselasky	uint64_t ports_fdr;
734c187222hselasky	uint64_t ports_edr;
7355115240jeff	uint64_t ports_unknown_speed;
736c187222hselasky	port_report_t *unknown_speed_ports;
737c187222hselasky	uint64_t ports_unenabled_speed;
738c187222hselasky	port_report_t *unenabled_speed_ports;
7395115240jeff	uint64_t ports_reduced_speed;
7405115240jeff	port_report_t *reduced_speed_ports;
7415115240jeff} fabric_stats_t;
7425115240jeff
7435115240jeff/**
7445115240jeff * iterator function to get portstatus on each node
7455115240jeff */
7465115240jeffstatic void __get_stats(cl_map_item_t * const p_map_item, void *context)
7475115240jeff{
7485115240jeff	fabric_stats_t *fs = (fabric_stats_t *) context;
7495115240jeff	osm_node_t *node = (osm_node_t *) p_map_item;
750c187222hselasky	osm_physp_t *physp0;
751c187222hselasky	ib_port_info_t *pi0;
7525115240jeff	uint8_t num_ports = osm_node_get_num_physp(node);
7535115240jeff	uint8_t port = 0;
7545115240jeff
7555115240jeff	/* Skip nodes we are not interested in */
7565115240jeff	if (fs->node_type_lim != 0
7575115240jeff	    && fs->node_type_lim != node->node_info.node_type)
7585115240jeff		return;
7595115240jeff
7605115240jeff	fs->total_nodes++;
7615115240jeff
762c187222hselasky	if (osm_node_get_type(node) == IB_NODE_TYPE_SWITCH) {
763c187222hselasky		physp0 = osm_node_get_physp_ptr(node, 0);
764c187222hselasky		pi0 = &physp0->port_info;
765c187222hselasky	} else
766c187222hselasky		pi0 = NULL;
767c187222hselasky
7685115240jeff	for (port = 1; port < num_ports; port++) {
7695115240jeff		osm_physp_t *phys = osm_node_get_physp_ptr(node, port);
7705115240jeff		ib_port_info_t *pi = NULL;
771c187222hselasky		ib_mlnx_ext_port_info_t *epi = NULL;
7725115240jeff		uint8_t active_speed = 0;
7735115240jeff		uint8_t enabled_speed = 0;
7745115240jeff		uint8_t active_width = 0;
7755115240jeff		uint8_t enabled_width = 0;
7765115240jeff		uint8_t port_state = 0;
7775115240jeff		uint8_t port_phys_state = 0;
7785115240jeff
7795115240jeff		if (!phys)
7805115240jeff			continue;
7815115240jeff
782c187222hselasky		pi = &phys->port_info;
783c187222hselasky		epi = &phys->ext_port_info;
784c187222hselasky		if (!pi0)
785c187222hselasky			pi0 = pi;
7865115240jeff		active_speed = ib_port_info_get_link_speed_active(pi);
7875115240jeff		enabled_speed = ib_port_info_get_link_speed_enabled(pi);
7885115240jeff		active_width = pi->link_width_active;
7895115240jeff		enabled_width = pi->link_width_enabled;
7905115240jeff		port_state = ib_port_info_get_port_state(pi);
7915115240jeff		port_phys_state = ib_port_info_get_port_phys_state(pi);
7925115240jeff
793c187222hselasky		if (port_state == IB_LINK_DOWN)
794c187222hselasky			fs->ports_down++;
795c187222hselasky		else if (port_state == IB_LINK_ACTIVE)
796c187222hselasky			fs->ports_active++;
797c187222hselasky		if (port_phys_state == IB_PORT_PHYS_STATE_DISABLED) {
798c187222hselasky			__tag_port_report(&(fs->disabled_ports),
799c187222hselasky					  cl_ntoh64(node->node_info.node_guid),
800c187222hselasky					  port, node->print_desc);
801c187222hselasky			fs->ports_disabled++;
802c187222hselasky		}
803c187222hselasky
804c187222hselasky		fs->total_ports++;
805c187222hselasky
806c187222hselasky		if (port_state == IB_LINK_DOWN)
807c187222hselasky			continue;
808c187222hselasky
809c187222hselasky		if (!(active_width & enabled_width)) {
810c187222hselasky			__tag_port_report(&(fs->unenabled_width_ports),
811c187222hselasky					  cl_ntoh64(node->node_info.node_guid),
812c187222hselasky					  port, node->print_desc);
813c187222hselasky			fs->ports_unenabled_width++;
814c187222hselasky		}
815c187222hselasky		else if ((enabled_width ^ active_width) > active_width) {
8165115240jeff			__tag_port_report(&(fs->reduced_width_ports),
8175115240jeff					  cl_ntoh64(node->node_info.node_guid),
8185115240jeff					  port, node->print_desc);
8195115240jeff			fs->ports_reduced_width++;
8205115240jeff		}
8215115240jeff
822c187222hselasky		/* unenabled speed usually due to problems with force_link_speed */
823c187222hselasky		if (!(active_speed & enabled_speed)) {
824c187222hselasky			__tag_port_report(&(fs->unenabled_speed_ports),
825c187222hselasky					  cl_ntoh64(node->node_info.node_guid),
826c187222hselasky					  port, node->print_desc);
827c187222hselasky			fs->ports_unenabled_speed++;
828c187222hselasky		}
829c187222hselasky		else if ((enabled_speed ^ active_speed) > active_speed) {
8305115240jeff			__tag_port_report(&(fs->reduced_speed_ports),
8315115240jeff					  cl_ntoh64(node->node_info.node_guid),
8325115240jeff					  port, node->print_desc);
8335115240jeff			fs->ports_reduced_speed++;
8345115240jeff		}
8355115240jeff
8365115240jeff		switch (active_speed) {
8375115240jeff		case IB_LINK_SPEED_ACTIVE_2_5:
8385115240jeff			fs->ports_sdr++;
8395115240jeff			break;
8405115240jeff		case IB_LINK_SPEED_ACTIVE_5:
8415115240jeff			fs->ports_ddr++;
8425115240jeff			break;
8435115240jeff		case IB_LINK_SPEED_ACTIVE_10:
844c187222hselasky			if (!(pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS) ||
845c187222hselasky			    !ib_port_info_get_link_speed_ext_active(pi)) {
846c187222hselasky				if (epi->link_speed_active & FDR10)
847c187222hselasky					fs->ports_fdr10++;
848c187222hselasky				else {
849c187222hselasky					fs->ports_qdr++;
850c187222hselasky					/* check for speed reduced from FDR10 */
851c187222hselasky					if (epi->link_speed_enabled & FDR10) {
852c187222hselasky						__tag_port_report(&(fs->reduced_speed_ports),
853c187222hselasky								  cl_ntoh64(node->node_info.node_guid),
854c187222hselasky								  port, node->print_desc);
855c187222hselasky						fs->ports_reduced_speed++;
856c187222hselasky					}
857c187222hselasky				}
858c187222hselasky			}
859c187222hselasky			break;
860c187222hselasky		case IB_LINK_SPEED_ACTIVE_EXTENDED:
8615115240jeff			break;
8625115240jeff		default:
863c187222hselasky			__tag_port_report(&(fs->unknown_speed_ports),
864c187222hselasky					  cl_ntoh64(node->node_info.node_guid),
865c187222hselasky					  port, node->print_desc);
8665115240jeff			fs->ports_unknown_speed++;
8675115240jeff			break;
8685115240jeff		}
869c187222hselasky		if (pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS &&
870c187222hselasky		    ib_port_info_get_link_speed_ext_sup(pi) &&
871c187222hselasky		    (enabled_speed = ib_port_info_get_link_speed_ext_enabled(pi)) != IB_LINK_SPEED_EXT_DISABLE &&
872c187222hselasky		    active_speed == IB_LINK_SPEED_ACTIVE_10) {
873c187222hselasky			active_speed = ib_port_info_get_link_speed_ext_active(pi);
874c187222hselasky			if (!(active_speed & enabled_speed)) {
875c187222hselasky				__tag_port_report(&(fs->unenabled_speed_ports),
876c187222hselasky						  cl_ntoh64(node->node_info.node_guid),
877c187222hselasky						  port, node->print_desc);
878c187222hselasky				fs->ports_unenabled_speed++;
879c187222hselasky			}
880c187222hselasky			else if ((enabled_speed ^ active_speed) > active_speed) {
881c187222hselasky				__tag_port_report(&(fs->reduced_speed_ports),
882c187222hselasky						  cl_ntoh64(node->node_info.node_guid),
883c187222hselasky						  port, node->print_desc);
884c187222hselasky				fs->ports_reduced_speed++;
885c187222hselasky			}
886c187222hselasky			switch (active_speed) {
887c187222hselasky			case IB_LINK_SPEED_EXT_ACTIVE_14:
888c187222hselasky				fs->ports_fdr++;
889c187222hselasky				break;
890c187222hselasky			case IB_LINK_SPEED_EXT_ACTIVE_25:
891c187222hselasky				fs->ports_edr++;
892c187222hselasky				break;
893c187222hselasky			case IB_LINK_SPEED_EXT_ACTIVE_NONE:
894c187222hselasky				break;
895c187222hselasky			default:
896c187222hselasky				__tag_port_report(&(fs->unknown_speed_ports),
897c187222hselasky						  cl_ntoh64(node->node_info.node_guid),
898c187222hselasky						  port, node->print_desc);
899c187222hselasky				fs->ports_unknown_speed++;
900c187222hselasky				break;
901c187222hselasky			}
902c187222hselasky		}
9035115240jeff		switch (active_width) {
9045115240jeff		case IB_LINK_WIDTH_ACTIVE_1X:
9055115240jeff			fs->ports_1X++;
9065115240jeff			break;
9075115240jeff		case IB_LINK_WIDTH_ACTIVE_4X:
9085115240jeff			fs->ports_4X++;
9095115240jeff			break;
9105115240jeff		case IB_LINK_WIDTH_ACTIVE_8X:
9115115240jeff			fs->ports_8X++;
9125115240jeff			break;
9135115240jeff		case IB_LINK_WIDTH_ACTIVE_12X:
9145115240jeff			fs->ports_12X++;
9155115240jeff			break;
916c187222hselasky		case IB_LINK_WIDTH_ACTIVE_2X:
917c187222hselasky			fs->ports_2X++;
9185115240jeff			break;
919c187222hselasky		default:
920c187222hselasky			__tag_port_report(&(fs->unknown_width_ports),
9215115240jeff					  cl_ntoh64(node->node_info.node_guid),
9225115240jeff					  port, node->print_desc);
923c187222hselasky			fs->ports_unknown_width++;
924c187222hselasky			break;
9255115240jeff		}
9265115240jeff	}
9275115240jeff}
9285115240jeff
9295115240jeffstatic void portstatus_parse(char **p_last, osm_opensm_t * p_osm, FILE * out)
9305115240jeff{
9315115240jeff	fabric_stats_t fs;
9325115240jeff	struct timeval before, after;
9335115240jeff	char *p_cmd;
9345115240jeff
9355115240jeff	memset(&fs, 0, sizeof(fs));
9365115240jeff
9375115240jeff	p_cmd = next_token(p_last);
9385115240jeff	if (p_cmd) {
9395115240jeff		if (strcmp(p_cmd, "ca") == 0) {
9405115240jeff			fs.node_type_lim = IB_NODE_TYPE_CA;
9415115240jeff		} else if (strcmp(p_cmd, "switch") == 0) {
9425115240jeff			fs.node_type_lim = IB_NODE_TYPE_SWITCH;
9435115240jeff		} else if (strcmp(p_cmd, "router") == 0) {
9445115240jeff			fs.node_type_lim = IB_NODE_TYPE_ROUTER;
9455115240jeff		} else {
9465115240jeff			fprintf(out, "Node type not understood\n");
9475115240jeff			help_portstatus(out, 1);
9485115240jeff			return;
9495115240jeff		}
9505115240jeff	}
9515115240jeff
9525115240jeff	gettimeofday(&before, NULL);
9535115240jeff
9545115240jeff	/* for each node in the system gather the stats */
9555115240jeff	cl_plock_acquire(&p_osm->lock);
9565115240jeff	cl_qmap_apply_func(&(p_osm->subn.node_guid_tbl), __get_stats,
9575115240jeff			   (void *)&fs);
9585115240jeff	cl_plock_release(&p_osm->lock);
9595115240jeff
9605115240jeff	gettimeofday(&after, NULL);
9615115240jeff
9625115240jeff	/* report the stats */
9635115240jeff	fprintf(out, "\"%s\" port status:\n",
9645115240jeff		fs.node_type_lim ? ib_get_node_type_str(fs.
9655115240jeff							node_type_lim) : "ALL");
9665115240jeff	fprintf(out,
9675115240jeff		"   %" PRIu64 " port(s) scanned on %" PRIu64
9685115240jeff		" nodes in %lu us\n", fs.total_ports, fs.total_nodes,
9695115240jeff		after.tv_usec - before.tv_usec);
9705115240jeff
9715115240jeff	if (fs.ports_down)
9725115240jeff		fprintf(out, "   %" PRIu64 " down\n", fs.ports_down);
9735115240jeff	if (fs.ports_active)
9745115240jeff		fprintf(out, "   %" PRIu64 " active\n", fs.ports_active);
9755115240jeff	if (fs.ports_1X)
9765115240jeff		fprintf(out, "   %" PRIu64 " at 1X\n", fs.ports_1X);
9775115240jeff	if (fs.ports_4X)
9785115240jeff		fprintf(out, "   %" PRIu64 " at 4X\n", fs.ports_4X);
9795115240jeff	if (fs.ports_8X)
9805115240jeff		fprintf(out, "   %" PRIu64 " at 8X\n", fs.ports_8X);
9815115240jeff	if (fs.ports_12X)
9825115240jeff		fprintf(out, "   %" PRIu64 " at 12X\n", fs.ports_12X);
9835115240jeff
9845115240jeff	if (fs.ports_sdr)
9855115240jeff		fprintf(out, "   %" PRIu64 " at 2.5 Gbps\n", fs.ports_sdr);
9865115240jeff	if (fs.ports_ddr)
9875115240jeff		fprintf(out, "   %" PRIu64 " at 5.0 Gbps\n", fs.ports_ddr);
9885115240jeff	if (fs.ports_qdr)
9895115240jeff		fprintf(out, "   %" PRIu64 " at 10.0 Gbps\n", fs.ports_qdr);
990c187222hselasky	if (fs.ports_fdr10)
991c187222hselasky		fprintf(out, "   %" PRIu64 " at 10.0 Gbps (FDR10)\n", fs.ports_fdr10);
992c187222hselasky	if (fs.ports_fdr)
993c187222hselasky		fprintf(out, "   %" PRIu64 " at 14.0625 Gbps\n", fs.ports_fdr);
994c187222hselasky	if (fs.ports_edr)
995c187222hselasky		fprintf(out, "   %" PRIu64 " at 25.78125 Gbps\n", fs.ports_edr);
9965115240jeff
9975115240jeff	if (fs.ports_disabled + fs.ports_reduced_speed + fs.ports_reduced_width
998