1321936Shselasky/*
2321936Shselasky * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
3321936Shselasky *
4321936Shselasky * This software is available to you under a choice of one of two
5321936Shselasky * licenses.  You may choose to be licensed under the terms of the GNU
6321936Shselasky * General Public License (GPL) Version 2, available from the file
7321936Shselasky * COPYING in the main directory of this source tree, or the
8321936Shselasky * OpenIB.org BSD license below:
9321936Shselasky *
10321936Shselasky *     Redistribution and use in source and binary forms, with or
11321936Shselasky *     without modification, are permitted provided that the following
12321936Shselasky *     conditions are met:
13321936Shselasky *
14321936Shselasky *      - Redistributions of source code must retain the above
15321936Shselasky *        copyright notice, this list of conditions and the following
16321936Shselasky *        disclaimer.
17321936Shselasky *
18321936Shselasky *      - Redistributions in binary form must reproduce the above
19321936Shselasky *        copyright notice, this list of conditions and the following
20321936Shselasky *        disclaimer in the documentation and/or other materials
21321936Shselasky *        provided with the distribution.
22321936Shselasky *
23321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30321936Shselasky * SOFTWARE.
31321936Shselasky *
32321936Shselasky */
33321936Shselasky
34321936Shselasky#if HAVE_CONFIG_H
35321936Shselasky#  include <config.h>
36321936Shselasky#endif				/* HAVE_CONFIG_H */
37321936Shselasky
38321936Shselasky#include <stdio.h>
39321936Shselasky#include <stdlib.h>
40321936Shselasky#include <unistd.h>
41321936Shselasky#include <getopt.h>
42321936Shselasky#include <netinet/in.h>
43321936Shselasky
44321936Shselasky#include <infiniband/umad.h>
45321936Shselasky#include <infiniband/mad.h>
46321936Shselasky
47321936Shselasky#include "ibdiag_common.h"
48321936Shselasky
49321936Shselasky#define IB_MLX_VENDOR_CLASS		10
50321936Shselasky
51321936Shselasky/* Vendor specific Attribute IDs */
52321936Shselasky#define IB_MLX_IS3_GENERAL_INFO		0x17
53321936Shselasky
54321936Shselasky#define MAX_SWITCH_PORTS         (36+1)
55321936Shselaskystatic char mtx_ports[MAX_SWITCH_PORTS] = {0};
56321936Shselaskystatic char mrx_ports[MAX_SWITCH_PORTS] = {0};
57321936Shselaskystatic char str[4096];
58321936Shselaskystatic uint8_t buf[256];
59321936Shselasky
60321936Shselasky#define ATTRID_PM_ROUTE   0xff30
61321936Shselasky#define ATTRID_PM_FILTER  0xff31
62321936Shselasky#define ATTRID_PM_PORTS   0xff32
63321936Shselasky#define ATTRID_LOSSY_CFG  0xff80
64321936Shselasky
65321936Shselaskyenum mirror_type {
66321936Shselasky	MT_DISABLED        = 0,
67321936Shselasky	MT_MIRROR_NATIVE   = 2,
68321936Shselasky	MT_DROP            = 5,
69321936Shselasky	MT_MIRROR_ENCAP    = 6,
70321936Shselasky	MT_MIRROR_DROP     = 7
71321936Shselasky};
72321936Shselasky
73321936Shselaskyenum mirror_port {
74321936Shselasky	MP_DISABLED          = 0,
75321936Shselasky	MP_MIRROR_FILTER     = 1,
76321936Shselasky	MP_MIRROR_ALWAYS     = 2,
77321936Shselasky	MP_MIRROR_FILTER_NOT = 3,
78321936Shselasky	MT_MIRROR_AS_RX      = 1
79321936Shselasky};
80321936Shselasky
81321936Shselasky#define PM_ENCAP_ETHERTYPE 0x1123
82321936Shselasky
83321936Shselaskystruct ibmad_port *srcport;
84321936Shselasky
85321936Shselaskytypedef struct {
86321936Shselasky	uint16_t hw_revision;
87321936Shselasky	uint16_t device_id;
88321936Shselasky	uint8_t reserved[24];
89321936Shselasky	uint32_t uptime;
90321936Shselasky} is3_hw_info_t;
91321936Shselasky
92321936Shselaskytypedef struct {
93321936Shselasky	uint8_t resv1;
94321936Shselasky	uint8_t major;
95321936Shselasky	uint8_t minor;
96321936Shselasky	uint8_t sub_minor;
97321936Shselasky	uint32_t build_id;
98321936Shselasky	uint8_t month;
99321936Shselasky	uint8_t day;
100321936Shselasky	uint16_t year;
101321936Shselasky	uint16_t resv2;
102321936Shselasky	uint16_t hour;
103321936Shselasky	uint8_t psid[16];
104321936Shselasky	uint32_t ini_file_version;
105321936Shselasky} is3_fw_info_t;
106321936Shselasky
107321936Shselaskytypedef struct {
108321936Shselasky	uint8_t resv1;
109321936Shselasky	uint8_t major;
110321936Shselasky	uint8_t minor;
111321936Shselasky	uint8_t sub_minor;
112321936Shselasky	uint8_t resv2[28];
113321936Shselasky} is3_sw_info_t;
114321936Shselasky
115321936Shselaskytypedef struct {
116321936Shselasky	uint8_t reserved[8];
117321936Shselasky	is3_hw_info_t hw_info;
118321936Shselasky	is3_fw_info_t fw_info;
119321936Shselasky	is3_sw_info_t sw_info;
120321936Shselasky} is3_general_info_t;
121321936Shselasky
122321936Shselaskytypedef struct {
123321936Shselasky	uint16_t ignore_buffer_mask;
124321936Shselasky	uint16_t ignore_credit_mask;
125321936Shselasky} lossy_config_t;
126321936Shselasky
127321936Shselaskystatic int mirror_query, mirror_dport, mirror_dlid, mirror_clear, mirror_sl, lossy_set;
128321936Shselaskystatic int set_mtx, set_mrx, packet_size = 0xfff;
129321936Shselasky
130321936Shselaskystatic int parse_ports(char *ports_str, char *ports_array)
131321936Shselasky{
132321936Shselasky	int num, i;
133321936Shselasky	char *str = strdup(ports_str);
134321936Shselasky	char *token = strtok(str, ",");
135321936Shselasky	for (i = 0; i < MAX_SWITCH_PORTS && token; i++) {
136321936Shselasky		num = strtoul(token, NULL, 0);
137321936Shselasky		if (num > 0 && num < MAX_SWITCH_PORTS)
138321936Shselasky			ports_array[num] = 1;
139321936Shselasky
140321936Shselasky		token = strtok(NULL, ",");
141321936Shselasky	}
142321936Shselasky	free(str);
143321936Shselasky	return 0;
144321936Shselasky}
145321936Shselasky
146321936Shselaskyvoid port_mirror_route(ib_portid_t * portid, int query, int clear)
147321936Shselasky{
148321936Shselasky	int mirror_type;
149321936Shselasky
150321936Shselasky	memset(&buf, 0, sizeof(buf));
151321936Shselasky
152321936Shselasky	if (clear) {
153321936Shselasky		if (!smp_set_via(buf, portid, ATTRID_PM_ROUTE, 0, 0, srcport))
154321936Shselasky			IBEXIT("Clear port mirror route set failed");
155321936Shselasky		return;
156321936Shselasky	}
157321936Shselasky
158321936Shselasky	if (query) {
159321936Shselasky		if (!smp_query_via(buf, portid, ATTRID_PM_ROUTE, 0, 0, srcport))
160321936Shselasky			IBEXIT("Read port mirror route get failed");
161321936Shselasky		mad_decode_field(buf, IB_PMR_MT_F, &mirror_type);
162321936Shselasky		if (mirror_type == MT_MIRROR_ENCAP && mirror_dlid == 0)
163321936Shselasky			mad_decode_field(buf, IB_PMR_LRH_DLID_F, &mirror_dlid);
164321936Shselasky		if (mirror_type == MT_MIRROR_NATIVE && mirror_dport == 0)
165321936Shselasky			mad_decode_field(buf, IB_PMR_NM_PORT_F, &mirror_dport);
166321936Shselasky		goto Exit;
167321936Shselasky	}
168321936Shselasky
169321936Shselasky	/* Port Mirror Route */
170321936Shselasky	mad_set_field(buf, 0, IB_PMR_ENCAP_RAW_ETH_TYPE_F, PM_ENCAP_ETHERTYPE);
171321936Shselasky
172321936Shselasky	if (mirror_dlid == 0) {
173321936Shselasky		/* Can not truncate mirrored packets in local mode */
174321936Shselasky		mad_set_field(buf, 0, IB_PMR_MAX_MIRROR_LEN_F, 0xfff);
175321936Shselasky		mad_set_field(buf, 0, IB_PMR_MT_F, MT_MIRROR_NATIVE);
176321936Shselasky		mad_set_field(buf, 0, IB_PMR_NM_PORT_F, mirror_dport);
177321936Shselasky	}
178321936Shselasky	else { /* remote mirror */
179321936Shselasky		/* convert size to dwords */
180321936Shselasky		packet_size = packet_size / 4 + 1;
181321936Shselasky		mad_set_field(buf, 0, IB_PMR_MAX_MIRROR_LEN_F, packet_size);
182321936Shselasky		mad_set_field(buf, 0, IB_PMR_MT_F, MT_MIRROR_ENCAP);
183321936Shselasky		mad_set_field(buf, 0, IB_PMR_LRH_SL_F, mirror_sl);
184321936Shselasky		mad_set_field(buf, 0, IB_PMR_LRH_DLID_F, mirror_dlid);
185321936Shselasky		mad_set_field(buf, 0, IB_PMR_LRH_SLID_F, portid->lid);
186321936Shselasky	}
187321936Shselasky
188321936Shselasky	if (!smp_set_via(buf, portid, ATTRID_PM_ROUTE, 0, 0, srcport))
189321936Shselasky		IBEXIT("port mirror route set failed");
190321936Shselasky
191321936ShselaskyExit:
192321936Shselasky	mad_dump_portmirror_route(str, sizeof str, buf, sizeof buf);
193321936Shselasky	printf("Port Mirror Route\n%s", str);
194321936Shselasky}
195321936Shselasky
196321936Shselaskyvoid port_mirror_ports(ib_portid_t * portid, int query, int clear)
197321936Shselasky{
198321936Shselasky	int p, rqf, tqf, rqv, tqv;
199321936Shselasky
200321936Shselasky	memset(&buf, 0, sizeof(buf));
201321936Shselasky
202321936Shselasky	if (clear) {
203321936Shselasky		if (!smp_set_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport))
204321936Shselasky			IBEXIT("Clear port mirror ports set failed");
205321936Shselasky		return;
206321936Shselasky	}
207321936Shselasky
208321936Shselasky	if (query) {
209321936Shselasky		if (!smp_query_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport))
210321936Shselasky			IBEXIT("Read port mirror ports get failed");
211321936Shselasky		goto Exit;
212321936Shselasky	}
213321936Shselasky
214321936Shselasky	/* Port Mirror Ports */
215321936Shselasky	rqf = IB_PMP_RQ_1_F;
216321936Shselasky	tqf = IB_PMP_TQ_1_F;
217321936Shselasky
218321936Shselasky	for (p = 1; p < MAX_SWITCH_PORTS; p++) {
219321936Shselasky		rqv = mrx_ports[p] ? MP_MIRROR_ALWAYS : MP_DISABLED;
220321936Shselasky		tqv = mtx_ports[p] ? MP_MIRROR_ALWAYS : MT_MIRROR_AS_RX;
221321936Shselasky		mad_set_field(buf, 0, rqf, rqv);
222321936Shselasky		mad_set_field(buf, 0, tqf, tqv);
223321936Shselasky		rqf += 2;
224321936Shselasky		tqf += 2;
225321936Shselasky	}
226321936Shselasky
227321936Shselasky	if (!smp_set_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport))
228321936Shselasky		IBEXIT("port mirror ports set failed");
229321936Shselasky
230321936ShselaskyExit:
231321936Shselasky	mad_dump_portmirror_ports(str, sizeof str, buf, sizeof buf);
232321936Shselasky	printf("Port Mirror Ports\n%s", str);
233321936Shselasky}
234321936Shselasky
235321936Shselaskyint get_out_port(ib_portid_t* portid)
236321936Shselasky{
237321936Shselasky	int block;
238321936Shselasky	int offset;
239321936Shselasky
240321936Shselasky	if (mirror_dlid) {
241321936Shselasky		block = mirror_dlid / IB_SMP_DATA_SIZE;
242321936Shselasky		offset = mirror_dlid - block * IB_SMP_DATA_SIZE;
243321936Shselasky		/* get out port from lft */
244321936Shselasky		if (!smp_query_via(buf, portid, IB_ATTR_LINEARFORWTBL, block, 0, srcport))
245321936Shselasky			IBEXIT("linear forwarding table get failed");
246321936Shselasky		block = mirror_dlid / IB_SMP_DATA_SIZE;
247321936Shselasky		offset = mirror_dlid - block * IB_SMP_DATA_SIZE;
248321936Shselasky		return buf[offset];
249321936Shselasky	}
250321936Shselasky	else
251321936Shselasky		return mirror_dport;
252321936Shselasky}
253321936Shselasky
254321936Shselaskyint get_peer(ib_portid_t* portid, int outport, int* peerlid, int* peerport)
255321936Shselasky{
256321936Shselasky	ib_portid_t selfportid = { 0 };
257321936Shselasky	ib_portid_t peerportid = { 0 };
258321936Shselasky	int selfport = 0;
259321936Shselasky
260321936Shselasky	/* set peerportid for peer port */
261321936Shselasky	memcpy(&peerportid, portid, sizeof(peerportid));
262321936Shselasky	peerportid.drpath.cnt = 1;
263321936Shselasky	peerportid.drpath.p[1] = outport;
264321936Shselasky	if (ib_resolve_self_via(&selfportid, &selfport, 0, srcport) < 0)
265321936Shselasky		IBEXIT("failed to resolve self portid");
266321936Shselasky	peerportid.drpath.drslid = (uint16_t) selfportid.lid;
267321936Shselasky	peerportid.drpath.drdlid = 0xffff;
268321936Shselasky	if (!smp_query_via(buf, &peerportid, IB_ATTR_PORT_INFO, 0, 0, srcport))
269321936Shselasky		IBEXIT("get peer portinfo failed - unable to configure lossy\n");
270321936Shselasky
271321936Shselasky	mad_decode_field(buf, IB_PORT_LID_F, peerlid);
272321936Shselasky	mad_decode_field(buf, IB_PORT_LOCAL_PORT_F, peerport);
273321936Shselasky
274321936Shselasky	return 0;
275321936Shselasky}
276321936Shselasky
277321936Shselaskyint get_mirror_vl(ib_portid_t* portid, int outport)
278321936Shselasky{
279321936Shselasky	ib_slvl_table_t * p_slvl_tbl;
280321936Shselasky	int portnum;
281321936Shselasky	int vl;
282321936Shselasky
283321936Shselasky	/* hack; assume all sl2vl mappings are the same for any in port and outport */
284321936Shselasky	portnum = (1 << 8) | outport;
285321936Shselasky
286321936Shselasky	/* get sl2vl mapping */
287321936Shselasky	if (!smp_query_via(buf, portid, IB_ATTR_SLVL_TABLE, portnum, 0, srcport))
288321936Shselasky		IBEXIT("slvl query failed");
289321936Shselasky
290321936Shselasky	p_slvl_tbl = (ib_slvl_table_t *) buf;
291321936Shselasky	vl = ib_slvl_table_get(p_slvl_tbl, mirror_sl);
292321936Shselasky	printf("mirror_sl %d, mirror_vl %d\n", mirror_sl, vl);
293321936Shselasky	return vl;
294321936Shselasky}
295321936Shselasky
296321936Shselaskyint lossy_config(ib_portid_t* portid, int query, int clear)
297321936Shselasky{
298321936Shselasky	int outport;
299321936Shselasky	int peerport;
300321936Shselasky	int attr_mod;
301321936Shselasky	uint8_t mirror_vl;
302321936Shselasky	ib_portid_t peerportid = { 0 };
303321936Shselasky	ib_portid_t * p_portid;
304321936Shselasky	lossy_config_t local_lossy_cfg;
305321936Shselasky	lossy_config_t peer_lossy_cfg;
306321936Shselasky	lossy_config_t lossy_cfg;
307321936Shselasky
308321936Shselasky	outport = get_out_port(portid);
309321936Shselasky	if (outport == 0)
310321936Shselasky		IBEXIT("get_out_port failed, mirror_dlid and mirror_dport are 0");
311321936Shselasky
312321936Shselasky	get_peer(portid, outport, &peerportid.lid, &peerport);
313321936Shselasky
314321936Shselasky	printf("local lid %d / port %d\n", portid->lid, outport);
315321936Shselasky	printf("peer  lid %d / port %d\n", peerportid.lid, peerport);
316321936Shselasky
317321936Shselasky	mirror_vl = get_mirror_vl(portid, outport);
318321936Shselasky
319321936Shselasky	/* read local lossy configuration */
320321936Shselasky	if (!smp_query_via(buf, portid, ATTRID_LOSSY_CFG, outport, 0, srcport))
321321936Shselasky		IBEXIT("get lossy config from lid %d port %d failed - not supported\n",
322321936Shselasky			portid->lid, outport);
323321936Shselasky	memcpy(&local_lossy_cfg, buf, sizeof(local_lossy_cfg));
324321936Shselasky
325321936Shselasky	/* read peer lossy configuration */
326321936Shselasky	if (!smp_query_via(buf, &peerportid, ATTRID_LOSSY_CFG, peerport, 0, srcport))
327321936Shselasky		IBEXIT("get lossy config from lid %d port %d failed - not supported\n",
328321936Shselasky			peerportid.lid, peerport);
329321936Shselasky	memcpy(&peer_lossy_cfg, buf, sizeof(peer_lossy_cfg));
330321936Shselasky
331321936Shselasky	if (query) {
332321936Shselasky		printf("local port lid %d port %d ignore_buffer 0x%04x, ignore_credit 0x%04x\n",
333321936Shselasky			portid->lid, outport,
334321936Shselasky			ntohs(local_lossy_cfg.ignore_buffer_mask), ntohs(local_lossy_cfg.ignore_credit_mask));
335321936Shselasky		printf("peer  port lid %d port %d ignore_buffer 0x%04x, ignore_credit 0x%04x\n",
336321936Shselasky			peerportid.lid, peerport,
337321936Shselasky			ntohs(peer_lossy_cfg.ignore_buffer_mask), ntohs(peer_lossy_cfg.ignore_credit_mask));
338321936Shselasky		return 0;
339321936Shselasky	}
340321936Shselasky
341321936Shselasky	/* VLs 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 */
342321936Shselasky	/*                ignore Buf Overrun             ignore Credits                 */
343321936Shselasky	/* when mirror activated set ignore buffer overrun on peer port */
344321936Shselasky	/* when mirror is de-activated clear ignore credits on local port */
345321936Shselasky	memset(&buf, 0, sizeof(buf));
346321936Shselasky	if (clear) {
347321936Shselasky		p_portid = portid;
348321936Shselasky		attr_mod = outport;
349321936Shselasky	} else {
350321936Shselasky		/* set buffer overrun on peer port */
351321936Shselasky		p_portid = &peerportid;
352321936Shselasky		attr_mod = peerport;
353321936Shselasky		lossy_cfg.ignore_buffer_mask = htons(1<<mirror_vl);
354321936Shselasky		lossy_cfg.ignore_credit_mask = 0;
355321936Shselasky		memcpy(&buf, &lossy_cfg, sizeof(lossy_cfg));
356321936Shselasky	}
357321936Shselasky	if (!smp_set_via(buf, p_portid, ATTRID_LOSSY_CFG, attr_mod, 0, srcport))
358321936Shselasky		IBEXIT("%s lossy config on lid %d failed\n", clear?"clear":"set", p_portid->lid);
359321936Shselasky
360321936Shselasky	/* when mirror activated set ignore credit on local port */
361321936Shselasky	/* when mirror de-activated clear buffer overrun on peer */
362321936Shselasky	memset(&buf, 0, sizeof(buf));
363321936Shselasky	if (clear) {
364321936Shselasky		p_portid = &peerportid;
365321936Shselasky		attr_mod = peerport;
366321936Shselasky	} else {
367321936Shselasky		/* set ignore credit on local port */
368321936Shselasky		p_portid = portid;
369321936Shselasky		attr_mod = outport;
370321936Shselasky		lossy_cfg.ignore_credit_mask = htons(1<<mirror_vl);
371321936Shselasky		lossy_cfg.ignore_buffer_mask = 0;
372321936Shselasky		memcpy(&buf, &lossy_cfg, sizeof(lossy_cfg));
373321936Shselasky	}
374321936Shselasky	if (!smp_set_via(buf, p_portid, ATTRID_LOSSY_CFG, attr_mod, 0, srcport))
375321936Shselasky		IBEXIT("%s lossy config on lid %d failed\n", clear?"clear":"set", p_portid->lid);
376321936Shselasky
377321936Shselasky	return 0;
378321936Shselasky}
379321936Shselasky
380321936Shselaskyint mirror_config(ib_portid_t* portid, int query, int clear)
381321936Shselasky{
382321936Shselasky	port_mirror_route(portid, query, clear);
383321936Shselasky	/* port_mirror_filter(portid, query, clear); */
384321936Shselasky	port_mirror_ports(portid, query, clear);
385321936Shselasky
386321936Shselasky	return 0;
387321936Shselasky}
388321936Shselasky
389321936Shselaskystatic int process_opt(void *context, int ch, char *optarg)
390321936Shselasky{
391321936Shselasky	switch (ch) {
392321936Shselasky	case 'p':
393321936Shselasky		mirror_dport = strtoul(optarg, NULL, 0);
394321936Shselasky		break;
395321936Shselasky	case 'S':
396321936Shselasky		packet_size = strtoul(optarg, NULL, 0);
397321936Shselasky		break;
398321936Shselasky	case 'l':
399321936Shselasky		mirror_sl = strtoul(optarg, NULL, 0);
400321936Shselasky		break;
401321936Shselasky	case 'L':
402321936Shselasky		mirror_dlid = strtoul(optarg, NULL, 0);
403321936Shselasky		break;
404321936Shselasky	case 'R':
405321936Shselasky		set_mrx = 1;
406321936Shselasky		if (-1 == parse_ports(optarg, mrx_ports))
407321936Shselasky			return -1;
408321936Shselasky		break;
409321936Shselasky	case 'T':
410321936Shselasky		set_mtx = 1;
411321936Shselasky		if (-1 == parse_ports(optarg, mtx_ports))
412321936Shselasky			return -1;
413321936Shselasky		break;
414321936Shselasky	case 'D':
415321936Shselasky		mirror_clear = 1;
416321936Shselasky		break;
417321936Shselasky	case 'Q':
418321936Shselasky		mirror_query = 1;
419321936Shselasky		break;
420321936Shselasky	case 'y':
421321936Shselasky		lossy_set = 1;
422321936Shselasky		break;
423321936Shselasky	default:
424321936Shselasky		return -1;
425321936Shselasky	}
426321936Shselasky	return 0;
427321936Shselasky}
428321936Shselasky
429321936Shselaskyint main(int argc, char **argv)
430321936Shselasky{
431321936Shselasky	int mgmt_classes[4] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS,
432321936Shselasky		IB_MLX_VENDOR_CLASS
433321936Shselasky	};
434321936Shselasky	ib_portid_t portid = { 0 };
435321936Shselasky	int port = 0;
436321936Shselasky	ib_vendor_call_t call;
437321936Shselasky	is3_general_info_t *gi;
438321936Shselasky	uint32_t fw_ver;
439321936Shselasky	char op_str[32];
440321936Shselasky
441321936Shselasky	const struct ibdiag_opt opts[] = {
442321936Shselasky		{"dport", 'p', 1, "<port>", "set mirror destination port"},
443321936Shselasky		{"dlid", 'L', 1, "<dlid>", "set mirror destination LID"},
444321936Shselasky		{"sl", 'l', 1, "<sl>", "set mirror SL"},
445321936Shselasky		{"size", 'S', 1, "<size>", "set packet size"},
446321936Shselasky		{"rxports", 'R', 1, NULL, "mirror receive port list"},
447321936Shselasky		{"txports", 'T', 1, NULL, "mirror transmit port list"},
448321936Shselasky		{"clear", 'D', 0, NULL, "clear ports mirroring"},
449321936Shselasky		{"query", 'Q', 0, NULL, "read mirror configuration"},
450321936Shselasky		{"lossy", 'y', 0, NULL, "set lossy configuration on out port"},
451321936Shselasky		{0}
452321936Shselasky	};
453321936Shselasky
454321936Shselasky	char usage_args[] = "<lid>";
455321936Shselasky	const char *usage_examples[] = {
456321936Shselasky		"-R 1,2,3 -T 2,5 -l1 -L25 -S100 <lid>\t# configure mirror ports",
457321936Shselasky		"-D <lid> \t# clear mirror configuration",
458321936Shselasky		"-Q <lid>\t# read mirror configuration",
459321936Shselasky		NULL
460321936Shselasky	};
461321936Shselasky
462321936Shselasky	ibdiag_process_opts(argc, argv, NULL, "GDLs", opts, process_opt,
463321936Shselasky			    usage_args, usage_examples);
464321936Shselasky
465321936Shselasky	argc -= optind;
466321936Shselasky	argv += optind;
467321936Shselasky
468321936Shselasky	if (argc == 0)
469321936Shselasky		ibdiag_show_usage();
470321936Shselasky
471321936Shselasky	srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4);
472321936Shselasky	if (!srcport)
473321936Shselasky		IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port);
474321936Shselasky
475321936Shselasky	if (argc) {
476321936Shselasky		if (ib_resolve_portid_str_via(&portid, argv[0], ibd_dest_type,
477321936Shselasky					      ibd_sm_id, srcport) < 0)
478321936Shselasky			IBEXIT("can't resolve destination port %s", argv[0]);
479321936Shselasky	}
480321936Shselasky
481321936Shselasky
482321936Shselasky	memset(&buf, 0, sizeof(buf));
483321936Shselasky	memset(&call, 0, sizeof(call));
484321936Shselasky	call.mgmt_class = IB_MLX_VENDOR_CLASS;
485321936Shselasky	call.method = IB_MAD_METHOD_GET;
486321936Shselasky	call.timeout = ibd_timeout;
487321936Shselasky	call.attrid = IB_MLX_IS3_GENERAL_INFO;
488321936Shselasky	if (!ib_vendor_call_via(&buf, &portid, &call, srcport))
489321936Shselasky		IBEXIT("failed to read vendor info");
490321936Shselasky	gi = (is3_general_info_t *) & buf;
491321936Shselasky	if (ntohs(gi->hw_info.device_id) != 0x1b3)
492321936Shselasky		IBEXIT("device id 0x%x does not support mirroring", ntohs(gi->hw_info.device_id));
493321936Shselasky
494321936Shselasky	fw_ver = gi->fw_info.major * 100000 + gi->fw_info.minor * 1000 + gi->fw_info.sub_minor;
495321936Shselasky	printf("FW version %08d\n", fw_ver);
496321936Shselasky	if (lossy_set && fw_ver < 704000)
497321936Shselasky		IBEXIT("FW version %d.%d.%d does not support lossy config",
498321936Shselasky			gi->fw_info.major, gi->fw_info.minor, gi->fw_info.sub_minor);
499321936Shselasky
500321936Shselasky	if (ibdebug) {
501321936Shselasky		printf( "switch_lid = %d\n"
502321936Shselasky			"mirror_clear = %d\n"
503321936Shselasky			"mirror_dlid = %d\n"
504321936Shselasky			"mirror_sl = %d\n"
505321936Shselasky			"mirror_port = %d\n",
506321936Shselasky			portid.lid, mirror_clear, mirror_dlid,
507321936Shselasky			mirror_sl, mirror_dport);
508321936Shselasky
509321936Shselasky		for (port = 1; port < MAX_SWITCH_PORTS; port++) {
510321936Shselasky			if (mtx_ports[port])
511321936Shselasky				printf("TX:	%d\n",port);
512321936Shselasky			else if(mrx_ports[port])
513321936Shselasky				printf("RX:	%d\n",port);
514321936Shselasky		}
515321936Shselasky	}
516321936Shselasky
517321936Shselasky	if (mirror_clear)
518321936Shselasky		strcpy(op_str, "Clear");
519321936Shselasky	else if (mirror_query)
520321936Shselasky		strcpy(op_str, "Read");
521321936Shselasky	else if (!mirror_dport && !mirror_dlid)
522321936Shselasky		IBEXIT("Mirror remote LID and local port are zero");
523321936Shselasky	else if (!set_mtx && !set_mrx)
524321936Shselasky		IBEXIT("Mirror Rx and Tx ports not selected");
525321936Shselasky	else
526321936Shselasky		strcpy(op_str, "Set");
527321936Shselasky
528321936Shselasky	printf("\n%s Mirror Configuration\n", op_str);
529321936Shselasky	mirror_config(&portid, mirror_query, mirror_clear);
530321936Shselasky
531321936Shselasky	if (lossy_set) {
532321936Shselasky		printf("%s Lossy Configuration\n", op_str);
533321936Shselasky		lossy_config(&portid, mirror_query, mirror_clear);
534321936Shselasky	}
535321936Shselasky
536321936Shselasky	mad_rpc_close_port(srcport);
537321936Shselasky	exit(0);
538321936Shselasky}
539