1219820Sjeff#!/usr/bin/perl
2219820Sjeff#
3219820Sjeff# Copyright (c) 2006 The Regents of the University of California.
4219820Sjeff# Copyright (c) 2007-2008 Voltaire, Inc. All rights reserved.
5219820Sjeff#
6219820Sjeff# Produced at Lawrence Livermore National Laboratory.
7219820Sjeff# Written by Ira Weiny <weiny2@llnl.gov>.
8219820Sjeff#
9219820Sjeff# This software is available to you under a choice of one of two
10219820Sjeff# licenses.  You may choose to be licensed under the terms of the GNU
11219820Sjeff# General Public License (GPL) Version 2, available from the file
12219820Sjeff# COPYING in the main directory of this source tree, or the
13219820Sjeff# OpenIB.org BSD license below:
14219820Sjeff#
15219820Sjeff#     Redistribution and use in source and binary forms, with or
16219820Sjeff#     without modification, are permitted provided that the following
17219820Sjeff#     conditions are met:
18219820Sjeff#
19219820Sjeff#      - Redistributions of source code must retain the above
20219820Sjeff#        copyright notice, this list of conditions and the following
21219820Sjeff#        disclaimer.
22219820Sjeff#
23219820Sjeff#      - Redistributions in binary form must reproduce the above
24219820Sjeff#        copyright notice, this list of conditions and the following
25219820Sjeff#        disclaimer in the documentation and/or other materials
26219820Sjeff#        provided with the distribution.
27219820Sjeff#
28219820Sjeff# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29219820Sjeff# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30219820Sjeff# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31219820Sjeff# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
32219820Sjeff# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
33219820Sjeff# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34219820Sjeff# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35219820Sjeff# SOFTWARE.
36219820Sjeff#
37219820Sjeff
38219820Sjeffuse strict;
39219820Sjeff
40219820Sjeffuse Getopt::Std;
41219820Sjeffuse IBswcountlimits;
42219820Sjeff
43219820Sjeffsub usage_and_exit
44219820Sjeff{
45219820Sjeff	my $prog = $_[0];
46219820Sjeff	print
47219820Sjeff"Usage: $prog [-Rhclp -S <guid> -D <direct route> -C <ca_name> -P <ca_port>]\n";
48219820Sjeff	print
49219820Sjeff"   Report link speed and connection for each port of each switch which is active\n";
50219820Sjeff	print "   -h This help message\n";
51219820Sjeff	print
52219820Sjeff"   -R Recalculate ibnetdiscover information (Default is to reuse ibnetdiscover output)\n";
53219820Sjeff	print
54219820Sjeff"   -D <direct route> output only the switch specified by direct route path\n";
55219820Sjeff	print "   -S <guid> output only the switch specified by <guid> (hex format)\n";
56219820Sjeff	print "   -d print only down links\n";
57219820Sjeff	print
58219820Sjeff	  "   -l (line mode) print all information for each link on each line\n";
59219820Sjeff	print
60219820Sjeff"   -p print additional switch settings (PktLifeTime,HoqLife,VLStallCount)\n";
61219820Sjeff	print "   -c print port capabilities (enabled/supported values)\n";
62219820Sjeff	print "   -C <ca_name> use selected Channel Adaptor name for queries\n";
63219820Sjeff	print "   -P <ca_port> use selected channel adaptor port for queries\n";
64219820Sjeff	print "   -g print port guids instead of node guids\n";
65219820Sjeff	exit 2;
66219820Sjeff}
67219820Sjeff
68219820Sjeffmy $argv0              = `basename $0`;
69219820Sjeffmy $regenerate_map     = undef;
70219820Sjeffmy $single_switch      = undef;
71219820Sjeffmy $direct_route       = undef;
72219820Sjeffmy $line_mode          = undef;
73219820Sjeffmy $print_add_switch   = undef;
74219820Sjeffmy $print_extended_cap = undef;
75219820Sjeffmy $only_down_links    = undef;
76219820Sjeffmy $ca_name            = "";
77219820Sjeffmy $ca_port            = "";
78219820Sjeffmy $print_port_guids   = undef;
79219820Sjeffmy $switch_found       = "no";
80219820Sjeffchomp $argv0;
81219820Sjeff
82219820Sjeffif (!getopts("hcpldRS:D:C:P:g")) { usage_and_exit $argv0; }
83219820Sjeffif (defined $Getopt::Std::opt_h) { usage_and_exit $argv0; }
84219820Sjeffif (defined $Getopt::Std::opt_D) { $direct_route   = $Getopt::Std::opt_D; }
85219820Sjeffif (defined $Getopt::Std::opt_R) { $regenerate_map = $Getopt::Std::opt_R; }
86219820Sjeffif (defined $Getopt::Std::opt_S) {
87219820Sjeff	$single_switch = format_guid($Getopt::Std::opt_S);
88219820Sjeff}
89219820Sjeffif (defined $Getopt::Std::opt_d) { $only_down_links    = $Getopt::Std::opt_d; }
90219820Sjeffif (defined $Getopt::Std::opt_l) { $line_mode          = $Getopt::Std::opt_l; }
91219820Sjeffif (defined $Getopt::Std::opt_p) { $print_add_switch   = $Getopt::Std::opt_p; }
92219820Sjeffif (defined $Getopt::Std::opt_c) { $print_extended_cap = $Getopt::Std::opt_c; }
93219820Sjeffif (defined $Getopt::Std::opt_C) { $ca_name            = $Getopt::Std::opt_C; }
94219820Sjeffif (defined $Getopt::Std::opt_P) { $ca_port            = $Getopt::Std::opt_P; }
95219820Sjeffif (defined $Getopt::Std::opt_g) { $print_port_guids   = $Getopt::Std::opt_g; }
96219820Sjeff
97219820Sjeffmy $extra_smpquery_params = get_ca_name_port_param_string($ca_name, $ca_port);
98219820Sjeff
99219820Sjeffsub main
100219820Sjeff{
101219820Sjeff	get_link_ends($regenerate_map, $ca_name, $ca_port);
102219820Sjeff	if (defined($direct_route)) {
103219820Sjeff		# convert DR to guid, then use original single_switch option
104219820Sjeff		$single_switch = convert_dr_to_guid($direct_route);
105219820Sjeff		if (!defined($single_switch) || !is_switch($single_switch)) {
106219820Sjeff			printf("The direct route (%s) does not map to a switch.\n",
107219820Sjeff				$direct_route);
108219820Sjeff			return;
109219820Sjeff		}
110219820Sjeff	}
111219820Sjeff	foreach my $switch (sort (keys(%IBswcountlimits::link_ends))) {
112219820Sjeff		if ($single_switch && $switch ne $single_switch) {
113219820Sjeff			next;
114219820Sjeff		} else {
115219820Sjeff			$switch_found = "yes";
116219820Sjeff		}
117219820Sjeff		my $switch_prompt = "no";
118219820Sjeff		my $num_ports = get_num_ports($switch, $ca_name, $ca_port);
119219820Sjeff		if ($num_ports == 0) {
120219820Sjeff			printf("ERROR: switch $switch has 0 ports???\n");
121219820Sjeff		}
122219820Sjeff		my @output_lines    = undef;
123219820Sjeff		my $pkt_lifetime    = "";
124219820Sjeff		my $pkt_life_prompt = "";
125219820Sjeff		my $port_timeouts   = "";
126219820Sjeff		my $print_switch    = "yes";
127219820Sjeff		if ($only_down_links) { $print_switch = "no"; }
128219820Sjeff		if ($print_add_switch) {
129219820Sjeff			my $data = `smpquery $extra_smpquery_params -G switchinfo $switch`;
130219820Sjeff			if ($data eq "") {
131219820Sjeff				printf("ERROR: failed to get switchinfo for $switch\n");
132219820Sjeff			}
133219820Sjeff			my @lines = split("\n", $data);
134219820Sjeff			foreach my $line (@lines) {
135219820Sjeff				if ($line =~ /^LifeTime:\.+(.*)/) { $pkt_lifetime = $1; }
136219820Sjeff			}
137219820Sjeff			$pkt_life_prompt = sprintf(" (LT: %2s)", $pkt_lifetime);
138219820Sjeff		}
139219820Sjeff		foreach my $port (1 .. $num_ports) {
140219820Sjeff			my $hr = $IBswcountlimits::link_ends{$switch}{$port};
141219820Sjeff			if ($switch_prompt eq "no" && !$line_mode) {
142219820Sjeff				my $switch_name = "";
143219820Sjeff				my $tmp_port = $port;
144219820Sjeff				while ($switch_name eq "" && $tmp_port <= $num_ports) {
145219820Sjeff					# the first port is down find switch name with up port
146219820Sjeff					my $hr = $IBswcountlimits::link_ends{$switch}{$tmp_port};
147219820Sjeff					$switch_name = $hr->{loc_desc};
148219820Sjeff					$tmp_port++;
149219820Sjeff				}
150219820Sjeff				if ($switch_name eq "") {
151219820Sjeff					printf(
152219820Sjeff						"WARNING: Switch Name not found for $switch\n");
153219820Sjeff				}
154219820Sjeff				push(
155219820Sjeff					@output_lines,
156219820Sjeff					sprintf(
157219820Sjeff						"Switch %18s %s%s:\n",
158219820Sjeff						$switch, $switch_name, $pkt_life_prompt
159219820Sjeff					)
160219820Sjeff				);
161219820Sjeff				$switch_prompt = "yes";
162219820Sjeff			}
163219820Sjeff			my $data =
164219820Sjeff			  `smpquery $extra_smpquery_params -G portinfo $switch $port`;
165219820Sjeff			if ($data eq "") {
166219820Sjeff				printf(
167219820Sjeff					"ERROR: failed to get portinfo for $switch port $port\n");
168219820Sjeff			}
169219820Sjeff			my @lines          = split("\n", $data);
170219820Sjeff			my $speed          = "";
171219820Sjeff			my $speed_sup      = "";
172219820Sjeff			my $speed_enable   = "";
173219820Sjeff			my $width          = "";
174219820Sjeff			my $width_sup      = "";
175219820Sjeff			my $width_enable   = "";
176219820Sjeff			my $state          = "";
177219820Sjeff			my $hoq_life       = "";
178219820Sjeff			my $vl_stall       = "";
179219820Sjeff			my $phy_link_state = "";
180219820Sjeff
181219820Sjeff			foreach my $line (@lines) {
182219820Sjeff				if ($line =~ /^LinkSpeedActive:\.+(.*)/) { $speed = $1; }
183219820Sjeff				if ($line =~ /^LinkSpeedEnabled:\.+(.*)/) {
184219820Sjeff					$speed_enable = $1;
185219820Sjeff				}
186219820Sjeff				if ($line =~ /^LinkSpeedSupported:\.+(.*)/) { $speed_sup = $1; }
187219820Sjeff				if ($line =~ /^LinkWidthActive:\.+(.*)/)    { $width     = $1; }
188219820Sjeff				if ($line =~ /^LinkWidthEnabled:\.+(.*)/) {
189219820Sjeff					$width_enable = $1;
190219820Sjeff				}
191219820Sjeff				if ($line =~ /^LinkWidthSupported:\.+(.*)/) { $width_sup = $1; }
192219820Sjeff				if ($line =~ /^LinkState:\.+(.*)/)          { $state     = $1; }
193219820Sjeff				if ($line =~ /^HoqLife:\.+(.*)/)            { $hoq_life  = $1; }
194219820Sjeff				if ($line =~ /^VLStallCount:\.+(.*)/)       { $vl_stall  = $1; }
195219820Sjeff				if ($line =~ /^PhysLinkState:\.+(.*)/) { $phy_link_state = $1; }
196219820Sjeff			}
197219820Sjeff			my $rem_port         = $hr->{rem_port};
198219820Sjeff			my $rem_lid          = $hr->{rem_lid};
199219820Sjeff			my $rem_speed_sup    = "";
200219820Sjeff			my $rem_speed_enable = "";
201219820Sjeff			my $rem_width_sup    = "";
202219820Sjeff			my $rem_width_enable = "";
203219820Sjeff			if ($rem_lid ne "" && $rem_port ne "") {
204219820Sjeff				$data =
205219820Sjeff				  `smpquery $extra_smpquery_params portinfo $rem_lid $rem_port`;
206219820Sjeff				if ($data eq "") {
207219820Sjeff					printf(
208219820Sjeff						"ERROR: failed to get portinfo for $switch port $port\n"
209219820Sjeff					);
210219820Sjeff				}
211219820Sjeff				my @lines = split("\n", $data);
212219820Sjeff				foreach my $line (@lines) {
213219820Sjeff					if ($line =~ /^LinkSpeedEnabled:\.+(.*)/) {
214219820Sjeff						$rem_speed_enable = $1;
215219820Sjeff					}
216219820Sjeff					if ($line =~ /^LinkSpeedSupported:\.+(.*)/) {
217219820Sjeff						$rem_speed_sup = $1;
218219820Sjeff					}
219219820Sjeff					if ($line =~ /^LinkWidthEnabled:\.+(.*)/) {
220219820Sjeff						$rem_width_enable = $1;
221219820Sjeff					}
222219820Sjeff					if ($line =~ /^LinkWidthSupported:\.+(.*)/) {
223219820Sjeff						$rem_width_sup = $1;
224219820Sjeff					}
225219820Sjeff				}
226219820Sjeff			}
227219820Sjeff			my $capabilities = "";
228219820Sjeff			if ($print_extended_cap) {
229219820Sjeff				$capabilities = sprintf("(%3s %s %6s / %8s [%s/%s][%s/%s])",
230219820Sjeff					$width, $speed, $state, $phy_link_state, $width_enable,
231219820Sjeff					$width_sup, $speed_enable, $speed_sup);
232219820Sjeff			} else {
233219820Sjeff				$capabilities = sprintf("(%3s %s %6s / %8s)",
234219820Sjeff					$width, $speed, $state, $phy_link_state);
235219820Sjeff			}
236219820Sjeff			if ($print_add_switch) {
237219820Sjeff				$port_timeouts =
238219820Sjeff				  sprintf(" (HOQ:%s VL_Stall:%s)", $hoq_life, $vl_stall);
239219820Sjeff			}
240219820Sjeff			if (!$only_down_links || ($only_down_links && $state eq "Down")) {
241219820Sjeff				my $width_msg = "";
242219820Sjeff				my $speed_msg = "";
243219820Sjeff				if ($rem_width_enable ne "" && $rem_width_sup ne "") {
244219820Sjeff					if (   $width_enable =~ /12X/
245219820Sjeff						&& $rem_width_enable =~ /12X/
246219820Sjeff						&& $width !~ /12X/)
247219820Sjeff					{
248219820Sjeff						$width_msg = "Could be 12X";
249219820Sjeff					} else {
250219820Sjeff						if (   $width_enable =~ /8X/
251219820Sjeff							&& $rem_width_enable =~ /8X/
252219820Sjeff							&& $width !~ /8X/)
253219820Sjeff						{
254219820Sjeff							$width_msg = "Could be 8X";
255219820Sjeff						} else {
256219820Sjeff							if (   $width_enable =~ /4X/
257219820Sjeff								&& $rem_width_enable =~ /4X/
258219820Sjeff								&& $width !~ /4X/)
259219820Sjeff							{
260219820Sjeff								$width_msg = "Could be 4X";
261219820Sjeff							}
262219820Sjeff						}
263219820Sjeff					}
264219820Sjeff				}
265219820Sjeff				if ($rem_speed_enable ne "" && $rem_speed_sup ne "") {
266219820Sjeff					if (   $speed_enable =~ /10\.0/
267219820Sjeff						&& $rem_speed_enable =~ /10\.0/
268219820Sjeff						&& $speed !~ /10\.0/)
269219820Sjeff					{
270219820Sjeff						$speed_msg = "Could be 10.0 Gbps";
271219820Sjeff					} else {
272219820Sjeff						if (   $speed_enable =~ /5\.0/
273219820Sjeff							&& $rem_speed_enable =~ /5\.0/
274219820Sjeff							&& $speed !~ /5\.0/)
275219820Sjeff						{
276219820Sjeff							$speed_msg = "Could be 5.0 Gbps";
277219820Sjeff						}
278219820Sjeff					}
279219820Sjeff				}
280219820Sjeff
281219820Sjeff				if ($line_mode) {
282219820Sjeff					my $line_begin = sprintf("%18s \"%30s\"%s",
283219820Sjeff						$switch, $hr->{loc_desc}, $pkt_life_prompt);
284219820Sjeff					my $ext_guid = sprintf("%18s", $hr->{rem_guid});
285219820Sjeff					if ($print_port_guids && $hr->{rem_port_guid} ne "") {
286219820Sjeff						$ext_guid = sprintf("0x%016s", $hr->{rem_port_guid});
287219820Sjeff					}
288219820Sjeff					push(
289219820Sjeff						@output_lines,
290219820Sjeff						sprintf(
291219820Sjeff"%s %6s %4s[%2s]  ==%s%s==>  %18s %6s %4s[%2s] \"%s\" ( %s %s)\n",
292219820Sjeff							$line_begin,     $hr->{loc_sw_lid},
293219820Sjeff							$port,           $hr->{loc_ext_port},
294219820Sjeff							$capabilities,   $port_timeouts,
295219820Sjeff							$ext_guid,       $hr->{rem_lid},
296219820Sjeff							$hr->{rem_port}, $hr->{rem_ext_port},
297219820Sjeff							$hr->{rem_desc}, $width_msg,
298219820Sjeff							$speed_msg
299219820Sjeff						)
300219820Sjeff					);
301219820Sjeff				} else {
302219820Sjeff					push(
303219820Sjeff						@output_lines,
304219820Sjeff						sprintf(
305219820Sjeff" %6s %4s[%2s]  ==%s%s==>  %6s %4s[%2s] \"%s\" ( %s %s)\n",
306219820Sjeff							$hr->{loc_sw_lid},   $port,
307219820Sjeff							$hr->{loc_ext_port}, $capabilities,
308219820Sjeff							$port_timeouts,      $hr->{rem_lid},
309219820Sjeff							$hr->{rem_port},     $hr->{rem_ext_port},
310219820Sjeff							$hr->{rem_desc},     $width_msg,
311219820Sjeff							$speed_msg
312219820Sjeff						)
313219820Sjeff					);
314219820Sjeff				}
315219820Sjeff				$print_switch = "yes";
316219820Sjeff			}
317219820Sjeff		}
318219820Sjeff		if ($print_switch eq "yes") {
319219820Sjeff			foreach my $line (@output_lines) { print $line; }
320219820Sjeff		}
321219820Sjeff	}
322219820Sjeff	if ($single_switch && $switch_found ne "yes") {
323219820Sjeff		printf("Switch \"%s\" not found.\n", $single_switch);
324219820Sjeff	}
325219820Sjeff}
326219820Sjeffmain;
327219820Sjeff
328