1321936Shselasky/*
2321936Shselasky * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3321936Shselasky * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
4321936Shselasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5321936Shselasky * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
6321936Shselasky * Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
7321936Shselasky *
8321936Shselasky * This software is available to you under a choice of one of two
9321936Shselasky * licenses.  You may choose to be licensed under the terms of the GNU
10321936Shselasky * General Public License (GPL) Version 2, available from the file
11321936Shselasky * COPYING in the main directory of this source tree, or the
12321936Shselasky * OpenIB.org BSD license below:
13321936Shselasky *
14321936Shselasky *     Redistribution and use in source and binary forms, with or
15321936Shselasky *     without modification, are permitted provided that the following
16321936Shselasky *     conditions are met:
17321936Shselasky *
18321936Shselasky *      - Redistributions of source code must retain the above
19321936Shselasky *        copyright notice, this list of conditions and the following
20321936Shselasky *        disclaimer.
21321936Shselasky *
22321936Shselasky *      - Redistributions in binary form must reproduce the above
23321936Shselasky *        copyright notice, this list of conditions and the following
24321936Shselasky *        disclaimer in the documentation and/or other materials
25321936Shselasky *        provided with the distribution.
26321936Shselasky *
27321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34321936Shselasky * SOFTWARE.
35321936Shselasky *
36321936Shselasky */
37321936Shselasky
38321936Shselasky/*
39321936Shselasky * Abstract:
40321936Shselasky *    Implementation of osm_link_mgr_t.
41321936Shselasky * This file implements the Link Manager object.
42321936Shselasky */
43321936Shselasky
44321936Shselasky#if HAVE_CONFIG_H
45321936Shselasky#  include <config.h>
46321936Shselasky#endif				/* HAVE_CONFIG_H */
47321936Shselasky
48321936Shselasky#include <string.h>
49321936Shselasky#include <iba/ib_types.h>
50321936Shselasky#include <complib/cl_debug.h>
51321936Shselasky#include <opensm/osm_file_ids.h>
52321936Shselasky#define FILE_ID OSM_FILE_LINK_MGR_C
53321936Shselasky#include <opensm/osm_sm.h>
54321936Shselasky#include <opensm/osm_node.h>
55321936Shselasky#include <opensm/osm_switch.h>
56321936Shselasky#include <opensm/osm_helper.h>
57321936Shselasky#include <opensm/osm_msgdef.h>
58321936Shselasky#include <opensm/osm_opensm.h>
59321936Shselasky#include <opensm/osm_db_pack.h>
60321936Shselasky
61321936Shselaskystatic uint8_t link_mgr_get_smsl(IN osm_sm_t * sm, IN osm_physp_t * p_physp)
62321936Shselasky{
63321936Shselasky	osm_opensm_t *p_osm = sm->p_subn->p_osm;
64321936Shselasky	struct osm_routing_engine *re = p_osm->routing_engine_used;
65321936Shselasky	ib_net16_t slid;
66321936Shselasky	ib_net16_t smlid;
67321936Shselasky	uint8_t sl;
68321936Shselasky
69321936Shselasky	OSM_LOG_ENTER(sm->p_log);
70321936Shselasky
71321936Shselasky	if (!(re && re->path_sl &&
72321936Shselasky	      (slid = osm_physp_get_base_lid(p_physp)))) {
73321936Shselasky		/*
74321936Shselasky		 * Use default SL if routing engine does not provide a
75321936Shselasky		 * path SL lookup callback.
76321936Shselasky		 */
77321936Shselasky		OSM_LOG_EXIT(sm->p_log);
78321936Shselasky		return sm->p_subn->opt.sm_sl;
79321936Shselasky	}
80321936Shselasky
81321936Shselasky	smlid = sm->p_subn->sm_base_lid;
82321936Shselasky
83321936Shselasky	/* Call into routing engine to find proper SL */
84321936Shselasky	sl = re->path_sl(re->context, sm->p_subn->opt.sm_sl,
85321936Shselasky			 slid, smlid);
86321936Shselasky
87321936Shselasky	OSM_LOG_EXIT(sm->p_log);
88321936Shselasky	return sl;
89321936Shselasky}
90321936Shselasky
91321936Shselaskystatic int link_mgr_set_physp_pi(osm_sm_t * sm, IN osm_physp_t * p_physp,
92321936Shselasky				 IN uint8_t port_state)
93321936Shselasky{
94321936Shselasky	uint8_t payload[IB_SMP_DATA_SIZE], payload2[IB_SMP_DATA_SIZE];
95321936Shselasky	ib_port_info_t *p_pi = (ib_port_info_t *) payload;
96321936Shselasky	ib_mlnx_ext_port_info_t *p_epi = (ib_mlnx_ext_port_info_t *) payload2;
97321936Shselasky	const ib_port_info_t *p_old_pi;
98321936Shselasky	const ib_mlnx_ext_port_info_t *p_old_epi;
99321936Shselasky	osm_madw_context_t context;
100321936Shselasky	osm_node_t *p_node;
101321936Shselasky	ib_api_status_t status;
102321936Shselasky	uint8_t port_num, mtu, op_vls, smsl = OSM_DEFAULT_SL;
103321936Shselasky	boolean_t esp0 = FALSE, send_set = FALSE, send_set2 = FALSE;
104321936Shselasky	osm_physp_t *p_remote_physp, *physp0 = NULL;
105321936Shselasky	int issue_ext = 0, fdr10_change = 0;
106321936Shselasky	int ret = 0;
107321936Shselasky	ib_net32_t attr_mod, cap_mask;
108321936Shselasky	boolean_t update_mkey = FALSE;
109321936Shselasky	ib_net64_t m_key = 0;
110321936Shselasky	osm_port_t *p_port;
111321936Shselasky
112321936Shselasky	OSM_LOG_ENTER(sm->p_log);
113321936Shselasky
114321936Shselasky	p_node = osm_physp_get_node_ptr(p_physp);
115321936Shselasky
116321936Shselasky	p_old_pi = &p_physp->port_info;
117321936Shselasky
118321936Shselasky	port_num = osm_physp_get_port_num(p_physp);
119321936Shselasky
120321936Shselasky	memcpy(payload, p_old_pi, sizeof(ib_port_info_t));
121321936Shselasky
122321936Shselasky	if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH ||
123321936Shselasky	    port_num == 0) {
124321936Shselasky		/* Need to make sure LID and SMLID fields in PortInfo are not 0 */
125321936Shselasky		if (!p_pi->base_lid) {
126321936Shselasky			p_port = osm_get_port_by_guid(sm->p_subn,
127321936Shselasky						      osm_physp_get_port_guid(p_physp));
128321936Shselasky			p_pi->base_lid = p_port->lid;
129321936Shselasky			sm->lid_mgr.dirty = TRUE;
130321936Shselasky			send_set = TRUE;
131321936Shselasky		}
132321936Shselasky
133321936Shselasky		/* we are initializing the ports with our local sm_base_lid */
134321936Shselasky		p_pi->master_sm_base_lid = sm->p_subn->sm_base_lid;
135321936Shselasky		if (p_pi->master_sm_base_lid != p_old_pi->master_sm_base_lid)
136321936Shselasky			send_set = TRUE;
137321936Shselasky	}
138321936Shselasky
139321936Shselasky	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH)
140321936Shselasky		physp0 = osm_node_get_physp_ptr(p_node, 0);
141321936Shselasky
142321936Shselasky	if (port_num == 0) {
143321936Shselasky		/*
144321936Shselasky		   CAs don't have a port 0, and for switch port 0,
145321936Shselasky		   we need to check if this is enhanced or base port 0.
146321936Shselasky		   For base port 0 the following parameters are not valid
147321936Shselasky		   (IBA 1.2.1 p.830 table 146).
148321936Shselasky		 */
149321936Shselasky		if (!p_node->sw) {
150321936Shselasky			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 4201: "
151321936Shselasky				"Cannot find switch by guid: 0x%" PRIx64 "\n",
152321936Shselasky				cl_ntoh64(p_node->node_info.node_guid));
153321936Shselasky			goto Exit;
154321936Shselasky		}
155321936Shselasky
156321936Shselasky		if (ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)
157321936Shselasky		    == FALSE) {
158321936Shselasky
159321936Shselasky			/* Even for base port 0 we might have to set smsl
160321936Shselasky			   (if we are using lash routing) */
161321936Shselasky			smsl = link_mgr_get_smsl(sm, p_physp);
162321936Shselasky			if (smsl != ib_port_info_get_master_smsl(p_old_pi)) {
163321936Shselasky				send_set = TRUE;
164321936Shselasky				OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
165321936Shselasky					"Setting SMSL to %d on port 0 GUID 0x%016"
166321936Shselasky					PRIx64 "\n", smsl,
167321936Shselasky					cl_ntoh64(osm_physp_get_port_guid
168321936Shselasky						  (p_physp)));
169321936Shselasky			/* Enter if base lid and master_sm_lid didn't change */
170321936Shselasky			} else if (send_set == FALSE) {
171321936Shselasky				/* This means the switch doesn't support
172321936Shselasky				   enhanced port 0 and we don't need to
173321936Shselasky				   change SMSL. Can skip it. */
174321936Shselasky				OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
175321936Shselasky					"Skipping port 0, GUID 0x%016" PRIx64
176321936Shselasky					"\n",
177321936Shselasky					cl_ntoh64(osm_physp_get_port_guid
178321936Shselasky						  (p_physp)));
179321936Shselasky				goto Exit;
180321936Shselasky			}
181321936Shselasky		} else
182321936Shselasky			esp0 = TRUE;
183321936Shselasky	}
184321936Shselasky
185321936Shselasky	/*
186321936Shselasky	   Should never write back a value that is bigger then 3 in
187321936Shselasky	   the PortPhysicalState field - so can not simply copy!
188321936Shselasky
189321936Shselasky	   Actually we want to write there:
190321936Shselasky	   port physical state - no change,
191321936Shselasky	   link down default state = polling
192321936Shselasky	   port state - as requested.
193321936Shselasky	 */
194321936Shselasky	p_pi->state_info2 = 0x02;
195321936Shselasky	ib_port_info_set_port_state(p_pi, port_state);
196321936Shselasky
197321936Shselasky	/* Determine ports' M_Key */
198321936Shselasky	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH &&
199321936Shselasky	    osm_physp_get_port_num(p_physp) != 0)
200321936Shselasky		m_key = ib_port_info_get_m_key(&physp0->port_info);
201321936Shselasky	else
202321936Shselasky		m_key = ib_port_info_get_m_key(p_pi);
203321936Shselasky
204321936Shselasky	/* Check whether this is base port0 smsl handling only */
205321936Shselasky	if (port_num == 0 && esp0 == FALSE) {
206321936Shselasky		ib_port_info_set_master_smsl(p_pi, smsl);
207321936Shselasky		goto Send;
208321936Shselasky	}
209321936Shselasky
210321936Shselasky	/*
211321936Shselasky	   PAST THIS POINT WE ARE HANDLING EITHER A NON PORT 0 OR ENHANCED PORT 0
212321936Shselasky	 */
213321936Shselasky
214321936Shselasky	if (ib_port_info_get_link_down_def_state(p_pi) !=
215321936Shselasky	    ib_port_info_get_link_down_def_state(p_old_pi))
216321936Shselasky		send_set = TRUE;
217321936Shselasky
218321936Shselasky	/* didn't get PortInfo before */
219321936Shselasky	if (!ib_port_info_get_port_state(p_old_pi))
220321936Shselasky		send_set = TRUE;
221321936Shselasky
222321936Shselasky	/* we only change port fields if we do not change state */
223321936Shselasky	if (port_state == IB_LINK_NO_CHANGE) {
224321936Shselasky		/* The following fields are relevant only for CA port, router, or Enh. SP0 */
225321936Shselasky		if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH ||
226321936Shselasky		    port_num == 0) {
227321936Shselasky			p_pi->m_key = sm->p_subn->opt.m_key;
228321936Shselasky			if (memcmp(&p_pi->m_key, &p_old_pi->m_key,
229321936Shselasky				   sizeof(p_pi->m_key))) {
230321936Shselasky				update_mkey = TRUE;
231321936Shselasky				send_set = TRUE;
232321936Shselasky			}
233321936Shselasky
234321936Shselasky			p_pi->subnet_prefix = sm->p_subn->opt.subnet_prefix;
235321936Shselasky			if (memcmp(&p_pi->subnet_prefix,
236321936Shselasky				   &p_old_pi->subnet_prefix,
237321936Shselasky				   sizeof(p_pi->subnet_prefix)))
238321936Shselasky				send_set = TRUE;
239321936Shselasky
240321936Shselasky			smsl = link_mgr_get_smsl(sm, p_physp);
241321936Shselasky			if (smsl != ib_port_info_get_master_smsl(p_old_pi)) {
242321936Shselasky
243321936Shselasky				ib_port_info_set_master_smsl(p_pi, smsl);
244321936Shselasky
245321936Shselasky				OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
246321936Shselasky					"Setting SMSL to %d on GUID 0x%016"
247321936Shselasky					PRIx64 ", port %d\n", smsl,
248321936Shselasky					cl_ntoh64(osm_physp_get_port_guid
249321936Shselasky						  (p_physp)), port_num);
250321936Shselasky
251321936Shselasky				send_set = TRUE;
252321936Shselasky			}
253321936Shselasky
254321936Shselasky			p_pi->m_key_lease_period =
255321936Shselasky			    sm->p_subn->opt.m_key_lease_period;
256321936Shselasky			if (memcmp(&p_pi->m_key_lease_period,
257321936Shselasky				   &p_old_pi->m_key_lease_period,
258321936Shselasky				   sizeof(p_pi->m_key_lease_period)))
259321936Shselasky				send_set = TRUE;
260321936Shselasky
261321936Shselasky			p_pi->mkey_lmc = 0;
262321936Shselasky			ib_port_info_set_mpb(p_pi, sm->p_subn->opt.m_key_protect_bits);
263321936Shselasky			if (esp0 == FALSE || sm->p_subn->opt.lmc_esp0)
264321936Shselasky				ib_port_info_set_lmc(p_pi, sm->p_subn->opt.lmc);
265321936Shselasky			if (ib_port_info_get_lmc(p_old_pi) !=
266321936Shselasky			    ib_port_info_get_lmc(p_pi) ||
267321936Shselasky			    ib_port_info_get_mpb(p_old_pi) !=
268321936Shselasky			    ib_port_info_get_mpb(p_pi))
269321936Shselasky				send_set = TRUE;
270321936Shselasky
271321936Shselasky			ib_port_info_set_timeout(p_pi,
272321936Shselasky						 sm->p_subn->opt.
273321936Shselasky						 subnet_timeout);
274321936Shselasky			if (ib_port_info_get_timeout(p_pi) !=
275321936Shselasky			    ib_port_info_get_timeout(p_old_pi))
276321936Shselasky				send_set = TRUE;
277321936Shselasky		}
278321936Shselasky
279321936Shselasky		/*
280321936Shselasky		   Several timeout mechanisms:
281321936Shselasky		 */
282321936Shselasky		p_remote_physp = osm_physp_get_remote(p_physp);
283321936Shselasky		if (port_num != 0 && p_remote_physp) {
284321936Shselasky			if (osm_node_get_type(osm_physp_get_node_ptr(p_physp))
285321936Shselasky			    == IB_NODE_TYPE_ROUTER) {
286321936Shselasky				ib_port_info_set_hoq_lifetime(p_pi,
287321936Shselasky							      sm->p_subn->
288321936Shselasky							      opt.
289321936Shselasky							      leaf_head_of_queue_lifetime);
290321936Shselasky			} else
291321936Shselasky			    if (osm_node_get_type
292321936Shselasky				(osm_physp_get_node_ptr(p_physp)) ==
293321936Shselasky				IB_NODE_TYPE_SWITCH) {
294321936Shselasky				/* Is remote end CA or router (a leaf port) ? */
295321936Shselasky				if (osm_node_get_type
296321936Shselasky				    (osm_physp_get_node_ptr(p_remote_physp)) !=
297321936Shselasky				    IB_NODE_TYPE_SWITCH) {
298321936Shselasky					ib_port_info_set_hoq_lifetime(p_pi,
299321936Shselasky								      sm->
300321936Shselasky								      p_subn->
301321936Shselasky								      opt.
302321936Shselasky								      leaf_head_of_queue_lifetime);
303321936Shselasky					ib_port_info_set_vl_stall_count(p_pi,
304321936Shselasky									sm->
305321936Shselasky									p_subn->
306321936Shselasky									opt.
307321936Shselasky									leaf_vl_stall_count);
308321936Shselasky				} else {
309321936Shselasky					ib_port_info_set_hoq_lifetime(p_pi,
310321936Shselasky								      sm->
311321936Shselasky								      p_subn->
312321936Shselasky								      opt.
313321936Shselasky								      head_of_queue_lifetime);
314321936Shselasky					ib_port_info_set_vl_stall_count(p_pi,
315321936Shselasky									sm->
316321936Shselasky									p_subn->
317321936Shselasky									opt.
318321936Shselasky									vl_stall_count);
319321936Shselasky				}
320321936Shselasky			}
321321936Shselasky			if (ib_port_info_get_hoq_lifetime(p_pi) !=
322321936Shselasky			    ib_port_info_get_hoq_lifetime(p_old_pi) ||
323321936Shselasky			    ib_port_info_get_vl_stall_count(p_pi) !=
324321936Shselasky			    ib_port_info_get_vl_stall_count(p_old_pi))
325321936Shselasky				send_set = TRUE;
326321936Shselasky		}
327321936Shselasky
328321936Shselasky		ib_port_info_set_phy_and_overrun_err_thd(p_pi,
329321936Shselasky							 sm->p_subn->opt.
330321936Shselasky							 local_phy_errors_threshold,
331321936Shselasky							 sm->p_subn->opt.
332321936Shselasky							 overrun_errors_threshold);
333321936Shselasky		if (p_pi->error_threshold != p_old_pi->error_threshold)
334321936Shselasky			send_set = TRUE;
335321936Shselasky
336321936Shselasky		/*
337321936Shselasky		   Set the easy common parameters for all port types,
338321936Shselasky		   then determine the neighbor MTU.
339321936Shselasky		 */
340321936Shselasky		p_pi->link_width_enabled = p_old_pi->link_width_supported;
341321936Shselasky		if (p_pi->link_width_enabled != p_old_pi->link_width_enabled)
342321936Shselasky			send_set = TRUE;
343321936Shselasky
344321936Shselasky		if (sm->p_subn->opt.force_link_speed &&
345321936Shselasky		    (sm->p_subn->opt.force_link_speed != 15 ||
346321936Shselasky		     ib_port_info_get_link_speed_enabled(p_pi) !=
347321936Shselasky		     ib_port_info_get_link_speed_sup(p_pi))) {
348321936Shselasky			ib_port_info_set_link_speed_enabled(p_pi,
349321936Shselasky							    sm->p_subn->opt.
350321936Shselasky							    force_link_speed);
351321936Shselasky			if (p_pi->link_speed != p_old_pi->link_speed)
352321936Shselasky				send_set = TRUE;
353321936Shselasky		}
354321936Shselasky
355321936Shselasky		if (sm->p_subn->opt.fdr10 &&
356321936Shselasky		    p_physp->ext_port_info.link_speed_supported & FDR10) {
357321936Shselasky			if (sm->p_subn->opt.fdr10 == 1) { /* enable */
358321936Shselasky				if (!(p_physp->ext_port_info.link_speed_enabled & FDR10))
359321936Shselasky					fdr10_change = 1;
360321936Shselasky			} else {	/* disable */
361321936Shselasky				if (p_physp->ext_port_info.link_speed_enabled & FDR10)
362321936Shselasky					fdr10_change = 1;
363321936Shselasky			}
364321936Shselasky			if (fdr10_change) {
365321936Shselasky				p_old_epi = &p_physp->ext_port_info;
366321936Shselasky				memcpy(payload2, p_old_epi,
367321936Shselasky				       sizeof(ib_mlnx_ext_port_info_t));
368321936Shselasky				p_epi->state_change_enable = 0x01;
369321936Shselasky				if (sm->p_subn->opt.fdr10 == 1)
370321936Shselasky					p_epi->link_speed_enabled = FDR10;
371321936Shselasky				else
372321936Shselasky					p_epi->link_speed_enabled = 0;
373321936Shselasky				send_set2 = TRUE;
374321936Shselasky			}
375321936Shselasky		}
376321936Shselasky
377321936Shselasky		if (osm_node_get_type(p_physp->p_node) == IB_NODE_TYPE_SWITCH &&
378321936Shselasky		    osm_physp_get_port_num(p_physp) != 0) {
379321936Shselasky			cap_mask = physp0->port_info.capability_mask;
380321936Shselasky		} else
381321936Shselasky			cap_mask = p_pi->capability_mask;
382321936Shselasky
383321936Shselasky		if (cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS)
384321936Shselasky			issue_ext = 1;
385321936Shselasky
386321936Shselasky		/* Do peer ports support extended link speeds ? */
387321936Shselasky		if (port_num != 0 && p_remote_physp) {
388321936Shselasky			osm_physp_t *rphysp0;
389321936Shselasky			ib_net32_t rem_cap_mask;
390321936Shselasky
391321936Shselasky			if (osm_node_get_type(p_remote_physp->p_node) ==
392321936Shselasky			    IB_NODE_TYPE_SWITCH) {
393321936Shselasky				rphysp0 = osm_node_get_physp_ptr(p_remote_physp->p_node, 0);
394321936Shselasky				rem_cap_mask = rphysp0->port_info.capability_mask;
395321936Shselasky			} else
396321936Shselasky				rem_cap_mask = p_remote_physp->port_info.capability_mask;
397321936Shselasky
398321936Shselasky			if (cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS &&
399321936Shselasky			    rem_cap_mask & IB_PORT_CAP_HAS_EXT_SPEEDS) {
400321936Shselasky				if (sm->p_subn->opt.force_link_speed_ext &&
401321936Shselasky				    (sm->p_subn->opt.force_link_speed_ext != IB_LINK_SPEED_EXT_SET_LSES ||
402321936Shselasky				     p_pi->link_speed_ext_enabled !=
403321936Shselasky				     ib_port_info_get_link_speed_ext_sup(p_pi))) {
404321936Shselasky					p_pi->link_speed_ext_enabled = sm->p_subn->opt.force_link_speed_ext;
405321936Shselasky					if (p_pi->link_speed_ext_enabled !=
406321936Shselasky					    p_old_pi->link_speed_ext_enabled)
407321936Shselasky						send_set = TRUE;
408321936Shselasky				}
409321936Shselasky			}
410321936Shselasky		}
411321936Shselasky
412321936Shselasky		/* calc new op_vls and mtu */
413321936Shselasky		op_vls =
414321936Shselasky		    osm_physp_calc_link_op_vls(sm->p_log, sm->p_subn, p_physp,
415321936Shselasky					       ib_port_info_get_op_vls(p_old_pi));
416321936Shselasky		mtu = osm_physp_calc_link_mtu(sm->p_log, p_physp,
417321936Shselasky					      ib_port_info_get_neighbor_mtu(p_old_pi));
418321936Shselasky
419321936Shselasky		ib_port_info_set_neighbor_mtu(p_pi, mtu);
420321936Shselasky		if (ib_port_info_get_neighbor_mtu(p_pi) !=
421321936Shselasky		    ib_port_info_get_neighbor_mtu(p_old_pi))
422321936Shselasky			send_set = TRUE;
423321936Shselasky
424321936Shselasky		ib_port_info_set_op_vls(p_pi, op_vls);
425321936Shselasky		if (ib_port_info_get_op_vls(p_pi) !=
426321936Shselasky		    ib_port_info_get_op_vls(p_old_pi))
427321936Shselasky			send_set = TRUE;
428321936Shselasky
429321936Shselasky		/* provide the vl_high_limit from the qos mgr */
430321936Shselasky		if (sm->p_subn->opt.qos &&
431321936Shselasky		    p_physp->vl_high_limit != p_old_pi->vl_high_limit) {
432321936Shselasky			send_set = TRUE;
433321936Shselasky			p_pi->vl_high_limit = p_physp->vl_high_limit;
434321936Shselasky		}
435321936Shselasky	}
436321936Shselasky
437321936ShselaskySend:
438321936Shselasky	context.pi_context.active_transition = FALSE;
439321936Shselasky	if (port_state != IB_LINK_NO_CHANGE &&
440321936Shselasky	    port_state != ib_port_info_get_port_state(p_old_pi)) {
441321936Shselasky		send_set = TRUE;
442321936Shselasky		if (port_state == IB_LINK_ACTIVE)
443321936Shselasky			context.pi_context.active_transition = TRUE;
444321936Shselasky	}
445321936Shselasky
446321936Shselasky	context.pi_context.node_guid = osm_node_get_node_guid(p_node);
447321936Shselasky	context.pi_context.port_guid = osm_physp_get_port_guid(p_physp);
448321936Shselasky	context.pi_context.set_method = TRUE;
449321936Shselasky	context.pi_context.light_sweep = FALSE;
450321936Shselasky	context.pi_context.client_rereg = FALSE;
451321936Shselasky
452321936Shselasky	/* We need to send the PortInfoSet request with the new sm_lid
453321936Shselasky	   in the following cases:
454321936Shselasky	   1. There is a change in the values (send_set == TRUE)
455321936Shselasky	   2. This is a switch external port (so it wasn't handled yet by
456321936Shselasky	   osm_lid_mgr) and first_time_master_sweep flag on the subnet is TRUE,
457321936Shselasky	   which means the SM just became master, and it then needs to send at
458321936Shselasky	   PortInfoSet to every port.
459321936Shselasky	 */
460321936Shselasky	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && port_num
461321936Shselasky	    && sm->p_subn->first_time_master_sweep == TRUE)
462321936Shselasky		send_set = TRUE;
463321936Shselasky
464321936Shselasky	if (!send_set)
465321936Shselasky		goto SEND_EPI;
466321936Shselasky
467321936Shselasky	attr_mod = cl_hton32(port_num);
468321936Shselasky	if (issue_ext)
469321936Shselasky		attr_mod |= cl_hton32(1 << 31);	/* AM SMSupportExtendedSpeeds */
470321936Shselasky	status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp),
471321936Shselasky			     payload, sizeof(payload), IB_MAD_ATTR_PORT_INFO,
472321936Shselasky			     attr_mod, FALSE, m_key,
473321936Shselasky			     CL_DISP_MSGID_NONE, &context);
474321936Shselasky	if (status)
475321936Shselasky		ret = -1;
476321936Shselasky
477321936Shselasky	/* If we sent a new mkey above, update our guid2mkey map
478321936Shselasky	   now, on the assumption that the SubnSet succeeds
479321936Shselasky	 */
480321936Shselasky	if (update_mkey)
481321936Shselasky		osm_db_guid2mkey_set(sm->p_subn->p_g2m,
482321936Shselasky				     cl_ntoh64(p_physp->port_guid),
483321936Shselasky				     cl_ntoh64(p_pi->m_key));
484321936Shselasky
485321936ShselaskySEND_EPI:
486321936Shselasky	if (send_set2) {
487321936Shselasky		status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp),
488321936Shselasky				     payload2, sizeof(payload2),
489321936Shselasky				     IB_MAD_ATTR_MLNX_EXTENDED_PORT_INFO,
490321936Shselasky				     cl_hton32(port_num), FALSE, m_key,
491321936Shselasky				     CL_DISP_MSGID_NONE, &context);
492321936Shselasky		if (status)
493321936Shselasky			ret = -1;
494321936Shselasky	}
495321936Shselasky
496321936ShselaskyExit:
497321936Shselasky	OSM_LOG_EXIT(sm->p_log);
498321936Shselasky	return ret;
499321936Shselasky}
500321936Shselasky
501321936Shselaskystatic int link_mgr_process_node(osm_sm_t * sm, IN osm_node_t * p_node,
502321936Shselasky				 IN const uint8_t link_state)
503321936Shselasky{
504321936Shselasky	osm_physp_t *p_physp, *p_physp_remote;
505321936Shselasky	uint32_t i, num_physp;
506321936Shselasky	int ret = 0;
507321936Shselasky	uint8_t current_state;
508321936Shselasky
509321936Shselasky	OSM_LOG_ENTER(sm->p_log);
510321936Shselasky
511321936Shselasky	OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
512321936Shselasky		"Node 0x%" PRIx64 " going to %s\n",
513321936Shselasky		cl_ntoh64(osm_node_get_node_guid(p_node)),
514321936Shselasky		ib_get_port_state_str(link_state));
515321936Shselasky
516321936Shselasky	/*
517321936Shselasky	   Set the PortInfo for every Physical Port associated
518321936Shselasky	   with this Port.  Start iterating with port 1, since the linkstate
519321936Shselasky	   is not applicable to the management port on switches.
520321936Shselasky	 */
521321936Shselasky	num_physp = osm_node_get_num_physp(p_node);
522321936Shselasky	for (i = 0; i < num_physp; i++) {
523321936Shselasky		/*
524321936Shselasky		   Don't bother doing anything if this Physical Port is not valid.
525321936Shselasky		   or if the state of the port is already better then the
526321936Shselasky		   specified state.
527321936Shselasky		 */
528321936Shselasky		p_physp = osm_node_get_physp_ptr(p_node, (uint8_t) i);
529321936Shselasky		if (!p_physp)
530321936Shselasky			continue;
531321936Shselasky
532321936Shselasky		current_state = osm_physp_get_port_state(p_physp);
533321936Shselasky		if (current_state == IB_LINK_DOWN)
534321936Shselasky			continue;
535321936Shselasky
536321936Shselasky		/*
537321936Shselasky		    Set PortState to DOWN in case Remote Physical Port is
538321936Shselasky		    unreachable. We have to check this for all ports, except
539321936Shselasky		    port zero.
540321936Shselasky		 */
541321936Shselasky		p_physp_remote = osm_physp_get_remote(p_physp);
542321936Shselasky		if ((i != 0) && (!p_physp_remote ||
543321936Shselasky		    !osm_physp_is_valid(p_physp_remote))) {
544321936Shselasky			if (current_state != IB_LINK_INIT)
545321936Shselasky				link_mgr_set_physp_pi(sm, p_physp, IB_LINK_DOWN);
546321936Shselasky			continue;
547321936Shselasky		}
548321936Shselasky
549321936Shselasky		/*
550321936Shselasky		   Normally we only send state update if state is lower
551321936Shselasky		   then required state. However, we need to send update if
552321936Shselasky		   no state change required.
553321936Shselasky		 */
554321936Shselasky		if (link_state != IB_LINK_NO_CHANGE &&
555321936Shselasky		    link_state <= current_state)
556321936Shselasky			OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
557321936Shselasky				"Physical port %u already %s. Skipping\n",
558321936Shselasky				p_physp->port_num,
559321936Shselasky				ib_get_port_state_str(current_state));
560321936Shselasky		else if (link_mgr_set_physp_pi(sm, p_physp, link_state))
561321936Shselasky			ret = -1;
562321936Shselasky	}
563321936Shselasky
564321936Shselasky	OSM_LOG_EXIT(sm->p_log);
565321936Shselasky	return ret;
566321936Shselasky}
567321936Shselasky
568321936Shselaskyint osm_link_mgr_process(osm_sm_t * sm, IN const uint8_t link_state)
569321936Shselasky{
570321936Shselasky	cl_qmap_t *p_node_guid_tbl;
571321936Shselasky	osm_node_t *p_node;
572321936Shselasky	int ret = 0;
573321936Shselasky
574321936Shselasky	OSM_LOG_ENTER(sm->p_log);
575321936Shselasky
576321936Shselasky	p_node_guid_tbl = &sm->p_subn->node_guid_tbl;
577321936Shselasky
578321936Shselasky	CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
579321936Shselasky
580321936Shselasky	for (p_node = (osm_node_t *) cl_qmap_head(p_node_guid_tbl);
581321936Shselasky	     p_node != (osm_node_t *) cl_qmap_end(p_node_guid_tbl);
582321936Shselasky	     p_node = (osm_node_t *) cl_qmap_next(&p_node->map_item))
583321936Shselasky		if (link_mgr_process_node(sm, p_node, link_state))
584321936Shselasky			ret = -1;
585321936Shselasky
586321936Shselasky	CL_PLOCK_RELEASE(sm->p_lock);
587321936Shselasky
588321936Shselasky	OSM_LOG_EXIT(sm->p_log);
589321936Shselasky	return ret;
590321936Shselasky}
591