1/*
2 * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 *
6 * This software is available to you under a choice of one of two
7 * licenses.  You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
11 *
12 *     Redistribution and use in source and binary forms, with or
13 *     without modification, are permitted provided that the following
14 *     conditions are met:
15 *
16 *      - Redistributions of source code must retain the above
17 *        copyright notice, this list of conditions and the following
18 *        disclaimer.
19 *
20 *      - Redistributions in binary form must reproduce the above
21 *        copyright notice, this list of conditions and the following
22 *        disclaimer in the documentation and/or other materials
23 *        provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 *
34 */
35
36/*
37 * Abstract:
38 *    Implementation of SLtoVL and VL Arbitration testing flow..
39 *    Top level is osmt_run_slvl_and_vlarb_records_flow:
40 *     osmt_query_all_ports_vl_arb
41 *     osmt_query_all_ports_slvl_map
42 *
43 */
44
45#ifndef __WIN__
46#include <unistd.h>
47#endif
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <complib/cl_debug.h>
52#include "osmtest.h"
53
54/**********************************************************************
55 **********************************************************************/
56static ib_api_status_t
57osmtest_write_vl_arb_table(IN osmtest_t * const p_osmt,
58			   IN FILE * fh,
59			   IN const ib_vl_arb_table_record_t * const p_rec)
60{
61	int result, i;
62	cl_status_t status = IB_SUCCESS;
63
64	OSM_LOG_ENTER(&p_osmt->log);
65
66	result = fprintf(fh,
67			 "VL_ARBITRATION_TABLE\n"
68			 "lid                     0x%X\n"
69			 "port_num                0x%X\n"
70			 "block                   0x%X\n",
71			 cl_ntoh16(p_rec->lid),
72			 p_rec->port_num, p_rec->block_num);
73
74	fprintf(fh, "       ");
75	for (i = 0; i < 32; i++)
76		fprintf(fh, "| %-2u ", i);
77	fprintf(fh, "|\nVL:    ");
78
79	for (i = 0; i < 32; i++)
80		fprintf(fh, "|0x%02X", p_rec->vl_arb_tbl.vl_entry[i].vl);
81	fprintf(fh, "|\nWEIGHT:");
82
83	for (i = 0; i < 32; i++)
84		fprintf(fh, "|0x%02X", p_rec->vl_arb_tbl.vl_entry[i].weight);
85	fprintf(fh, "|\nEND\n\n");
86
87	/*  Exit: */
88	OSM_LOG_EXIT(&p_osmt->log);
89	return (status);
90}
91
92/**********************************************************************
93 * GET A SINGLE PORT INFO BY NODE LID AND PORT NUMBER
94 **********************************************************************/
95ib_api_status_t
96osmt_query_vl_arb(IN osmtest_t * const p_osmt,
97		  IN ib_net16_t const lid,
98		  IN uint8_t const port_num,
99		  IN uint8_t const block_num, IN FILE * fh)
100{
101	osmtest_req_context_t context;
102	ib_api_status_t status = IB_SUCCESS;
103	osmv_user_query_t user;
104	osmv_query_req_t req;
105	ib_vl_arb_table_record_t record, *p_rec;
106
107	OSM_LOG_ENTER(&p_osmt->log);
108
109	OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG,
110		"Getting VL_Arbitration Table for port with LID 0x%X Num:0x%X\n",
111		cl_ntoh16(lid), port_num);
112
113	/*
114	 * Do a blocking query for this record in the subnet.
115	 * The result is returned in the result field of the caller's
116	 * context structure.
117	 *
118	 * The query structures are locals.
119	 */
120	memset(&req, 0, sizeof(req));
121	memset(&user, 0, sizeof(user));
122	memset(&context, 0, sizeof(context));
123
124	context.p_osmt = p_osmt;
125
126	record.lid = lid;
127	record.port_num = port_num;
128	record.block_num = block_num;
129	user.p_attr = &record;
130
131	req.query_type = OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK;
132	req.timeout_ms = p_osmt->opt.transaction_timeout;
133	req.retry_cnt = p_osmt->opt.retry_count;
134	req.flags = OSM_SA_FLAGS_SYNC;
135	req.query_context = &context;
136	req.pfn_query_cb = osmtest_query_res_cb;
137	req.p_query_input = &user;
138	req.sm_key = 0;
139
140	status = osmv_query_sa(p_osmt->h_bind, &req);
141
142	if (status != IB_SUCCESS) {
143		OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0405: "
144			"ib_query failed (%s)\n", ib_get_err_str(status));
145		goto Exit;
146	}
147
148	status = context.result.status;
149
150	if (status != IB_SUCCESS) {
151		OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0466: "
152			"ib_query failed (%s)\n", ib_get_err_str(status));
153
154		if (status == IB_REMOTE_ERROR) {
155			OSM_LOG(&p_osmt->log, OSM_LOG_ERROR,
156				"Remote error = %s\n",
157				ib_get_mad_status_str(osm_madw_get_mad_ptr
158						      (context.result.
159						       p_result_madw)));
160		}
161		goto Exit;
162	}
163
164	/* ok it worked */
165	p_rec = osmv_get_query_result(context.result.p_result_madw, 0);
166	if (fh) {
167		osmtest_write_vl_arb_table(p_osmt, fh, p_rec);
168	}
169
170Exit:
171	/*
172	 * Return the IB query MAD to the pool as necessary.
173	 */
174	if (context.result.p_result_madw != NULL) {
175		osm_mad_pool_put(&p_osmt->mad_pool,
176				 context.result.p_result_madw);
177		context.result.p_result_madw = NULL;
178	}
179
180	OSM_LOG_EXIT(&p_osmt->log);
181	return (status);
182}
183
184static ib_api_status_t
185osmt_query_all_ports_vl_arb(IN osmtest_t * const p_osmt, IN FILE * fh)
186{
187	cl_status_t status = CL_SUCCESS;
188	cl_qmap_t *p_tbl;
189	port_t *p_src_port;
190	uint8_t block, anyErr = 0;
191
192	OSM_LOG_ENTER(&p_osmt->log);
193
194	OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE,
195		"Obtaining ALL Ports VL Arbitration Tables\n");
196
197	/*
198	 * Go over all ports that exist in the subnet
199	 * get the relevant VLarbs
200	 */
201
202	p_tbl = &p_osmt->exp_subn.port_key_tbl;
203
204	p_src_port = (port_t *) cl_qmap_head(p_tbl);
205
206	while (p_src_port != (port_t *) cl_qmap_end(p_tbl)) {
207
208		/* HACK we use capability_mask to know diff a CA port from switch port */
209		if (p_src_port->rec.port_info.capability_mask) {
210			/* this is an hca port */
211			for (block = 1; block <= 4; block++) {
212				/*  NOTE to comply we must set port number to 0 and the SA should figure it out */
213				/*  since it is a CA port */
214				status =
215				    osmt_query_vl_arb(p_osmt,
216						      p_src_port->rec.lid, 0,
217						      block, fh);
218				if (status != IB_SUCCESS) {
219					OSM_LOG(&p_osmt->log, OSM_LOG_ERROR,
220						"ERR 0467: "
221						"Failed to get Lid:0x%X Port:0x%X (%s)\n",
222						cl_ntoh16(p_src_port->rec.lid),
223						0, ib_get_err_str(status));
224					anyErr = 1;
225				}
226			}
227		} else {
228			/* this is a switch port */
229			for (block = 1; block <= 4; block++) {
230				status =
231				    osmt_query_vl_arb(p_osmt,
232						      p_src_port->rec.lid,
233						      p_src_port->rec.port_num,
234						      block, fh);
235				if (status != IB_SUCCESS) {
236					OSM_LOG(&p_osmt->log, OSM_LOG_ERROR,
237						"ERR 0468: "
238						"Failed to get Lid:0x%X Port:0x%X (%s)\n",
239						cl_ntoh16(p_src_port->rec.lid),
240						p_src_port->rec.port_num,
241						ib_get_err_str(status));
242					anyErr = 1;
243				}
244			}
245		}
246
247		p_src_port = (port_t *) cl_qmap_next(&p_src_port->map_item);
248	}
249
250	OSM_LOG_EXIT(&p_osmt->log);
251	if (anyErr) {
252		status = IB_ERROR;
253	}
254	return (status);
255}
256
257/*******************************************************************************
258 SLtoVL
259*******************************************************************************/
260static ib_api_status_t
261osmtest_write_slvl_map_table(IN osmtest_t * const p_osmt,
262			     IN FILE * fh,
263			     IN const ib_slvl_table_record_t * const p_rec)
264{
265	int result, i;
266	cl_status_t status = IB_SUCCESS;
267
268	OSM_LOG_ENTER(&p_osmt->log);
269
270	result = fprintf(fh,
271			 "SLtoVL_MAP_TABLE\n"
272			 "lid                     0x%X\n"
273			 "in_port_num             0x%X\n"
274			 "out_port_num            0x%X\n",
275			 cl_ntoh16(p_rec->lid),
276			 p_rec->in_port_num, p_rec->out_port_num);
277
278	fprintf(fh, "SL:");
279	for (i = 0; i < 16; i++)
280		fprintf(fh, "| %-2u  ", i);
281	fprintf(fh, "|\nVL:");
282
283	for (i = 0; i < 16; i++)
284		fprintf(fh, "| 0x%01X ",
285			ib_slvl_table_get(&p_rec->slvl_tbl, (uint8_t) i));
286	fprintf(fh, "|\nEND\n\n");
287
288	/*  Exit: */
289	OSM_LOG_EXIT(&p_osmt->log);
290	return (status);
291}
292
293/**********************************************************************
294 * GET A SINGLE PORT INFO BY NODE LID AND PORT NUMBER
295 **********************************************************************/
296ib_api_status_t
297osmt_query_slvl_map(IN osmtest_t * const p_osmt,
298		    IN ib_net16_t const lid,
299		    IN uint8_t const out_port_num,
300		    IN uint8_t const in_port_num, IN FILE * fh)
301{
302	osmtest_req_context_t context;
303	ib_api_status_t status = IB_SUCCESS;
304	osmv_user_query_t user;
305	osmv_query_req_t req;
306	ib_slvl_table_record_t record, *p_rec;
307
308	OSM_LOG_ENTER(&p_osmt->log);
309
310	OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG,
311		"Getting SLtoVL Map Table for out-port with LID 0x%X Num:0x%X from In-Port:0x%X\n",
312		cl_ntoh16(lid), out_port_num, in_port_num);
313
314	/*
315	 * 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