1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff * Copyright (c) 2007      Simula Research Laboratory. All rights reserved.
6219820Sjeff * Copyright (c) 2007      Silicon Graphics Inc. All rights reserved.
7219820Sjeff *
8219820Sjeff * This software is available to you under a choice of one of two
9219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
10219820Sjeff * General Public License (GPL) Version 2, available from the file
11219820Sjeff * COPYING in the main directory of this source tree, or the
12219820Sjeff * OpenIB.org BSD license below:
13219820Sjeff *
14219820Sjeff *     Redistribution and use in source and binary forms, with or
15219820Sjeff *     without modification, are permitted provided that the following
16219820Sjeff *     conditions are met:
17219820Sjeff *
18219820Sjeff *      - Redistributions of source code must retain the above
19219820Sjeff *        copyright notice, this list of conditions and the following
20219820Sjeff *        disclaimer.
21219820Sjeff *
22219820Sjeff *      - Redistributions in binary form must reproduce the above
23219820Sjeff *        copyright notice, this list of conditions and the following
24219820Sjeff *        disclaimer in the documentation and/or other materials
25219820Sjeff *        provided with the distribution.
26219820Sjeff *
27219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34219820Sjeff * SOFTWARE.
35219820Sjeff *
36219820Sjeff */
37219820Sjeff
38219820Sjeff/*
39219820Sjeff * Abstract:
40219820Sjeff *      Implementation of LASH algorithm Calculation functions
41219820Sjeff */
42219820Sjeff
43219820Sjeff#if HAVE_CONFIG_H
44219820Sjeff#  include <config.h>
45219820Sjeff#endif				/* HAVE_CONFIG_H */
46219820Sjeff
47219820Sjeff#include <stdlib.h>
48219820Sjeff#include <stdio.h>
49219820Sjeff#include <errno.h>
50219820Sjeff#include <complib/cl_debug.h>
51219820Sjeff#include <complib/cl_qmap.h>
52219820Sjeff#include <opensm/osm_switch.h>
53219820Sjeff#include <opensm/osm_opensm.h>
54219820Sjeff#include <opensm/osm_log.h>
55219820Sjeff
56219820Sjeff/* //////////////////////////// */
57219820Sjeff/*  Local types                 */
58219820Sjeff/* //////////////////////////// */
59219820Sjeff
60219820Sjeffenum {
61219820Sjeff	UNQUEUED,
62219820Sjeff	Q_MEMBER,
63219820Sjeff	MST_MEMBER,
64219820Sjeff	MAX_INT = 9999,
65219820Sjeff	NONE = MAX_INT
66219820Sjeff};
67219820Sjeff
68219820Sjefftypedef struct _cdg_vertex {
69219820Sjeff	int num_dependencies;
70219820Sjeff	struct _cdg_vertex **dependency;
71219820Sjeff	int from;
72219820Sjeff	int to;
73219820Sjeff	int seen;
74219820Sjeff	int temp;
75219820Sjeff	int visiting_number;
76219820Sjeff	struct _cdg_vertex *next;
77219820Sjeff	int num_temp_depend;
78219820Sjeff	int num_using_vertex;
79219820Sjeff	int *num_using_this_depend;
80219820Sjeff} cdg_vertex_t;
81219820Sjeff
82219820Sjefftypedef struct _reachable_dest {
83219820Sjeff	int switch_id;
84219820Sjeff	struct _reachable_dest *next;
85219820Sjeff} reachable_dest_t;
86219820Sjeff
87219820Sjefftypedef struct _switch {
88219820Sjeff	osm_switch_t *p_sw;
89219820Sjeff	int *dij_channels;
90219820Sjeff	int id;
91219820Sjeff	int used_channels;
92219820Sjeff	int q_state;
93219820Sjeff	struct routing_table {
94219820Sjeff		unsigned out_link;
95219820Sjeff		unsigned lane;
96219820Sjeff	} *routing_table;
97219820Sjeff	unsigned int num_connections;
98219820Sjeff	int *virtual_physical_port_table;
99219820Sjeff	int *phys_connections;
100219820Sjeff} switch_t;
101219820Sjeff
102219820Sjefftypedef struct _lash {
103219820Sjeff	osm_opensm_t *p_osm;
104219820Sjeff	int num_switches;
105219820Sjeff	uint8_t vl_min;
106219820Sjeff	int balance_limit;
107219820Sjeff	switch_t **switches;
108219820Sjeff	cdg_vertex_t ****cdg_vertex_matrix;
109219820Sjeff	int *num_mst_in_lane;
110219820Sjeff	int ***virtual_location;
111219820Sjeff} lash_t;
112219820Sjeff
113219820Sjeffstatic cdg_vertex_t *create_cdg_vertex(unsigned num_switches)
114219820Sjeff{
115219820Sjeff	cdg_vertex_t *cdg_vertex = (cdg_vertex_t *) malloc(sizeof(cdg_vertex_t));
116219820Sjeff
117219820Sjeff	cdg_vertex->dependency = malloc((num_switches - 1) * sizeof(cdg_vertex_t *));
118219820Sjeff	cdg_vertex->num_using_this_depend = (int *)malloc((num_switches - 1) * sizeof(int));
119219820Sjeff	return cdg_vertex;
120219820Sjeff}
121219820Sjeff
122219820Sjeffstatic void connect_switches(lash_t * p_lash, int sw1, int sw2, int phy_port_1)
123219820Sjeff{
124219820Sjeff	osm_log_t *p_log = &p_lash->p_osm->log;
125219820Sjeff	unsigned num = p_lash->switches[sw1]->num_connections;
126219820Sjeff
127219820Sjeff	p_lash->switches[sw1]->phys_connections[num] = sw2;
128219820Sjeff	p_lash->switches[sw1]->virtual_physical_port_table[num] = phy_port_1;
129219820Sjeff	p_lash->switches[sw1]->num_connections++;
130219820Sjeff
131219820Sjeff	OSM_LOG(p_log, OSM_LOG_VERBOSE,
132219820Sjeff		"LASH connect: %d, %d, %d\n", sw1, sw2,
133219820Sjeff		phy_port_1);
134219820Sjeff
135219820Sjeff}
136219820Sjeff
137219820Sjeffstatic osm_switch_t *get_osm_switch_from_port(osm_port_t * port)
138219820Sjeff{
139219820Sjeff	osm_physp_t *p = port->p_physp;
140219820Sjeff	if (p->p_node->sw)
141219820Sjeff		return p->p_node->sw;
142219820Sjeff	else if (p->p_remote_physp->p_node->sw)
143219820Sjeff		return p->p_remote_physp->p_node->sw;
144219820Sjeff	return NULL;
145219820Sjeff}
146219820Sjeff
147219820Sjeff#if 0
148219820Sjeffstatic int randint(int high)
149219820Sjeff{
150219820Sjeff	int r;
151219820Sjeff
152219820Sjeff	if (high == 0)
153219820Sjeff		return 0;
154219820Sjeff	r = rand();
155219820Sjeff	high++;
156219820Sjeff	return (r % high);
157219820Sjeff}
158219820Sjeff#endif
159219820Sjeff
160219820Sjeffstatic int cycle_exists(cdg_vertex_t * start, cdg_vertex_t * current,
161219820Sjeff			cdg_vertex_t * prev, int visit_num)
162219820Sjeff{
163219820Sjeff	cdg_vertex_t *h;
164219820Sjeff	int i, new_visit_num;
165219820Sjeff	int cycle_found = 0;
166219820Sjeff
167219820Sjeff	if (current != NULL && current->visiting_number > 0) {
168219820Sjeff		if (visit_num > current->visiting_number && current->seen == 0) {
169219820Sjeff			h = start;
170219820Sjeff			cycle_found = 1;
171219820Sjeff		}
172219820Sjeff	} else {
173219820Sjeff		if (current == NULL) {
174219820Sjeff			current = start;
175219820Sjeff			CL_ASSERT(prev == NULL);
176219820Sjeff		}
177219820Sjeff
178219820Sjeff		current->visiting_number = visit_num;
179219820Sjeff
180219820Sjeff		if (prev != NULL) {
181219820Sjeff			prev->next = current;
182219820Sjeff			CL_ASSERT(prev->to == current->from);
183219820Sjeff			CL_ASSERT(prev->visiting_number > 0);
184219820Sjeff		}
185219820Sjeff
186219820Sjeff		new_visit_num = visit_num + 1;
187219820Sjeff
188219820Sjeff		for (i = 0; i < current->num_dependencies; i++) {
189219820Sjeff			cycle_found =
190219820Sjeff			    cycle_exists(start, current->dependency[i], current,
191219820Sjeff					 new_visit_num);
192219820Sjeff			if (cycle_found == 1)
193219820Sjeff				i = current->num_dependencies;
194219820Sjeff		}
195219820Sjeff
196219820Sjeff		current->seen = 1;
197219820Sjeff		if (prev != NULL)
198219820Sjeff			prev->next = NULL;
199219820Sjeff	}
200219820Sjeff
201219820Sjeff	return cycle_found;
202219820Sjeff}
203219820Sjeff
204219820Sjeffstatic void remove_semipermanent_depend_for_sp(lash_t * p_lash, int sw,
205219820Sjeff					       int dest_switch, int lane)
206219820Sjeff{
207219820Sjeff	switch_t **switches = p_lash->switches;
208219820Sjeff	cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix;
209219820Sjeff	int i_next_switch, output_link, i, next_link, i_next_next_switch,
210219820Sjeff	    depend = 0;
211219820Sjeff	cdg_vertex_t *v;
212219820Sjeff	int found;
213219820Sjeff
214219820Sjeff	output_link = switches[sw]->routing_table[dest_switch].out_link;
215219820Sjeff	i_next_switch = switches[sw]->phys_connections[output_link];
216219820Sjeff
217219820Sjeff	while (sw != dest_switch) {
218219820Sjeff		v = cdg_vertex_matrix[lane][sw][i_next_switch];
219219820Sjeff		CL_ASSERT(v != NULL);
220219820Sjeff
221219820Sjeff		if (v->num_using_vertex == 1) {
222219820Sjeff
223219820Sjeff			cdg_vertex_matrix[lane][sw][i_next_switch] = NULL;
224219820Sjeff
225219820Sjeff			free(v);
226219820Sjeff		} else {
227219820Sjeff			v->num_using_vertex--;
228219820Sjeff			if (i_next_switch != dest_switch) {
229219820Sjeff				next_link =
230219820Sjeff				    switches[i_next_switch]->routing_table[dest_switch].out_link;
231219820Sjeff				i_next_next_switch =
232219820Sjeff				    switches[i_next_switch]->phys_connections[next_link];
233219820Sjeff				found = 0;
234219820Sjeff
235219820Sjeff				for (i = 0; i < v->num_dependencies; i++)
236219820Sjeff					if (v->dependency[i] ==
237219820Sjeff					    cdg_vertex_matrix[lane][i_next_switch]
238219820Sjeff					    [i_next_next_switch]) {
239219820Sjeff						found = 1;
240219820Sjeff						depend = i;
241219820Sjeff					}
242219820Sjeff
243219820Sjeff				CL_ASSERT(found);
244219820Sjeff
245219820Sjeff				if (v->num_using_this_depend[depend] == 1) {
246219820Sjeff					for (i = depend;
247219820Sjeff					     i < v->num_dependencies - 1; i++) {
248219820Sjeff						v->dependency[i] =
249219820Sjeff						    v->dependency[i + 1];
250219820Sjeff						v->num_using_this_depend[i] =
251219820Sjeff						    v->num_using_this_depend[i +
252219820Sjeff									     1];
253219820Sjeff					}
254219820Sjeff
255219820Sjeff					v->num_dependencies--;
256219820Sjeff				} else
257219820Sjeff					v->num_using_this_depend[depend]--;
258219820Sjeff			}
259219820Sjeff		}
260219820Sjeff
261219820Sjeff		sw = i_next_switch;
262219820Sjeff		output_link = switches[sw]->routing_table[dest_switch].out_link;
263219820Sjeff
264219820Sjeff		if (sw != dest_switch)
265219820Sjeff			i_next_switch =
266219820Sjeff			    switches[sw]->phys_connections[output_link];
267219820Sjeff	}
268219820Sjeff}
269219820Sjeff
270219820Sjeffinline static void enqueue(cl_list_t * bfsq, switch_t * sw)
271219820Sjeff{
272219820Sjeff	CL_ASSERT(sw->q_state == UNQUEUED);
273219820Sjeff	sw->q_state = Q_MEMBER;
274219820Sjeff	cl_list_insert_tail(bfsq, sw);
275219820Sjeff}
276219820Sjeff
277219820Sjeffinline static void dequeue(cl_list_t * bfsq, switch_t ** sw)
278219820Sjeff{
279219820Sjeff	*sw = (switch_t *) cl_list_remove_head(bfsq);
280219820Sjeff	CL_ASSERT((*sw)->q_state == Q_MEMBER);
281219820Sjeff	(*sw)->q_state = MST_MEMBER;
282219820Sjeff}
283219820Sjeff
284219820Sjeffstatic int get_phys_connection(switch_t *sw, int switch_to)
285219820Sjeff{
286219820Sjeff	unsigned int i = 0;
287219820Sjeff
288219820Sjeff	for (i = 0; i < sw->num_connections; i++)
289219820Sjeff		if (sw->phys_connections[i] == switch_to)
290219820Sjeff			return i;
291219820Sjeff	return i;
292219820Sjeff}
293219820Sjeff
294219820Sjeffstatic void shortest_path(lash_t * p_lash, int ir)
295219820Sjeff{
296219820Sjeff	switch_t **switches = p_lash->switches, *sw, *swi;
297219820Sjeff	unsigned int i;
298219820Sjeff	cl_list_t bfsq;
299219820Sjeff
300219820Sjeff	cl_list_construct(&bfsq);
301219820Sjeff	cl_list_init(&bfsq, 20);
302219820Sjeff
303219820Sjeff	enqueue(&bfsq, switches[ir]);
304219820Sjeff
305219820Sjeff	while (!cl_is_list_empty(&bfsq)) {
306219820Sjeff		dequeue(&bfsq, &sw);
307219820Sjeff		for (i = 0; i < sw->num_connections; i++) {
308219820Sjeff			swi = switches[sw->phys_connections[i]];
309219820Sjeff			if (swi->q_state == UNQUEUED) {
310219820Sjeff				enqueue(&bfsq, swi);
311219820Sjeff				sw->dij_channels[sw->used_channels++] = swi->id;
312219820Sjeff			}
313219820Sjeff		}
314219820Sjeff	}
315219820Sjeff
316219820Sjeff	cl_list_destroy(&bfsq);
317219820Sjeff}
318219820Sjeff
319219820Sjeffstatic void generate_routing_func_for_mst(lash_t * p_lash, int sw_id,
320219820Sjeff					  reachable_dest_t ** destinations)
321219820Sjeff{
322219820Sjeff	int i, next_switch;
323219820Sjeff	switch_t *sw = p_lash->switches[sw_id];
324219820Sjeff	int num_channels = sw->used_channels;
325219820Sjeff	reachable_dest_t *dest, *i_dest, *concat_dest = NULL, *prev;
326219820Sjeff
327219820Sjeff	for (i = 0; i < num_channels; i++) {
328219820Sjeff		next_switch = sw->dij_channels[i];
329219820Sjeff		generate_routing_func_for_mst(p_lash, next_switch, &dest);
330219820Sjeff
331219820Sjeff		i_dest = dest;
332219820Sjeff		prev = i_dest;
333219820Sjeff
334219820Sjeff		while (i_dest != NULL) {
335219820Sjeff			if (sw->routing_table[i_dest->switch_id].out_link ==
336219820Sjeff			    NONE) {
337219820Sjeff				sw->routing_table[i_dest->switch_id].out_link =
338219820Sjeff				    get_phys_connection(sw, next_switch);
339219820Sjeff			}
340219820Sjeff
341219820Sjeff			prev = i_dest;
342219820Sjeff			i_dest = i_dest->next;
343219820Sjeff		}
344219820Sjeff
345219820Sjeff		CL_ASSERT(prev->next == NULL);
346219820Sjeff		prev->next = concat_dest;
347219820Sjeff		concat_dest = dest;
348219820Sjeff	}
349219820Sjeff
350219820Sjeff	i_dest = (reachable_dest_t *) malloc(sizeof(reachable_dest_t));
351219820Sjeff	i_dest->switch_id = sw->id;
352219820Sjeff	i_dest->next = concat_dest;
353219820Sjeff	*destinations = i_dest;
354219820Sjeff}
355219820Sjeff
356219820Sjeffstatic void generate_cdg_for_sp(lash_t * p_lash, int sw, int dest_switch,
357219820Sjeff				int lane)
358219820Sjeff{
359219820Sjeff	unsigned num_switches = p_lash->num_switches;
360219820Sjeff	switch_t **switches = p_lash->switches;
361219820Sjeff	cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix;
362219820Sjeff	int next_switch, output_link, j, exists;
363219820Sjeff	cdg_vertex_t *v, *prev = NULL;
364219820Sjeff
365219820Sjeff	output_link = switches[sw]->routing_table[dest_switch].out_link;
366219820Sjeff	next_switch = switches[sw]->phys_connections[output_link];
367219820Sjeff
368219820Sjeff	while (sw != dest_switch) {
369219820Sjeff
370219820Sjeff		if (cdg_vertex_matrix[lane][sw][next_switch] == NULL) {
371219820Sjeff			unsigned i;
372219820Sjeff			v = create_cdg_vertex(num_switches);
373219820Sjeff
374219820Sjeff			for (i = 0; i < num_switches - 1; i++) {
375219820Sjeff				v->dependency[i] = NULL;
376219820Sjeff				v->num_using_this_depend[i] = 0;
377219820Sjeff			}
378219820Sjeff
379219820Sjeff			v->num_using_vertex = 0;
380219820Sjeff			v->num_dependencies = 0;
381219820Sjeff			v->from = sw;
382219820Sjeff			v->to = next_switch;
383219820Sjeff			v->seen = 0;
384219820Sjeff			v->visiting_number = 0;
385219820Sjeff			v->next = NULL;
386219820Sjeff			v->temp = 1;
387219820Sjeff			v->num_temp_depend = 0;
388219820Sjeff
389219820Sjeff			cdg_vertex_matrix[lane][sw][next_switch] = v;
390219820Sjeff		} else
391219820Sjeff			v = cdg_vertex_matrix[lane][sw][next_switch];
392219820Sjeff
393219820Sjeff		v->num_using_vertex++;
394219820Sjeff
395219820Sjeff		if (prev != NULL) {
396219820Sjeff			exists = 0;
397219820Sjeff
398219820Sjeff			for (j = 0; j < prev->num_dependencies; j++)
399219820Sjeff				if (prev->dependency[j] == v) {
400219820Sjeff					exists = 1;
401219820Sjeff					prev->num_using_this_depend[j]++;
402219820Sjeff				}
403219820Sjeff
404219820Sjeff			if (exists == 0) {
405219820Sjeff				prev->dependency[prev->num_dependencies] = v;
406219820Sjeff				prev->num_using_this_depend[prev->num_dependencies]++;
407219820Sjeff				prev->num_dependencies++;
408219820Sjeff
409219820Sjeff				CL_ASSERT(prev->num_dependencies < (int)num_switches);
410219820Sjeff
411219820Sjeff				if (prev->temp == 0)
412219820Sjeff					prev->num_temp_depend++;
413219820Sjeff
414219820Sjeff			}
415219820Sjeff		}
416219820Sjeff
417219820Sjeff		sw = next_switch;
418219820Sjeff		output_link = switches[sw]->routing_table[dest_switch].out_link;
419219820Sjeff
420219820Sjeff		if (sw != dest_switch) {
421219820Sjeff			CL_ASSERT(output_link != NONE);
422219820Sjeff			next_switch = switches[sw]->phys_connections[output_link];
423219820Sjeff		}
424219820Sjeff
425219820Sjeff		prev = v;
426219820Sjeff	}
427219820Sjeff}
428219820Sjeff
429219820Sjeffstatic void set_temp_depend_to_permanent_for_sp(lash_t * p_lash, int sw,
430219820Sjeff						int dest_switch, int lane)
431219820Sjeff{
432219820Sjeff	switch_t **switches = p_lash->switches;
433219820Sjeff	cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix;
434219820Sjeff	int next_switch, output_link;
435219820Sjeff	cdg_vertex_t *v;
436219820Sjeff
437219820Sjeff	output_link = switches[sw]->routing_table[dest_switch].out_link;
438219820Sjeff	next_switch = switches[sw]->phys_connections[output_link];
439219820Sjeff
440219820Sjeff	while (sw != dest_switch) {
441219820Sjeff		v = cdg_vertex_matrix[lane][sw][next_switch];
442219820Sjeff		CL_ASSERT(v != NULL);
443219820Sjeff
444219820Sjeff		if (v->temp == 1)
445219820Sjeff			v->temp = 0;
446219820Sjeff		else
447219820Sjeff			v->num_temp_depend = 0;
448219820Sjeff
449219820Sjeff		sw = next_switch;
450219820Sjeff		output_link = switches[sw]->routing_table[dest_switch].out_link;
451219820Sjeff
452219820Sjeff		if (sw != dest_switch)
453219820Sjeff			next_switch =
454219820Sjeff			    switches[sw]->phys_connections[output_link];
455219820Sjeff	}
456219820Sjeff
457219820Sjeff}
458219820Sjeff
459219820Sjeffstatic void remove_temp_depend_for_sp(lash_t * p_lash, int sw, int dest_switch,
460219820Sjeff				      int lane)
461219820Sjeff{
462219820Sjeff	switch_t **switches = p_lash->switches;
463219820Sjeff	cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix;
464219820Sjeff	int next_switch, output_link, i;
465219820Sjeff	cdg_vertex_t *v;
466219820Sjeff
467219820Sjeff	output_link = switches[sw]->routing_table[dest_switch].out_link;
468219820Sjeff	next_switch = switches[sw]->phys_connections[output_link];
469219820Sjeff
470219820Sjeff	while (sw != dest_switch) {
471219820Sjeff		v = cdg_vertex_matrix[lane][sw][next_switch];
472219820Sjeff		CL_ASSERT(v != NULL);
473219820Sjeff
474219820Sjeff		if (v->temp == 1) {
475219820Sjeff			cdg_vertex_matrix[lane][sw][next_switch] = NULL;
476219820Sjeff			free(v);
477219820Sjeff		} else {
478219820Sjeff			CL_ASSERT(v->num_temp_depend <= v->num_dependencies);
479219820Sjeff			v->num_dependencies =
480219820Sjeff			    v->num_dependencies - v->num_temp_depend;
481219820Sjeff			v->num_temp_depend = 0;
482219820Sjeff			v->num_using_vertex--;
483219820Sjeff
484219820Sjeff			for (i = v->num_dependencies;
485219820Sjeff			     i < p_lash->num_switches - 1; i++)
486219820Sjeff				v->num_using_this_depend[i] = 0;
487219820Sjeff		}
488219820Sjeff
489219820Sjeff		sw = next_switch;
490219820Sjeff		output_link = switches[sw]->routing_table[dest_switch].out_link;
491219820Sjeff
492219820Sjeff		if (sw != dest_switch)
493219820Sjeff			next_switch =
494219820Sjeff			    switches[sw]->phys_connections[output_link];
495219820Sjeff
496219820Sjeff	}
497219820Sjeff}
498219820Sjeff
499219820Sjeffstatic void balance_virtual_lanes(lash_t * p_lash, unsigned lanes_needed)
500219820Sjeff{
501219820Sjeff	unsigned num_switches = p_lash->num_switches;
502219820Sjeff	cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix;
503219820Sjeff	int *num_mst_in_lane = p_lash->num_mst_in_lane;
504219820Sjeff	int ***virtual_location = p_lash->virtual_location;
505219820Sjeff	int min_filled_lane, max_filled_lane, medium_filled_lane, trials;
506219820Sjeff	int old_min_filled_lane, old_max_filled_lane, new_num_min_lane,
507219820Sjeff	    new_num_max_lane;
508219820Sjeff	unsigned int i, j;
509219820Sjeff	int src, dest, start, next_switch, output_link;
510219820Sjeff	int next_switch2, output_link2;
511219820Sjeff	int stop = 0, cycle_found;
512219820Sjeff	int cycle_found2;
513219820Sjeff
514219820Sjeff	max_filled_lane = 0;
515219820Sjeff	min_filled_lane = lanes_needed - 1;
516219820Sjeff
517219820Sjeff	if (max_filled_lane > 1)
518219820Sjeff		medium_filled_lane = max_filled_lane - 1;
519219820Sjeff
520219820Sjeff	trials = num_mst_in_lane[max_filled_lane];
521219820Sjeff	if (lanes_needed == 1)
522219820Sjeff		stop = 1;
523219820Sjeff
524219820Sjeff	while (stop == 0) {
525219820Sjeff		src = abs(rand()) % (num_switches);
526219820Sjeff		dest = abs(rand()) % (num_switches);
527219820Sjeff
528219820Sjeff		while (virtual_location[src][dest][max_filled_lane] != 1) {
529219820Sjeff			start = dest;
530219820Sjeff			if (dest == num_switches - 1)
531219820Sjeff				dest = 0;
532219820Sjeff			else
533219820Sjeff				dest++;
534219820Sjeff
535219820Sjeff			while (dest != start
536219820Sjeff			       && virtual_location[src][dest][max_filled_lane]
537219820Sjeff			       != 1) {
538219820Sjeff				if (dest == num_switches - 1)
539219820Sjeff					dest = 0;
540219820Sjeff				else
541219820Sjeff					dest++;
542219820Sjeff			}
543219820Sjeff
544219820Sjeff			if (virtual_location[src][dest][max_filled_lane] != 1) {
545219820Sjeff				if (src == num_switches - 1)
546219820Sjeff					src = 0;
547219820Sjeff				else
548219820Sjeff					src++;
549219820Sjeff			}
550219820Sjeff		}
551219820Sjeff
552219820Sjeff		generate_cdg_for_sp(p_lash, src, dest, min_filled_lane);
553219820Sjeff		generate_cdg_for_sp(p_lash, dest, src, min_filled_lane);
554219820Sjeff
555219820Sjeff		output_link = p_lash->switches[src]->routing_table[dest].out_link;
556219820Sjeff		next_switch = p_lash->switches[src]->phys_connections[output_link];
557219820Sjeff
558219820Sjeff		output_link2 = p_lash->switches[dest]->routing_table[src].out_link;
559219820Sjeff		next_switch2 = p_lash->switches[dest]->phys_connections[output_link2];
560219820Sjeff
561219820Sjeff		CL_ASSERT(cdg_vertex_matrix[min_filled_lane][src][next_switch] != NULL);
562219820Sjeff		CL_ASSERT(cdg_vertex_matrix[min_filled_lane][dest][next_switch2] != NULL);
563219820Sjeff
564219820Sjeff		cycle_found =
565219820Sjeff		    cycle_exists(cdg_vertex_matrix[min_filled_lane][src][next_switch], NULL, NULL,
566219820Sjeff				 1);
567219820Sjeff		cycle_found2 =
568219820Sjeff		    cycle_exists(cdg_vertex_matrix[min_filled_lane][dest][next_switch2], NULL, NULL,
569219820Sjeff				 1);
570219820Sjeff
571219820Sjeff		for (i = 0; i < num_switches; i++)
572219820Sjeff			for (j = 0; j < num_switches; j++)
573219820Sjeff				if (cdg_vertex_matrix[min_filled_lane][i][j] != NULL) {
574219820Sjeff					cdg_vertex_matrix[min_filled_lane][i][j]->visiting_number =
575219820Sjeff					    0;
576219820Sjeff					cdg_vertex_matrix[min_filled_lane][i][j]->seen = 0;
577219820Sjeff				}
578219820Sjeff
579219820Sjeff		if (cycle_found == 1 || cycle_found2 == 1) {
580219820Sjeff			remove_temp_depend_for_sp(p_lash, src, dest, min_filled_lane);
581219820Sjeff			remove_temp_depend_for_sp(p_lash, dest, src, min_filled_lane);
582219820Sjeff
583219820Sjeff			virtual_location[src][dest][max_filled_lane] = 2;
584219820Sjeff			virtual_location[dest][src][max_filled_lane] = 2;
585219820Sjeff			trials--;
586219820Sjeff			trials--;
587219820Sjeff		} else {
588219820Sjeff			set_temp_depend_to_permanent_for_sp(p_lash, src, dest, min_filled_lane);
589219820Sjeff			set_temp_depend_to_permanent_for_sp(p_lash, dest, src, min_filled_lane);
590219820Sjeff
591219820Sjeff			num_mst_in_lane[max_filled_lane]--;
592219820Sjeff			num_mst_in_lane[max_filled_lane]--;
593219820Sjeff			num_mst_in_lane[min_filled_lane]++;
594219820Sjeff			num_mst_in_lane[min_filled_lane]++;
595219820Sjeff
596219820Sjeff			remove_semipermanent_depend_for_sp(p_lash, src, dest, max_filled_lane);
597219820Sjeff			remove_semipermanent_depend_for_sp(p_lash, dest, src, max_filled_lane);
598219820Sjeff			virtual_location[src][dest][max_filled_lane] = 0;
599219820Sjeff			virtual_location[dest][src][max_filled_lane] = 0;
600219820Sjeff			virtual_location[src][dest][min_filled_lane] = 1;
601219820Sjeff			virtual_location[dest][src][min_filled_lane] = 1;
602219820Sjeff			p_lash->switches[src]->routing_table[dest].lane = min_filled_lane;
603219820Sjeff			p_lash->switches[dest]->routing_table[src].lane = min_filled_lane;
604219820Sjeff		}
605219820Sjeff
606219820Sjeff		if (trials == 0)
607219820Sjeff			stop = 1;
608219820Sjeff		else {
609219820Sjeff			if (num_mst_in_lane[max_filled_lane] - num_mst_in_lane[min_filled_lane] <
610219820Sjeff			    p_lash->balance_limit)
611219820Sjeff				stop = 1;
612219820Sjeff		}
613219820Sjeff
614219820Sjeff		old_min_filled_lane = min_filled_lane;
615219820Sjeff		old_max_filled_lane = max_filled_lane;
616219820Sjeff
617219820Sjeff		new_num_min_lane = MAX_INT;
618219820Sjeff		new_num_max_lane = 0;
619219820Sjeff
620219820Sjeff		for (i = 0; i < lanes_needed; i++) {
621219820Sjeff
622219820Sjeff			if (num_mst_in_lane[i] < new_num_min_lane) {
623219820Sjeff				new_num_min_lane = num_mst_in_lane[i];
624219820Sjeff				min_filled_lane = i;
625219820Sjeff			}
626219820Sjeff
627219820Sjeff			if (num_mst_in_lane[i] > new_num_max_lane) {
628219820Sjeff				new_num_max_lane = num_mst_in_lane[i];
629219820Sjeff				max_filled_lane = i;
630219820Sjeff			}
631219820Sjeff		}
632219820Sjeff
633219820Sjeff		if (old_min_filled_lane != min_filled_lane) {
634219820Sjeff			trials = num_mst_in_lane[max_filled_lane];
635219820Sjeff			for (i = 0; i < num_switches; i++)
636219820Sjeff				for (j = 0; j < num_switches; j++)
637219820Sjeff					if (virtual_location[i][j][max_filled_lane] == 2)
638219820Sjeff						virtual_location[i][j][max_filled_lane] = 1;
639219820Sjeff		}
640219820Sjeff
641219820Sjeff		if (old_max_filled_lane != max_filled_lane) {
642219820Sjeff			trials = num_mst_in_lane[max_filled_lane];
643219820Sjeff			for (i = 0; i < num_switches; i++)
644219820Sjeff				for (j = 0; j < num_switches; j++)
645219820Sjeff					if (virtual_location[i][j][old_max_filled_lane] == 2)
646219820Sjeff						virtual_location[i][j][old_max_filled_lane] = 1;
647219820Sjeff		}
648219820Sjeff	}
649219820Sjeff}
650219820Sjeff
651219820Sjeffstatic switch_t *switch_create(lash_t * p_lash, unsigned id, osm_switch_t * p_sw)
652219820Sjeff{
653219820Sjeff	unsigned num_switches = p_lash->num_switches;
654219820Sjeff	unsigned num_ports = p_sw->num_ports;
655219820Sjeff	switch_t *sw;
656219820Sjeff	unsigned int i;
657219820Sjeff
658219820Sjeff	sw = malloc(sizeof(*sw));
659219820Sjeff	if (!sw)
660219820Sjeff		return NULL;
661219820Sjeff
662219820Sjeff	memset(sw, 0, sizeof(*sw));
663219820Sjeff
664219820Sjeff	sw->id = id;
665219820Sjeff	sw->dij_channels = malloc(num_ports * sizeof(int));
666219820Sjeff	if (!sw->dij_channels) {
667219820Sjeff		free(sw);
668219820Sjeff		return NULL;
669219820Sjeff	}
670219820Sjeff
671219820Sjeff	sw->virtual_physical_port_table = malloc(num_ports * sizeof(int));
672219820Sjeff	if (!sw->virtual_physical_port_table) {
673219820Sjeff		free(sw->dij_channels);
674219820Sjeff		free(sw);
675219820Sjeff		return NULL;
676219820Sjeff	}
677219820Sjeff
678219820Sjeff	sw->phys_connections = malloc(num_ports * sizeof(int));
679219820Sjeff	if (!sw->phys_connections) {
680219820Sjeff		free(sw->virtual_physical_port_table);
681219820Sjeff		free(sw->dij_channels);
682219820Sjeff		free(sw);
683219820Sjeff		return NULL;
684219820Sjeff	}
685219820Sjeff
686219820Sjeff	sw->routing_table = malloc(num_switches * sizeof(sw->routing_table[0]));
687219820Sjeff	if (!sw->routing_table) {
688219820Sjeff		free(sw->phys_connections);
689219820Sjeff		free(sw->virtual_physical_port_table);
690219820Sjeff		free(sw->dij_channels);
691219820Sjeff		free(sw);
692219820Sjeff		return NULL;
693219820Sjeff	}
694219820Sjeff
695219820Sjeff	for (i = 0; i < num_switches; i++) {
696219820Sjeff		sw->routing_table[i].out_link = NONE;
697219820Sjeff		sw->routing_table[i].lane = NONE;
698219820Sjeff	}
699219820Sjeff
700219820Sjeff	for (i = 0; i < num_ports; i++) {
701219820Sjeff		sw->virtual_physical_port_table[i] = -1;
702219820Sjeff		sw->phys_connections[i] = NONE;
703219820Sjeff	}
704219820Sjeff
705219820Sjeff	sw->p_sw = p_sw;
706219820Sjeff	if (p_sw)
707219820Sjeff		p_sw->priv = sw;
708219820Sjeff
709219820Sjeff	return sw;
710219820Sjeff}
711219820Sjeff
712219820Sjeffstatic void switch_delete(switch_t * sw)
713219820Sjeff{
714219820Sjeff	if (sw->dij_channels)
715219820Sjeff		free(sw->dij_channels);
716219820Sjeff	if (sw->virtual_physical_port_table)
717219820Sjeff		free(sw->virtual_physical_port_table);
718219820Sjeff	if (sw->phys_connections)
719219820Sjeff		free(sw->phys_connections);
720219820Sjeff	if (sw->routing_table)
721219820Sjeff		free(sw->routing_table);
722219820Sjeff	free(sw);
723219820Sjeff}
724219820Sjeff
725219820Sjeffstatic void free_lash_structures(lash_t * p_lash)
726219820Sjeff{
727219820Sjeff	unsigned int i, j, k;
728219820Sjeff	unsigned num_switches = p_lash->num_switches;
729219820Sjeff	osm_log_t *p_log = &p_lash->p_osm->log;
730219820Sjeff
731219820Sjeff	OSM_LOG_ENTER(p_log);
732219820Sjeff
733219820Sjeff	// free cdg_vertex_matrix
734219820Sjeff	for (i = 0; i < p_lash->vl_min; i++) {
735219820Sjeff		for (j = 0; j < num_switches; j++) {
736219820Sjeff			for (k = 0; k < num_switches; k++) {
737219820Sjeff				if (p_lash->cdg_vertex_matrix[i][j][k]) {
738219820Sjeff
739219820Sjeff					if (p_lash->cdg_vertex_matrix[i][j][k]->dependency)
740219820Sjeff						free(p_lash->cdg_vertex_matrix[i][j][k]->
741219820Sjeff						     dependency);
742219820Sjeff
743219820Sjeff					if (p_lash->cdg_vertex_matrix[i][j][k]->
744219820Sjeff					    num_using_this_depend)
745219820Sjeff						free(p_lash->cdg_vertex_matrix[i][j][k]->
746219820Sjeff						     num_using_this_depend);
747219820Sjeff
748219820Sjeff					free(p_lash->cdg_vertex_matrix[i][j][k]);
749219820Sjeff				}
750219820Sjeff			}
751219820Sjeff			if (p_lash->cdg_vertex_matrix[i][j])
752219820Sjeff				free(p_lash->cdg_vertex_matrix[i][j]);
753219820Sjeff		}
754219820Sjeff		if (p_lash->cdg_vertex_matrix[i])
755219820Sjeff			free(p_lash->cdg_vertex_matrix[i]);
756219820Sjeff	}
757219820Sjeff
758219820Sjeff	if (p_lash->cdg_vertex_matrix)
759219820Sjeff		free(p_lash->cdg_vertex_matrix);
760219820Sjeff
761219820Sjeff	// free virtual_location
762219820Sjeff	for (i = 0; i < num_switches; i++) {
763219820Sjeff		for (j = 0; j < num_switches; j++) {
764219820Sjeff			if (p_lash->virtual_location[i][j])
765219820Sjeff				free(p_lash->virtual_location[i][j]);
766219820Sjeff		}
767219820Sjeff		if (p_lash->virtual_location[i])
768219820Sjeff			free(p_lash->virtual_location[i]);
769219820Sjeff	}
770219820Sjeff	if (p_lash->virtual_location)
771219820Sjeff		free(p_lash->virtual_location);
772219820Sjeff
773219820Sjeff	if (p_lash->num_mst_in_lane)
774219820Sjeff		free(p_lash->num_mst_in_lane);
775219820Sjeff
776219820Sjeff	OSM_LOG_EXIT(p_log);
777219820Sjeff}
778219820Sjeff
779219820Sjeffstatic int init_lash_structures(lash_t * p_lash)
780219820Sjeff{
781219820Sjeff	unsigned vl_min = p_lash->vl_min;
782219820Sjeff	unsigned num_switches = p_lash->num_switches;
783219820Sjeff	osm_log_t *p_log = &p_lash->p_osm->log;
784219820Sjeff	int status = 0;
785219820Sjeff	unsigned int i, j, k;
786219820Sjeff
787219820Sjeff	OSM_LOG_ENTER(p_log);
788219820Sjeff
789219820Sjeff	// initialise cdg_vertex_matrix[num_switches][num_switches][num_switches]
790219820Sjeff	p_lash->cdg_vertex_matrix =
791219820Sjeff	    (cdg_vertex_t ****) malloc(vl_min * sizeof(cdg_vertex_t ****));
792219820Sjeff	for (i = 0; i < vl_min; i++) {
793219820Sjeff		p_lash->cdg_vertex_matrix[i] =
794219820Sjeff		    (cdg_vertex_t ***) malloc(num_switches *
795219820Sjeff					      sizeof(cdg_vertex_t ***));
796219820Sjeff
797219820Sjeff		if (p_lash->cdg_vertex_matrix[i] == NULL)
798219820Sjeff			goto Exit_Mem_Error;
799219820Sjeff	}
800219820Sjeff
801219820Sjeff	for (i = 0; i < vl_min; i++) {
802219820Sjeff		for (j = 0; j < num_switches; j++) {
803219820Sjeff			p_lash->cdg_vertex_matrix[i][j] =
804219820Sjeff			    (cdg_vertex_t **) malloc(num_switches *
805219820Sjeff						     sizeof(cdg_vertex_t **));
806219820Sjeff			if (p_lash->cdg_vertex_matrix[i][j] == NULL)
807219820Sjeff				goto Exit_Mem_Error;
808219820Sjeff
809219820Sjeff			for (k = 0; k < num_switches; k++) {
810219820Sjeff				p_lash->cdg_vertex_matrix[i][j][k] = NULL;
811219820Sjeff			}
812219820Sjeff		}
813219820Sjeff	}
814219820Sjeff
815219820Sjeff	// initialise virtual_location[num_switches][num_switches][num_layers],
816219820Sjeff	// default value = 0
817219820Sjeff	p_lash->virtual_location =
818219820Sjeff	    (int ***)malloc(num_switches * sizeof(int ***));
819219820Sjeff	if (p_lash->virtual_location == NULL)
820219820Sjeff		goto Exit_Mem_Error;
821219820Sjeff
822219820Sjeff	for (i = 0; i < num_switches; i++) {
823219820Sjeff		p_lash->virtual_location[i] =
824219820Sjeff		    (int **)malloc(num_switches * sizeof(int **));
825219820Sjeff		if (p_lash->virtual_location[i] == NULL)
826219820Sjeff			goto Exit_Mem_Error;
827219820Sjeff	}
828219820Sjeff
829219820Sjeff	for (i = 0; i < num_switches; i++) {
830219820Sjeff		for (j = 0; j < num_switches; j++) {
831219820Sjeff			p_lash->virtual_location[i][j] =
832219820Sjeff			    (int *)malloc(vl_min * sizeof(int *));
833219820Sjeff			if (p_lash->virtual_location[i][j] == NULL)
834219820Sjeff				goto Exit_Mem_Error;
835219820Sjeff			for (k = 0; k < vl_min; k++) {
836219820Sjeff				p_lash->virtual_location[i][j][k] = 0;
837219820Sjeff			}
838219820Sjeff		}
839219820Sjeff	}
840219820Sjeff
841219820Sjeff	// initialise num_mst_in_lane[num_switches], default 0
842219820Sjeff	p_lash->num_mst_in_lane = (int *)malloc(num_switches * sizeof(int));
843219820Sjeff	if (p_lash->num_mst_in_lane == NULL)
844219820Sjeff		goto Exit_Mem_Error;
845219820Sjeff	memset(p_lash->num_mst_in_lane, 0,
846219820Sjeff	       num_switches * sizeof(p_lash->num_mst_in_lane[0]));
847219820Sjeff
848219820Sjeff	goto Exit;
849219820Sjeff
850219820SjeffExit_Mem_Error:
851219820Sjeff	status = -1;
852219820Sjeff	OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D01: "
853219820Sjeff		"Could not allocate required memory for LASH errno %d, errno %d for lack of memory\n",
854219820Sjeff		errno, ENOMEM);
855219820Sjeff
856219820SjeffExit:
857219820Sjeff	OSM_LOG_EXIT(p_log);
858219820Sjeff	return status;
859219820Sjeff}
860219820Sjeff
861219820Sjeffstatic int lash_core(lash_t * p_lash)
862219820Sjeff{
863219820Sjeff	osm_log_t *p_log = &p_lash->p_osm->log;
864219820Sjeff	unsigned num_switches = p_lash->num_switches;
865219820Sjeff	switch_t **switches = p_lash->switches;
866219820Sjeff	unsigned lanes_needed = 1;
867219820Sjeff	unsigned int i, j, k, dest_switch = 0;
868219820Sjeff	reachable_dest_t *dests, *idest;
869219820Sjeff	int cycle_found = 0;
870219820Sjeff	unsigned v_lane;
871219820Sjeff	int stop = 0, output_link, i_next_switch;
872219820Sjeff	int output_link2, i_next_switch2;
873219820Sjeff	int cycle_found2 = 0;
874219820Sjeff	int status = 0;
875219820Sjeff	int *switch_bitmap;	/* Bitmap to check if we have processed this pair */
876219820Sjeff
877219820Sjeff	OSM_LOG_ENTER(p_log);
878219820Sjeff
879219820Sjeff	for (i = 0; i < num_switches; i++) {
880219820Sjeff
881219820Sjeff		shortest_path(p_lash, i);
882219820Sjeff		generate_routing_func_for_mst(p_lash, i, &dests);
883219820Sjeff
884219820Sjeff		idest = dests;
885219820Sjeff		while (idest != NULL) {
886219820Sjeff			dests = dests->next;
887219820Sjeff			free(idest);
888219820Sjeff			idest = dests;
889219820Sjeff		}
890219820Sjeff
891219820Sjeff		for (j = 0; j < num_switches; j++) {
892219820Sjeff			switches[j]->used_channels = 0;
893219820Sjeff			switches[j]->q_state = UNQUEUED;
894219820Sjeff		}
895219820Sjeff	}
896219820Sjeff
897219820Sjeff	switch_bitmap = malloc(num_switches * num_switches * sizeof(int));
898219820Sjeff	if (!switch_bitmap) {
899219820Sjeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D04: "
900219820Sjeff			"Failed allocating switch_bitmap - out of memory\n");
901219820Sjeff		goto Exit;
902219820Sjeff	}
903219820Sjeff	memset(switch_bitmap, 0, num_switches * num_switches * sizeof(int));
904219820Sjeff
905219820Sjeff	for (i = 0; i < num_switches; i++) {
906219820Sjeff		for (dest_switch = 0; dest_switch < num_switches; dest_switch++)
907219820Sjeff			if (dest_switch != i && switch_bitmap[i * num_switches + dest_switch] == 0) {
908219820Sjeff				v_lane = 0;
909219820Sjeff				stop = 0;
910219820Sjeff				while (v_lane < lanes_needed && stop == 0) {
911219820Sjeff					generate_cdg_for_sp(p_lash, i, dest_switch, v_lane);
912219820Sjeff					generate_cdg_for_sp(p_lash, dest_switch, i, v_lane);
913219820Sjeff
914219820Sjeff					output_link =
915219820Sjeff					    switches[i]->routing_table[dest_switch].out_link;
916219820Sjeff					output_link2 =
917219820Sjeff					    switches[dest_switch]->routing_table[i].out_link;
918219820Sjeff
919219820Sjeff					i_next_switch = switches[i]->phys_connections[output_link];
920219820Sjeff					i_next_switch2 =
921219820Sjeff					    switches[dest_switch]->phys_connections[output_link2];
922219820Sjeff
923219820Sjeff					CL_ASSERT(p_lash->
924219820Sjeff						  cdg_vertex_matrix[v_lane][i][i_next_switch] !=
925219820Sjeff						  NULL);
926219820Sjeff					CL_ASSERT(p_lash->
927219820Sjeff						  cdg_vertex_matrix[v_lane][dest_switch]
928219820Sjeff						  [i_next_switch2] != NULL);
929219820Sjeff
930219820Sjeff					cycle_found =
931219820Sjeff					    cycle_exists(p_lash->
932219820Sjeff							 cdg_vertex_matrix[v_lane][i]
933219820Sjeff							 [i_next_switch], NULL, NULL, 1);
934219820Sjeff					cycle_found2 =
935219820Sjeff					    cycle_exists(p_lash->
936219820Sjeff							 cdg_vertex_matrix[v_lane][dest_switch]
937219820Sjeff							 [i_next_switch2], NULL, NULL, 1);
938219820Sjeff
939219820Sjeff					for (j = 0; j < num_switches; j++)
940219820Sjeff						for (k = 0; k < num_switches; k++)
941219820Sjeff							if (p_lash->
942219820Sjeff							    cdg_vertex_matrix[v_lane][j][k] !=
943219820Sjeff							    NULL) {
944219820Sjeff								p_lash->
945219820Sjeff								    cdg_vertex_matrix[v_lane][j]
946219820Sjeff								    [k]->visiting_number = 0;
947219820Sjeff								p_lash->
948219820Sjeff								    cdg_vertex_matrix[v_lane][j]
949219820Sjeff								    [k]->seen = 0;
950219820Sjeff							}
951219820Sjeff
952219820Sjeff					if (cycle_found == 1 || cycle_found2 == 1) {
953219820Sjeff						remove_temp_depend_for_sp(p_lash, i, dest_switch,
954219820Sjeff									  v_lane);
955219820Sjeff						remove_temp_depend_for_sp(p_lash, dest_switch, i,
956219820Sjeff									  v_lane);
957219820Sjeff						v_lane++;
958219820Sjeff					} else {
959219820Sjeff						set_temp_depend_to_permanent_for_sp(p_lash, i,
960219820Sjeff										    dest_switch,
961219820Sjeff										    v_lane);
962219820Sjeff						set_temp_depend_to_permanent_for_sp(p_lash,
963219820Sjeff										    dest_switch, i,
964219820Sjeff										    v_lane);
965219820Sjeff						stop = 1;
966219820Sjeff						p_lash->num_mst_in_lane[v_lane]++;
967219820Sjeff						p_lash->num_mst_in_lane[v_lane]++;
968219820Sjeff					}
969219820Sjeff				}
970219820Sjeff
971219820Sjeff				switches[i]->routing_table[dest_switch].lane = v_lane;
972219820Sjeff				switches[dest_switch]->routing_table[i].lane = v_lane;
973219820Sjeff
974219820Sjeff				if (cycle_found == 1 || cycle_found2 == 1) {
975219820Sjeff					if (++lanes_needed > p_lash->vl_min)
976219820Sjeff						goto Error_Not_Enough_Lanes;
977219820Sjeff
978219820Sjeff					generate_cdg_for_sp(p_lash, i, dest_switch, v_lane);
979219820Sjeff					generate_cdg_for_sp(p_lash, dest_switch, i, v_lane);
980219820Sjeff
981219820Sjeff					set_temp_depend_to_permanent_for_sp(p_lash, i, dest_switch,
982219820Sjeff									    v_lane);
983219820Sjeff					set_temp_depend_to_permanent_for_sp(p_lash, dest_switch, i,
984219820Sjeff									    v_lane);
985219820Sjeff
986219820Sjeff					p_lash->num_mst_in_lane[v_lane]++;
987219820Sjeff					p_lash->num_mst_in_lane[v_lane]++;
988219820Sjeff				}
989219820Sjeff				p_lash->virtual_location[i][dest_switch][v_lane] = 1;
990219820Sjeff				p_lash->virtual_location[dest_switch][i][v_lane] = 1;
991219820Sjeff
992219820Sjeff				switch_bitmap[i * num_switches + dest_switch] = 1;
993219820Sjeff				switch_bitmap[dest_switch * num_switches + i] = 1;
994219820Sjeff			}
995219820Sjeff	}
996219820Sjeff
997219820Sjeff	OSM_LOG(p_log, OSM_LOG_INFO,
998219820Sjeff		"Lanes needed: %d, Balancing\n", lanes_needed);
999219820Sjeff
1000219820Sjeff	for (i = 0; i < lanes_needed; i++) {
1001219820Sjeff		OSM_LOG(p_log, OSM_LOG_INFO, "Lanes in layer %d: %d\n",
1002219820Sjeff			i, p_lash->num_mst_in_lane[i]);
1003219820Sjeff	}
1004219820Sjeff
1005219820Sjeff	balance_virtual_lanes(p_lash, lanes_needed);
1006219820Sjeff
1007219820Sjeff	for (i = 0; i < lanes_needed; i++) {
1008219820Sjeff		OSM_LOG(p_log, OSM_LOG_INFO, "Lanes in layer %d: %d\n",
1009219820Sjeff			i, p_lash->num_mst_in_lane[i]);
1010219820Sjeff	}
1011219820Sjeff
1012219820Sjeff	goto Exit;
1013219820Sjeff
1014219820SjeffError_Not_Enough_Lanes:
1015219820Sjeff	status = -1;
1016219820Sjeff	OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D02: "
1017219820Sjeff		"Lane requirements (%d) exceed available lanes (%d)\n",
1018219820Sjeff		p_lash->vl_min, lanes_needed);
1019219820SjeffExit:
1020219820Sjeff	if (switch_bitmap)
1021219820Sjeff		free(switch_bitmap);
1022219820Sjeff	OSM_LOG_EXIT(p_log);
1023219820Sjeff	return status;
1024219820Sjeff}
1025219820Sjeff
1026219820Sjeffstatic unsigned get_lash_id(osm_switch_t * p_sw)
1027219820Sjeff{
1028219820Sjeff	return ((switch_t *) p_sw->priv)->id;
1029219820Sjeff}
1030219820Sjeff
1031219820Sjeffstatic void populate_fwd_tbls(lash_t * p_lash)
1032219820Sjeff{
1033219820Sjeff	osm_log_t *p_log = &p_lash->p_osm->log;
1034219820Sjeff	osm_subn_t *p_subn = &p_lash->p_osm->subn;
1035219820Sjeff	osm_opensm_t *p_osm = p_lash->p_osm;
1036219820Sjeff	osm_switch_t *p_sw, *p_next_sw, *p_dst_sw;
1037219820Sjeff	osm_port_t *port;
1038219820Sjeff	uint16_t max_lid_ho, lid;
1039219820Sjeff
1040219820Sjeff	OSM_LOG_ENTER(p_log);
1041219820Sjeff
1042219820Sjeff	p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
1043219820Sjeff
1044219820Sjeff	// Go through each swtich individually
1045219820Sjeff	while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) {
1046219820Sjeff		uint64_t current_guid;
1047219820Sjeff		switch_t *sw;
1048219820Sjeff		p_sw = p_next_sw;
1049219820Sjeff		p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item);
1050219820Sjeff
1051219820Sjeff		max_lid_ho = p_sw->max_lid_ho;
1052219820Sjeff		current_guid = p_sw->p_node->node_info.port_guid;
1053219820Sjeff		sw = p_sw->priv;
1054219820Sjeff
1055219820Sjeff		memset(p_sw->new_lft, OSM_NO_PATH, IB_LID_UCAST_END_HO + 1);
1056219820Sjeff
1057219820Sjeff		for (lid = 1; lid <= max_lid_ho; lid++) {
1058219820Sjeff			port = cl_ptr_vector_get(&p_subn->port_lid_tbl, lid);
1059219820Sjeff			if (!port)
1060219820Sjeff				continue;
1061219820Sjeff
1062219820Sjeff			p_dst_sw = get_osm_switch_from_port(port);
1063219820Sjeff			if (p_dst_sw == p_sw) {
1064219820Sjeff				uint8_t egress_port = port->p_node->sw ? 0 :
1065219820Sjeff					port->p_physp->p_remote_physp->port_num;
1066219820Sjeff				p_sw->new_lft[lid] = egress_port;
1067219820Sjeff				OSM_LOG(p_log, OSM_LOG_VERBOSE,
1068219820Sjeff					"LASH fwd MY SRC SRC GUID 0x%016" PRIx64
1069219820Sjeff					" src lash id (%d), src lid no (%u) src lash port (%d) "
1070219820Sjeff					"DST GUID 0x%016" PRIx64
1071219820Sjeff					" src lash id (%d), src lash port (%d)\n",
1072219820Sjeff					cl_ntoh64(current_guid), -1, lid,
1073219820Sjeff					egress_port, cl_ntoh64(current_guid),
1074219820Sjeff					-1, egress_port);
1075219820Sjeff			} else if (p_dst_sw) {
1076219820Sjeff				unsigned dst_lash_switch_id =
1077219820Sjeff				    get_lash_id(p_dst_sw);
1078219820Sjeff				uint8_t lash_egress_port =
1079219820Sjeff				    (uint8_t) sw->
1080219820Sjeff				    routing_table[dst_lash_switch_id].out_link;
1081219820Sjeff				uint8_t physical_egress_port =
1082219820Sjeff				    (uint8_t) sw->
1083219820Sjeff				    virtual_physical_port_table
1084219820Sjeff				    [lash_egress_port];
1085219820Sjeff
1086219820Sjeff				p_sw->new_lft[lid] = physical_egress_port;
1087219820Sjeff				OSM_LOG(p_log, OSM_LOG_VERBOSE,
1088219820Sjeff					"LASH fwd SRC GUID 0x%016" PRIx64
1089219820Sjeff					" src lash id (%d), "
1090219820Sjeff					"src lid no (%u) src lash port (%d) "
1091219820Sjeff					"DST GUID 0x%016" PRIx64
1092219820Sjeff					" src lash id (%d), src lash port (%d)\n",
1093219820Sjeff					cl_ntoh64(current_guid), sw->id, lid,
1094219820Sjeff					lash_egress_port,
1095219820Sjeff					cl_ntoh64(p_dst_sw->p_node->node_info.
1096219820Sjeff						  port_guid),
1097219820Sjeff					dst_lash_switch_id,
1098219820Sjeff					physical_egress_port);
1099219820Sjeff			}
1100219820Sjeff		}		// for
1101219820Sjeff		osm_ucast_mgr_set_fwd_table(&p_osm->sm.ucast_mgr, p_sw);
1102219820Sjeff	}
1103219820Sjeff	OSM_LOG_EXIT(p_log);
1104219820Sjeff}
1105219820Sjeff
1106219820Sjeffstatic void osm_lash_process_switch(lash_t * p_lash, osm_switch_t * p_sw)
1107219820Sjeff{
1108219820Sjeff	osm_log_t *p_log = &p_lash->p_osm->log;
1109219820Sjeff	int i, port_count;
1110219820Sjeff	osm_physp_t *p_current_physp, *p_remote_physp;
1111219820Sjeff	unsigned switch_a_lash_id, switch_b_lash_id;
1112219820Sjeff
1113219820Sjeff	OSM_LOG_ENTER(p_log);
1114219820Sjeff
1115219820Sjeff	switch_a_lash_id = get_lash_id(p_sw);
1116219820Sjeff	port_count = osm_node_get_num_physp(p_sw->p_node);
1117219820Sjeff
1118219820Sjeff	// starting at port 1, ignoring management port on switch
1119219820Sjeff	for (i = 1; i < port_count; i++) {
1120219820Sjeff
1121219820Sjeff		p_current_physp = osm_node_get_physp_ptr(p_sw->p_node, i);
1122219820Sjeff		if (p_current_physp) {
1123219820Sjeff			p_remote_physp = p_current_physp->p_remote_physp;
1124219820Sjeff			if (p_remote_physp && p_remote_physp->p_node->sw) {
1125219820Sjeff				int physical_port_a_num =
1126219820Sjeff				    osm_physp_get_port_num(p_current_physp);
1127219820Sjeff				int physical_port_b_num =
1128219820Sjeff				    osm_physp_get_port_num(p_remote_physp);
1129219820Sjeff				switch_b_lash_id =
1130219820Sjeff				    get_lash_id(p_remote_physp->p_node->sw);
1131219820Sjeff
1132219820Sjeff				connect_switches(p_lash, switch_a_lash_id,
1133219820Sjeff						 switch_b_lash_id,
1134219820Sjeff						 physical_port_a_num);
1135219820Sjeff				OSM_LOG(p_log, OSM_LOG_VERBOSE,
1136219820Sjeff					"LASH SUCCESS connected G 0x%016" PRIx64
1137219820Sjeff					" , lash_id(%u), P(%u) " " to G 0x%016"
1138219820Sjeff					PRIx64 " , lash_id(%u) , P(%u)\n",
1139219820Sjeff					cl_ntoh64(osm_physp_get_port_guid
1140219820Sjeff						  (p_current_physp)),
1141219820Sjeff					switch_a_lash_id, physical_port_a_num,
1142219820Sjeff					cl_ntoh64(osm_physp_get_port_guid
1143219820Sjeff						  (p_remote_physp)),
1144219820Sjeff					switch_b_lash_id, physical_port_b_num);
1145219820Sjeff			}
1146219820Sjeff		}
1147219820Sjeff	}
1148219820Sjeff
1149219820Sjeff	OSM_LOG_EXIT(p_log);
1150219820Sjeff}
1151219820Sjeff
1152219820Sjeffstatic void lash_cleanup(lash_t * p_lash)
1153219820Sjeff{
1154219820Sjeff	osm_subn_t *p_subn = &p_lash->p_osm->subn;
1155219820Sjeff	osm_switch_t *p_next_sw, *p_sw;
1156219820Sjeff
1157219820Sjeff	/* drop any existing references to old lash switches */
1158219820Sjeff	p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
1159219820Sjeff	while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) {
1160219820Sjeff		p_sw = p_next_sw;
1161219820Sjeff		p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item);
1162219820Sjeff		p_sw->priv = NULL;
1163219820Sjeff	}
1164219820Sjeff
1165219820Sjeff	if (p_lash->switches) {
1166219820Sjeff		unsigned id;
1167219820Sjeff		for (id = 0; ((int)id) < p_lash->num_switches; id++)
1168219820Sjeff			if (p_lash->switches[id])
1169219820Sjeff				switch_delete(p_lash->switches[id]);
1170219820Sjeff		free(p_lash->switches);
1171219820Sjeff	}
1172219820Sjeff	p_lash->switches = NULL;
1173219820Sjeff}
1174219820Sjeff
1175219820Sjeff/*
1176219820Sjeff  static int  discover_network_properties()
1177219820Sjeff  Traverse the topology of the network in order to determine
1178219820Sjeff   - the maximum number of switches,
1179219820Sjeff   - the minimum number of virtual layers
1180219820Sjeff*/
1181219820Sjeff
1182219820Sjeffstatic int discover_network_properties(lash_t * p_lash)
1183219820Sjeff{
1184219820Sjeff	int i = 0, id = 0;
1185219820Sjeff	uint8_t vl_min;
1186219820Sjeff	osm_subn_t *p_subn = &p_lash->p_osm->subn;
1187219820Sjeff	osm_switch_t *p_next_sw, *p_sw;
1188219820Sjeff	osm_log_t *p_log = &p_lash->p_osm->log;
1189219820Sjeff
1190219820Sjeff	p_lash->num_switches = cl_qmap_count(&p_subn->sw_guid_tbl);
1191219820Sjeff
1192219820Sjeff	p_lash->switches = malloc(p_lash->num_switches * sizeof(switch_t *));
1193219820Sjeff	if (!p_lash->switches)
1194219820Sjeff		return -1;
1195219820Sjeff	memset(p_lash->switches, 0, p_lash->num_switches * sizeof(switch_t *));
1196219820Sjeff
1197219820Sjeff	vl_min = 5;		// set to a high value
1198219820Sjeff
1199219820Sjeff	p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
1200219820Sjeff	while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) {
1201219820Sjeff		uint16_t port_count;
1202219820Sjeff		p_sw = p_next_sw;
1203219820Sjeff		p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item);
1204219820Sjeff
1205219820Sjeff		p_lash->switches[id] = switch_create(p_lash, id, p_sw);
1206219820Sjeff		if (!p_lash->switches[id])
1207219820Sjeff			return -1;
1208219820Sjeff		id++;
1209219820Sjeff
1210219820Sjeff		port_count = osm_node_get_num_physp(p_sw->p_node);
1211219820Sjeff
1212219820Sjeff		// Note, ignoring port 0. management port
1213219820Sjeff		for (i = 1; i < port_count; i++) {
1214219820Sjeff			osm_physp_t *p_current_physp =
1215219820Sjeff			    osm_node_get_physp_ptr(p_sw->p_node, i);
1216219820Sjeff
1217219820Sjeff			if (p_current_physp
1218219820Sjeff			    && p_current_physp->p_remote_physp) {
1219219820Sjeff
1220219820Sjeff				ib_port_info_t *p_port_info =
1221219820Sjeff				    &p_current_physp->port_info;
1222219820Sjeff				uint8_t port_vl_min =
1223219820Sjeff				    ib_port_info_get_op_vls(p_port_info);
1224219820Sjeff				if (port_vl_min && port_vl_min < vl_min)
1225219820Sjeff					vl_min = port_vl_min;
1226219820Sjeff			}
1227219820Sjeff		}		// for
1228219820Sjeff	}			// while
1229219820Sjeff
1230219820Sjeff	vl_min = 1 << (vl_min - 1);
1231219820Sjeff	if (vl_min > 15)
1232219820Sjeff		vl_min = 15;
1233219820Sjeff
1234219820Sjeff	p_lash->vl_min = vl_min;
1235219820Sjeff
1236219820Sjeff	OSM_LOG(p_log, OSM_LOG_INFO,
1237219820Sjeff		"min operational vl(%d) max_switches(%d)\n", p_lash->vl_min,
1238219820Sjeff		p_lash->num_switches);
1239219820Sjeff	return 0;
1240219820Sjeff}
1241219820Sjeff
1242219820Sjeffstatic void process_switches(lash_t * p_lash)
1243219820Sjeff{
1244219820Sjeff	osm_switch_t *p_sw, *p_next_sw;
1245219820Sjeff	osm_subn_t *p_subn = &p_lash->p_osm->subn;
1246219820Sjeff
1247219820Sjeff	/* Go through each swithc and process it. i.e build the connection
1248219820Sjeff	   structure required by LASH */
1249219820Sjeff	p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
1250219820Sjeff	while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) {
1251219820Sjeff		p_sw = p_next_sw;
1252219820Sjeff		p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item);
1253219820Sjeff
1254219820Sjeff		osm_lash_process_switch(p_lash, p_sw);
1255219820Sjeff	}
1256219820Sjeff}
1257219820Sjeff
1258219820Sjeffstatic int lash_process(void *context)
1259219820Sjeff{
1260219820Sjeff	lash_t *p_lash = context;
1261219820Sjeff	osm_log_t *p_log = &p_lash->p_osm->log;
1262219820Sjeff	int return_status = IB_SUCCESS;
1263219820Sjeff
1264219820Sjeff	OSM_LOG_ENTER(p_log);
1265219820Sjeff
1266219820Sjeff	p_lash->balance_limit = 6;
1267219820Sjeff
1268219820Sjeff	// everything starts here
1269219820Sjeff	lash_cleanup(p_lash);
1270219820Sjeff
1271219820Sjeff	discover_network_properties(p_lash);
1272219820Sjeff
1273219820Sjeff	return_status = init_lash_structures(p_lash);
1274219820Sjeff	if (return_status != IB_SUCCESS)
1275219820Sjeff		goto Exit;
1276219820Sjeff
1277219820Sjeff	process_switches(p_lash);
1278219820Sjeff
1279219820Sjeff	return_status = lash_core(p_lash);
1280219820Sjeff	if (return_status != IB_SUCCESS)
1281219820Sjeff		goto Exit;
1282219820Sjeff
1283219820Sjeff	populate_fwd_tbls(p_lash);
1284219820Sjeff
1285219820SjeffExit:
1286219820Sjeff	free_lash_structures(p_lash);
1287219820Sjeff	OSM_LOG_EXIT(p_log);
1288219820Sjeff
1289219820Sjeff	return return_status;
1290219820Sjeff}
1291219820Sjeff
1292219820Sjeffstatic lash_t *lash_create(osm_opensm_t * p_osm)
1293219820Sjeff{
1294219820Sjeff	lash_t *p_lash;
1295219820Sjeff
1296219820Sjeff	p_lash = malloc(sizeof(lash_t));
1297219820Sjeff	if (!p_lash)
1298219820Sjeff		return NULL;
1299219820Sjeff
1300219820Sjeff	memset(p_lash, 0, sizeof(lash_t));
1301219820Sjeff	p_lash->p_osm = p_osm;
1302219820Sjeff
1303219820Sjeff	return (p_lash);
1304219820Sjeff}
1305219820Sjeff
1306219820Sjeffstatic void lash_delete(void *context)
1307219820Sjeff{
1308219820Sjeff	lash_t *p_lash = context;
1309219820Sjeff	if (p_lash->switches) {
1310219820Sjeff		unsigned id;
1311219820Sjeff		for (id = 0; ((int)id) < p_lash->num_switches; id++)
1312219820Sjeff			if (p_lash->switches[id])
1313219820Sjeff				switch_delete(p_lash->switches[id]);
1314219820Sjeff		free(p_lash->switches);
1315219820Sjeff	}
1316219820Sjeff	free(p_lash);
1317219820Sjeff}
1318219820Sjeff
1319219820Sjeffuint8_t osm_get_lash_sl(osm_opensm_t * p_osm, osm_port_t * p_src_port,
1320219820Sjeff			osm_port_t * p_dst_port)
1321219820Sjeff{
1322219820Sjeff	unsigned dst_id;
1323219820Sjeff	unsigned src_id;
1324219820Sjeff	osm_switch_t *p_sw;
1325219820Sjeff
1326219820Sjeff	if (p_osm->routing_engine_used != OSM_ROUTING_ENGINE_TYPE_LASH)
1327219820Sjeff		return OSM_DEFAULT_SL;
1328219820Sjeff
1329219820Sjeff	p_sw = get_osm_switch_from_port(p_dst_port);
1330219820Sjeff	if (!p_sw || !p_sw->priv)
1331219820Sjeff		return OSM_DEFAULT_SL;
1332219820Sjeff	dst_id = get_lash_id(p_sw);
1333219820Sjeff
1334219820Sjeff	p_sw = get_osm_switch_from_port(p_src_port);
1335219820Sjeff	if (!p_sw || !p_sw->priv)
1336219820Sjeff		return OSM_DEFAULT_SL;
1337219820Sjeff
1338219820Sjeff	src_id = get_lash_id(p_sw);
1339219820Sjeff	if (src_id == dst_id)
1340219820Sjeff		return OSM_DEFAULT_SL;
1341219820Sjeff
1342219820Sjeff	return (uint8_t) ((switch_t *) p_sw->priv)->routing_table[dst_id].lane;
1343219820Sjeff}
1344219820Sjeff
1345219820Sjeffint osm_ucast_lash_setup(struct osm_routing_engine *r, osm_opensm_t *p_osm)
1346219820Sjeff{
1347219820Sjeff	lash_t *p_lash = lash_create(p_osm);
1348219820Sjeff	if (!p_lash)
1349219820Sjeff		return -1;
1350219820Sjeff
1351219820Sjeff	r->context = p_lash;
1352219820Sjeff	r->ucast_build_fwd_tables = lash_process;
1353219820Sjeff	r->delete = lash_delete;
1354219820Sjeff
1355219820Sjeff	return 0;
1356219820Sjeff}
1357