1249259Sdim/*
2249259Sdim * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved.
3249259Sdim * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4249259Sdim * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5249259Sdim *
6249259Sdim * This software is available to you under a choice of one of two
7249259Sdim * licenses.  You may choose to be licensed under the terms of the GNU
8249259Sdim * General Public License (GPL) Version 2, available from the file
9249259Sdim * COPYING in the main directory of this source tree, or the
10249259Sdim * OpenIB.org BSD license below:
11249259Sdim *
12249259Sdim *     Redistribution and use in source and binary forms, with or
13249259Sdim *     without modification, are permitted provided that the following
14249259Sdim *     conditions are met:
15249259Sdim *
16249259Sdim *      - Redistributions of source code must retain the above
17249259Sdim *        copyright notice, this list of conditions and the following
18249259Sdim *        disclaimer.
19249259Sdim *
20249259Sdim *      - Redistributions in binary form must reproduce the above
21249259Sdim *        copyright notice, this list of conditions and the following
22249259Sdim *        disclaimer in the documentation and/or other materials
23249259Sdim *        provided with the distribution.
24249259Sdim *
25249259Sdim * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26249259Sdim * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27249259Sdim * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28249259Sdim * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29249259Sdim * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30249259Sdim * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31249259Sdim * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32249259Sdim * SOFTWARE.
33249259Sdim *
34249259Sdim */
35249259Sdim
36249259Sdim/*
37249259Sdim * Abstract:
38249259Sdim *    Implementation of SLtoVL and VL Arbitration testing flow..
39249259Sdim *    Top level is osmt_run_slvl_and_vlarb_records_flow:
40249259Sdim *     osmt_query_all_ports_vl_arb
41249259Sdim *     osmt_query_all_ports_slvl_map
42249259Sdim *
43249259Sdim */
44249259Sdim
45249259Sdim#ifndef __WIN__
46249259Sdim#include <unistd.h>
47249259Sdim#endif
48249259Sdim#include <stdio.h>
49249259Sdim#include <stdlib.h>
50249259Sdim#include <string.h>
51249259Sdim#include <complib/cl_debug.h>
52249259Sdim#include "osmtest.h"
53249259Sdim
54249259Sdim/**********************************************************************
55249259Sdim **********************************************************************/
56249259Sdimstatic ib_api_status_t
57249259Sdimosmtest_write_vl_arb_table(IN osmtest_t * const p_osmt,
58249259Sdim			   IN FILE * fh,
59249259Sdim			   IN const ib_vl_arb_table_record_t * const p_rec)
60249259Sdim{
61249259Sdim	int result, i;
62249259Sdim	cl_status_t status = IB_SUCCESS;
63249259Sdim
64249259Sdim	OSM_LOG_ENTER(&p_osmt->log);
65249259Sdim
66249259Sdim	result = fprintf(fh,
67249259Sdim			 "VL_ARBITRATION_TABLE\n"
68249259Sdim			 "lid                     0x%X\n"
69249259Sdim			 "port_num                0x%X\n"
70249259Sdim			 "block                   0x%X\n",
71249259Sdim			 cl_ntoh16(p_rec->lid),
72249259Sdim			 p_rec->port_num, p_rec->block_num);
73249259Sdim
74249259Sdim	fprintf(fh, "       ");
75249259Sdim	for (i = 0; i < 32; i++)
76249259Sdim		fprintf(fh, "| %-2u ", i);
77249259Sdim	fprintf(fh, "|\nVL:    ");
78249259Sdim
79249259Sdim	for (i = 0; i < 32; i++)
80249259Sdim		fprintf(fh, "|0x%02X", p_rec->vl_arb_tbl.vl_entry[i].vl);
81249259Sdim	fprintf(fh, "|\nWEIGHT:");
82249259Sdim
83249259Sdim	for (i = 0; i < 32; i++)
84249259Sdim		fprintf(fh, "|0x%02X", p_rec->vl_arb_tbl.vl_entry[i].weight);
85249259Sdim	fprintf(fh, "|\nEND\n\n");
86249259Sdim
87249259Sdim	/*  Exit: */
88249259Sdim	OSM_LOG_EXIT(&p_osmt->log);
89249259Sdim	return (status);
90249259Sdim}
91249259Sdim
92249259Sdim/**********************************************************************
93249259Sdim * GET A SINGLE PORT INFO BY NODE LID AND PORT NUMBER
94249259Sdim **********************************************************************/
95249259Sdimib_api_status_t
96249259Sdimosmt_query_vl_arb(IN osmtest_t * const p_osmt,
97249259Sdim		  IN ib_net16_t const lid,
98249259Sdim		  IN uint8_t const port_num,
99249259Sdim		  IN uint8_t const block_num, IN FILE * fh)
100249259Sdim{
101249259Sdim	osmtest_req_context_t context;
102249259Sdim	ib_api_status_t status = IB_SUCCESS;
103249259Sdim	osmv_user_query_t user;
104249259Sdim	osmv_query_req_t req;
105249259Sdim	ib_vl_arb_table_record_t record, *p_rec;
106249259Sdim
107249259Sdim	OSM_LOG_ENTER(&p_osmt->log);
108249259Sdim
109249259Sdim	OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG,
110249259Sdim		"Getting VL_Arbitration Table for port with LID 0x%X Num:0x%X\n",
111249259Sdim		cl_ntoh16(lid), port_num);
112249259Sdim
113249259Sdim	/*
114249259Sdim	 * Do a blocking query for this record in the subnet.
115249259Sdim	 * The result is returned in the result field of the caller's
116249259Sdim	 * context structure.
117249259Sdim	 *
118249259Sdim	 * The query structures are locals.
119249259Sdim	 */
120249259Sdim	memset(&req, 0, sizeof(req));
121249259Sdim	memset(&user, 0, sizeof(user));
122249259Sdim	memset(&context, 0, sizeof(context));
123249259Sdim
124249259Sdim	context.p_osmt = p_osmt;
125249259Sdim
126249259Sdim	record.lid = lid;
127249259Sdim	record.port_num = port_num;
128249259Sdim	record.block_num = block_num;
129249259Sdim	user.p_attr = &record;
130249259Sdim
131249259Sdim	req.query_type = OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK;
132249259Sdim	req.timeout_ms = p_osmt->opt.transaction_timeout;
133249259Sdim	req.retry_cnt = p_osmt->opt.retry_count;
134249259Sdim	req.flags = OSM_SA_FLAGS_SYNC;
135249259Sdim	req.query_context = &context;
136249259Sdim	req.pfn_query_cb = osmtest_query_res_cb;
137249259Sdim	req.p_query_input = &user;
138249259Sdim	req.sm_key = 0;
139249259Sdim
140249259Sdim	status = osmv_query_sa(p_osmt->h_bind, &req);
141249259Sdim
142249259Sdim	if (status != IB_SUCCESS) {
143249259Sdim		OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0405: "
144249259Sdim			"ib_query failed (%s)\n", ib_get_err_str(status));
145249259Sdim		goto Exit;
146249259Sdim	}
147249259Sdim
148249259Sdim	status = context.result.status;
149249259Sdim
150249259Sdim	if (status != IB_SUCCESS) {
151249259Sdim		OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0466: "
152249259Sdim			"ib_query failed (%s)\n", ib_get_err_str(status));
153249259Sdim
154249259Sdim		if (status == IB_REMOTE_ERROR) {
155249259Sdim			OSM_LOG(&p_osmt->log, OSM_LOG_ERROR,
156249259Sdim				"Remote error = %s\n",
157249259Sdim				ib_get_mad_status_str(osm_madw_get_mad_ptr
158249259Sdim						      (context.result.
159249259Sdim						       p_result_madw)));
160249259Sdim		}
161249259Sdim		goto Exit;
162249259Sdim	}
163249259Sdim
164249259Sdim	/* ok it worked */
165249259Sdim	p_rec = osmv_get_query_result(context.result.p_result_madw, 0);
166249259Sdim	if (fh) {
167249259Sdim		osmtest_write_vl_arb_table(p_osmt, fh, p_rec);
168249259Sdim	}
169249259Sdim
170249259SdimExit:
171249259Sdim	/*
172249259Sdim	 * Return the IB query MAD to the pool as necessary.
173249259Sdim	 */
174249259Sdim	if (context.result.p_result_madw != NULL) {
175249259Sdim		osm_mad_pool_put(&p_osmt->mad_pool,
176249259Sdim				 context.result.p_result_madw);
177249259Sdim		context.result.p_result_madw = NULL;
178249259Sdim	}
179249259Sdim
180249259Sdim	OSM_LOG_EXIT(&p_osmt->log);
181249259Sdim	return (status);
182249259Sdim}
183249259Sdim
184249259Sdimstatic ib_api_status_t
185249259Sdimosmt_query_all_ports_vl_arb(IN osmtest_t * const p_osmt, IN FILE * fh)
186249259Sdim{
187249259Sdim	cl_status_t status = CL_SUCCESS;
188249259Sdim	cl_qmap_t *p_tbl;
189249259Sdim	port_t *p_src_port;
190249259Sdim	uint8_t block, anyErr = 0;
191249259Sdim
192249259Sdim	OSM_LOG_ENTER(&p_osmt->log);
193249259Sdim
194249259Sdim	OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE,
195249259Sdim		"Obtaining ALL Ports VL Arbitration Tables\n");
196249259Sdim
197249259Sdim	/*
198249259Sdim	 * Go over all ports that exist in the subnet
199249259Sdim	 * get the relevant VLarbs
200249259Sdim	 */
201249259Sdim
202249259Sdim	p_tbl = &p_osmt->exp_subn.port_key_tbl;
203249259Sdim
204249259Sdim	p_src_port = (port_t *) cl_qmap_head(p_tbl);
205249259Sdim
206249259Sdim	while (p_src_port != (port_t *) cl_qmap_end(p_tbl)) {
207249259Sdim
208249259Sdim		/* HACK we use capability_mask to know diff a CA port from switch port */
209249259Sdim		if (p_src_port->rec.port_info.capability_mask) {
210249259Sdim			/* this is an hca port */
211249259Sdim			for (block = 1; block <= 4; block++) {
212249259Sdim				/*  NOTE to comply we must set port number to 0 and the SA should figure it out */
213249259Sdim				/*  since it is a CA port */
214249259Sdim				status =
215249259Sdim				    osmt_query_vl_arb(p_osmt,
216249259Sdim						      p_src_port->rec.lid, 0,
217249259Sdim						      block, fh);
218249259Sdim				if (status != IB_SUCCESS) {
219249259Sdim					OSM_LOG(&p_osmt->log, OSM_LOG_ERROR,
220249259Sdim						"ERR 0467: "
221249259Sdim						"Failed to get Lid:0x%X Port:0x%X (%s)\n",
222249259Sdim						cl_ntoh16(p_src_port->rec.lid),
223249259Sdim						0, ib_get_err_str(status));
224249259Sdim					anyErr = 1;
225249259Sdim				}
226249259Sdim			}
227249259Sdim		} else {
228249259Sdim			/* this is a switch port */
229249259Sdim			for (block = 1; block <= 4; block++) {
230249259Sdim				status =
231249259Sdim				    osmt_query_vl_arb(p_osmt,
232249259Sdim						      p_src_port->rec.lid,
233249259Sdim						      p_src_port->rec.port_num,
234249259Sdim						      block, fh);
235249259Sdim				if (status != IB_SUCCESS) {
236249259Sdim					OSM_LOG(&p_osmt->log, OSM_LOG_ERROR,
237249259Sdim						"ERR 0468: "
238249259Sdim						"Failed to get Lid:0x%X Port:0x%X (%s)\n",
239249259Sdim						cl_ntoh16(p_src_port->rec.lid),
240249259Sdim						p_src_port->rec.port_num,
241249259Sdim						ib_get_err_str(status));
242249259Sdim					anyErr = 1;
243249259Sdim				}
244249259Sdim			}
245249259Sdim		}
246249259Sdim
247249259Sdim		p_src_port = (port_t *) cl_qmap_next(&p_src_port->map_item);
248249259Sdim	}
249249259Sdim
250249259Sdim	OSM_LOG_EXIT(&p_osmt->log);
251249259Sdim	if (anyErr) {
252249259Sdim		status = IB_ERROR;
253249259Sdim	}
254249259Sdim	return (status);
255249259Sdim}
256249259Sdim
257249259Sdim/*******************************************************************************
258249259Sdim SLtoVL
259249259Sdim*******************************************************************************/
260249259Sdimstatic ib_api_status_t
261249259Sdimosmtest_write_slvl_map_table(IN osmtest_t * const p_osmt,
262249259Sdim			     IN FILE * fh,
263249259Sdim			     IN const ib_slvl_table_record_t * const p_rec)
264249259Sdim{
265249259Sdim	int result, i;
266249259Sdim	cl_status_t status = IB_SUCCESS;
267249259Sdim
268249259Sdim	OSM_LOG_ENTER(&p_osmt->log);
269249259Sdim
270249259Sdim	result = fprintf(fh,
271249259Sdim			 "SLtoVL_MAP_TABLE\n"
272249259Sdim			 "lid                     0x%X\n"
273249259Sdim			 "in_port_num             0x%X\n"
274249259Sdim			 "out_port_num            0x%X\n",
275249259Sdim			 cl_ntoh16(p_rec->lid),
276249259Sdim			 p_rec->in_port_num, p_rec->out_port_num);
277249259Sdim
278249259Sdim	fprintf(fh, "SL:");
279249259Sdim	for (i = 0; i < 16; i++)
280249259Sdim		fprintf(fh, "| %-2u  ", i);
281249259Sdim	fprintf(fh, "|\nVL:");
282249259Sdim
283249259Sdim	for (i = 0; i < 16; i++)
284249259Sdim		fprintf(fh, "| 0x%01X ",
285249259Sdim			ib_slvl_table_get(&p_rec->slvl_tbl, (uint8_t) i));
286249259Sdim	fprintf(fh, "|\nEND\n\n");
287249259Sdim
288249259Sdim	/*  Exit: */
289249259Sdim	OSM_LOG_EXIT(&p_osmt->log);
290249259Sdim	return (status);
291249259Sdim}
292249259Sdim
293249259Sdim/**********************************************************************
294249259Sdim * GET A SINGLE PORT INFO BY NODE LID AND PORT NUMBER
295249259Sdim **********************************************************************/
296249259Sdimib_api_status_t
297249259Sdimosmt_query_slvl_map(IN osmtest_t * const p_osmt,
298249259Sdim		    IN ib_net16_t const lid,
299249259Sdim		    IN uint8_t const out_port_num,
300249259Sdim		    IN uint8_t const in_port_num, IN FILE * fh)
301249259Sdim{
302249259Sdim	osmtest_req_context_t context;
303249259Sdim	ib_api_status_t status = IB_SUCCESS;
304249259Sdim	osmv_user_query_t user;
305249259Sdim	osmv_query_req_t req;
306249259Sdim	ib_slvl_table_record_t record, *p_rec;
307249259Sdim
308249259Sdim	OSM_LOG_ENTER(&p_osmt->log);
309249259Sdim
310249259Sdim	OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG,
311249259Sdim		"Getting SLtoVL Map Table for out-port with LID 0x%X Num:0x%X from In-Port:0x%X\n",
312249259Sdim		cl_ntoh16(lid), out_port_num, in_port_num);
313249259Sdim
314249259Sdim	/*
315249259Sdim	 * Do a blocking query for this record in the subnet.
316	 * The result is returned in the result field of the caller's
317	 * context structure.
318	 *
319	 * The query structures are locals.
320	 */
321	memset(&req, 0, sizeof(req));
322	memset(&user, 0, sizeof(user));
323	memset(&context, 0, sizeof(context));
324
325	context.p_osmt = p_osmt;
326
327	record.lid = lid;
328	record.in_port_num = in_port_num;
329	record.out_port_num = out_port_num;
330	user.p_attr = &record;
331
332	req.query_type = OSMV_QUERY_SLVL_BY_LID_AND_PORTS;
333	req.timeout_ms = p_osmt->opt.transaction_timeout;
334	req.retry_cnt = p_osmt->opt.retry_count;
335	req.flags = OSM_SA_FLAGS_SYNC;
336	req.query_context = &context;
337	req.pfn_query_cb = osmtest_query_res_cb;
338	req.p_query_input = &user;
339	req.sm_key = 0;
340
341	status = osmv_query_sa(p_osmt->h_bind, &req);
342
343	if (status != IB_SUCCESS) {
344		OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0469: "
345			"ib_query failed (%s)\n", ib_get_err_str(status));
346		goto Exit;
347	}
348
349	status = context.result.status;
350
351	if (status != IB_SUCCESS) {
352		OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0470: "
353			"ib_query failed (%s)\n", ib_get_err_str(status));
354
355		if (status == IB_REMOTE_ERROR) {
356			OSM_LOG(&p_osmt->log, OSM_LOG_ERROR,
357				"Remote error = %s\n",
358				ib_get_mad_status_str(osm_madw_get_mad_ptr
359						      (context.result.
360						       p_result_madw)));
361		}
362		goto Exit;
363	}
364
365	/* ok it worked */
366	p_rec = osmv_get_query_result(context.result.p_result_madw, 0);
367	if (fh) {
368		osmtest_write_slvl_map_table(p_osmt, fh, p_rec);
369	}
370
371Exit:
372	/*
373	 * Return the IB query MAD to the pool as necessary.
374	 */
375	if (context.result.p_result_madw != NULL) {
376		osm_mad_pool_put(&p_osmt->mad_pool,
377				 context.result.p_result_madw);
378		context.result.p_result_madw = NULL;
379	}
380
381	OSM_LOG_EXIT(&p_osmt->log);
382	return (status);
383}
384
385static ib_api_status_t
386osmt_query_all_ports_slvl_map(IN osmtest_t * const p_osmt, IN FILE * fh)
387{
388	cl_status_t status = CL_SUCCESS;
389	cl_qmap_t *p_tbl;
390	port_t *p_src_port;
391	uint8_t in_port, anyErr = 0, num_ports;
392	node_t *p_node;
393	const cl_qmap_t *p_node_tbl;
394
395	OSM_LOG_ENTER(&p_osmt->log);
396
397	/*
398	 * Go over all ports that exist in the subnet
399	 * get the relevant SLtoVLs
400	 */
401
402	OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE,
403		"Obtaining ALL Ports (to other ports) SLtoVL Maps\n");
404
405	p_tbl = &p_osmt->exp_subn.port_key_tbl;
406	p_node_tbl = &p_osmt->exp_subn.node_lid_tbl;
407
408	p_src_port = (port_t *) cl_qmap_head(p_tbl);
409
410	while (p_src_port != (port_t *) cl_qmap_end(p_tbl)) {
411
412		/* HACK we use capability_mask to know diff a CA port from switch port */
413		if (p_src_port->rec.port_info.capability_mask) {
414			/* this is an hca port */
415			/*  NOTE to comply we must set port number to 0 and the SA should figure it out */
416			/*  since it is a CA port */
417			status =
418			    osmt_query_slvl_map(p_osmt, p_src_port->rec.lid, 0,
419						0, fh);
420			if (status != IB_SUCCESS) {
421				OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0471: "
422					"Failed to get Lid:0x%X In-Port:0x%X Out-Port:0x%X(%s)\n",
423					cl_ntoh16(p_src_port->rec.lid), 0, 0,
424					ib_get_err_str(status));
425				anyErr = 1;
426			}
427		} else {
428			/* this is a switch port */
429			/* get the node */
430			p_node =
431			    (node_t *) cl_qmap_get(p_node_tbl,
432						   p_src_port->rec.lid);
433			if (p_node == (node_t *) cl_qmap_end(p_node_tbl)) {
434				OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0472: "
435					"Failed to get Node by Lid:0x%X\n",
436					p_src_port->rec.lid);
437				goto Exit;
438			}
439
440			num_ports = p_node->rec.node_info.num_ports;
441
442			for (in_port = 1; in_port <= num_ports; in_port++) {
443				status =
444				    osmt_query_slvl_map(p_osmt,
445							p_src_port->rec.lid,
446							p_src_port->rec.
447							port_num, in_port, fh);
448				if (status != IB_SUCCESS) {
449					OSM_LOG(&p_osmt->log, OSM_LOG_ERROR,
450						"ERR 0473: "
451						"Failed to get Lid:0x%X In-Port:0x%X Out-Port:0x%X (%s)\n",
452						cl_ntoh16(p_src_port->rec.lid),
453						p_src_port->rec.port_num,
454						in_port,
455						ib_get_err_str(status));
456					anyErr = 1;
457				}
458			}
459		}
460
461		p_src_port = (port_t *) cl_qmap_next(&p_src_port->map_item);
462	}
463
464Exit:
465	OSM_LOG_EXIT(&p_osmt->log);
466	if (anyErr) {
467		status = IB_ERROR;
468	}
469	return (status);
470}
471
472/*
473 * Run a vl arbitration queries and sl2vl maps queries flow:
474 * Good flow:
475 * - for each physical port on the network - obtain the VL Arb
476 * - for each CA physical port obtain its SLtoVL Map
477 * - for each SW physical port (out) obtain the SLtoVL Map to each other port
478 * BAD flow:
479 * - Try get with multiple results
480 * - Try gettable
481 * - Try providing non existing port
482 */
483ib_api_status_t
484osmt_run_slvl_and_vlarb_records_flow(IN osmtest_t * const p_osmt)
485{
486	ib_api_status_t status;
487	FILE *fh;
488	ib_net16_t test_lid;
489	uint8_t lmc;
490
491	OSM_LOG_ENTER(&p_osmt->log);
492
493	fh = fopen("qos.txt", "w");
494
495	/* go over all ports in the subnet */
496	status = osmt_query_all_ports_vl_arb(p_osmt, fh);
497	if (status != IB_SUCCESS) {
498		goto Exit;
499	}
500
501	status = osmt_query_all_ports_slvl_map(p_osmt, fh);
502	if (status != IB_SUCCESS) {
503		goto Exit;
504	}
505
506	/* If LMC > 0, test non base LID SA QoS Record requests */
507	status =
508	    osmtest_get_local_port_lmc(p_osmt, p_osmt->local_port.lid, &lmc);
509	if (status != IB_SUCCESS)
510		goto Exit;
511
512	if (lmc != 0) {
513		test_lid = cl_ntoh16(p_osmt->local_port.lid + 1);
514
515		status = osmt_query_vl_arb(p_osmt, test_lid, 0, 1, NULL);
516		if (status != IB_SUCCESS)
517			goto Exit;
518
519		status = osmt_query_slvl_map(p_osmt, test_lid, 0, 0, NULL);
520		if (status != IB_SUCCESS)
521			goto Exit;
522	}
523
524Exit:
525	fclose(fh);
526	OSM_LOG_EXIT(&p_osmt->log);
527	return status;
528}
529