2 * Copyright (c) 2004-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.
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:
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
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.
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
38 * Implementation of osm_link_mgr_t.
39 * This file implements the Link Manager object.
44 #endif /* HAVE_CONFIG_H */
47 #include <iba/ib_types.h>
48 #include <complib/cl_debug.h>
49 #include <opensm/osm_sm.h>
50 #include <opensm/osm_node.h>
51 #include <opensm/osm_switch.h>
52 #include <opensm/osm_helper.h>
53 #include <opensm/osm_msgdef.h>
55 /**********************************************************************
56 **********************************************************************/
58 __osm_link_mgr_set_physp_pi(osm_sm_t * sm,
59 IN osm_physp_t * const p_physp,
60 IN uint8_t const port_state)
62 uint8_t payload[IB_SMP_DATA_SIZE];
63 ib_port_info_t *const p_pi = (ib_port_info_t *) payload;
64 const ib_port_info_t *p_old_pi;
65 osm_madw_context_t context;
67 ib_api_status_t status;
71 boolean_t esp0 = FALSE;
72 boolean_t send_set = FALSE;
73 osm_physp_t *p_remote_physp;
75 OSM_LOG_ENTER(sm->p_log);
77 p_node = osm_physp_get_node_ptr(p_physp);
79 port_num = osm_physp_get_port_num(p_physp);
83 CAs don't have a port 0, and for switch port 0,
84 we need to check if this is enhanced or base port 0.
85 For base port 0 the following parameters are not valid (p822, table 145).
88 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 4201: "
89 "Cannot find switch by guid: 0x%" PRIx64 "\n",
90 cl_ntoh64(p_node->node_info.node_guid));
94 if (ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)
96 /* This means the switch doesn't support enhanced port 0.
98 OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
99 "Skipping port 0, GUID 0x%016" PRIx64 "\n",
100 cl_ntoh64(osm_physp_get_port_guid(p_physp)));
107 PAST THIS POINT WE ARE HANDLING EITHER A NON PORT 0 OR ENHANCED PORT 0
110 p_old_pi = &p_physp->port_info;
112 memset(payload, 0, IB_SMP_DATA_SIZE);
113 memcpy(payload, p_old_pi, sizeof(ib_port_info_t));
116 Should never write back a value that is bigger then 3 in
117 the PortPhysicalState field - so can not simply copy!
119 Actually we want to write there:
120 port physical state - no change,
121 link down default state = polling
122 port state - as requested.
124 p_pi->state_info2 = 0x02;
125 ib_port_info_set_port_state(p_pi, port_state);
127 if (ib_port_info_get_link_down_def_state(p_pi) !=
128 ib_port_info_get_link_down_def_state(p_old_pi))
131 /* didn't get PortInfo before */
132 if (!ib_port_info_get_port_state(p_old_pi))
135 /* we only change port fields if we do not change state */
136 if (port_state == IB_LINK_NO_CHANGE) {
137 /* The following fields are relevant only for CA port, router, or Enh. SP0 */
138 if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH ||
140 p_pi->m_key = sm->p_subn->opt.m_key;
141 if (memcmp(&p_pi->m_key, &p_old_pi->m_key,
142 sizeof(p_pi->m_key)))
145 p_pi->subnet_prefix = sm->p_subn->opt.subnet_prefix;
146 if (memcmp(&p_pi->subnet_prefix,
147 &p_old_pi->subnet_prefix,
148 sizeof(p_pi->subnet_prefix)))
151 p_pi->base_lid = osm_physp_get_base_lid(p_physp);
152 if (memcmp(&p_pi->base_lid, &p_old_pi->base_lid,
153 sizeof(p_pi->base_lid)))
156 /* we are initializing the ports with our local sm_base_lid */
157 p_pi->master_sm_base_lid = sm->p_subn->sm_base_lid;
158 if (memcmp(&p_pi->master_sm_base_lid,
159 &p_old_pi->master_sm_base_lid,
160 sizeof(p_pi->master_sm_base_lid)))
163 p_pi->m_key_lease_period =
164 sm->p_subn->opt.m_key_lease_period;
165 if (memcmp(&p_pi->m_key_lease_period,
166 &p_old_pi->m_key_lease_period,
167 sizeof(p_pi->m_key_lease_period)))
171 p_pi->mkey_lmc = sm->p_subn->opt.lmc;
173 if (sm->p_subn->opt.lmc_esp0)
174 p_pi->mkey_lmc = sm->p_subn->opt.lmc;
178 if (memcmp(&p_pi->mkey_lmc, &p_old_pi->mkey_lmc,
179 sizeof(p_pi->mkey_lmc)))
182 ib_port_info_set_timeout(p_pi,
185 if (ib_port_info_get_timeout(p_pi) !=
186 ib_port_info_get_timeout(p_old_pi))
191 Several timeout mechanisms:
193 p_remote_physp = osm_physp_get_remote(p_physp);
194 if (port_num != 0 && p_remote_physp) {
195 if (osm_node_get_type(osm_physp_get_node_ptr(p_physp))
196 == IB_NODE_TYPE_ROUTER) {
197 ib_port_info_set_hoq_lifetime(p_pi,
200 leaf_head_of_queue_lifetime);
202 if (osm_node_get_type
203 (osm_physp_get_node_ptr(p_physp)) ==
204 IB_NODE_TYPE_SWITCH) {
205 /* Is remote end CA or router (a leaf port) ? */
206 if (osm_node_get_type
207 (osm_physp_get_node_ptr(p_remote_physp)) !=
208 IB_NODE_TYPE_SWITCH) {
209 ib_port_info_set_hoq_lifetime(p_pi,
213 leaf_head_of_queue_lifetime);
214 ib_port_info_set_vl_stall_count(p_pi,
218 leaf_vl_stall_count);
220 ib_port_info_set_hoq_lifetime(p_pi,
224 head_of_queue_lifetime);
225 ib_port_info_set_vl_stall_count(p_pi,
232 if (ib_port_info_get_hoq_lifetime(p_pi) !=
233 ib_port_info_get_hoq_lifetime(p_old_pi) ||
234 ib_port_info_get_vl_stall_count(p_pi) !=
235 ib_port_info_get_vl_stall_count(p_old_pi))
239 ib_port_info_set_phy_and_overrun_err_thd(p_pi,
241 local_phy_errors_threshold,
243 overrun_errors_threshold);
244 if (memcmp(&p_pi->error_threshold, &p_old_pi->error_threshold,
245 sizeof(p_pi->error_threshold)))
249 Set the easy common parameters for all port types,
250 then determine the neighbor MTU.
252 p_pi->link_width_enabled = p_old_pi->link_width_supported;
253 if (memcmp(&p_pi->link_width_enabled,
254 &p_old_pi->link_width_enabled,
255 sizeof(p_pi->link_width_enabled)))
258 if (sm->p_subn->opt.force_link_speed &&
259 (sm->p_subn->opt.force_link_speed != 15 ||
260 ib_port_info_get_link_speed_enabled(p_pi) !=
261 ib_port_info_get_link_speed_sup(p_pi))) {
262 ib_port_info_set_link_speed_enabled(p_pi,
265 if (memcmp(&p_pi->link_speed, &p_old_pi->link_speed,
266 sizeof(p_pi->link_speed)))
270 /* calc new op_vls and mtu */
272 osm_physp_calc_link_op_vls(sm->p_log, sm->p_subn, p_physp);
273 mtu = osm_physp_calc_link_mtu(sm->p_log, p_physp);
275 ib_port_info_set_neighbor_mtu(p_pi, mtu);
276 if (ib_port_info_get_neighbor_mtu(p_pi) !=
277 ib_port_info_get_neighbor_mtu(p_old_pi))
280 ib_port_info_set_op_vls(p_pi, op_vls);
281 if (ib_port_info_get_op_vls(p_pi) !=
282 ib_port_info_get_op_vls(p_old_pi))
285 /* provide the vl_high_limit from the qos mgr */
286 if (sm->p_subn->opt.qos &&
287 p_physp->vl_high_limit != p_old_pi->vl_high_limit) {
289 p_pi->vl_high_limit = p_physp->vl_high_limit;
293 if (port_state != IB_LINK_NO_CHANGE &&
294 port_state != ib_port_info_get_port_state(p_old_pi)) {
296 if (port_state == IB_LINK_ACTIVE)
297 context.pi_context.active_transition = TRUE;
299 context.pi_context.active_transition = FALSE;
302 context.pi_context.node_guid = osm_node_get_node_guid(p_node);
303 context.pi_context.port_guid = osm_physp_get_port_guid(p_physp);
304 context.pi_context.set_method = TRUE;
305 context.pi_context.light_sweep = FALSE;
307 /* We need to send the PortInfoSet request with the new sm_lid
308 in the following cases:
309 1. There is a change in the values (send_set == TRUE)
310 2. This is a switch external port (so it wasn't handled yet by
311 osm_lid_mgr) and first_time_master_sweep flag on the subnet is TRUE,
312 which means the SM just became master, and it then needs to send at
313 PortInfoSet to every port.
315 if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && port_num
316 && sm->p_subn->first_time_master_sweep == TRUE)
320 status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp),
321 payload, sizeof(payload),
322 IB_MAD_ATTR_PORT_INFO,
324 CL_DISP_MSGID_NONE, &context);
327 OSM_LOG_EXIT(sm->p_log);
331 /**********************************************************************
332 **********************************************************************/
334 __osm_link_mgr_process_node(osm_sm_t * sm,
335 IN osm_node_t * const p_node,
336 IN const uint8_t link_state)
340 osm_physp_t *p_physp;
341 uint8_t current_state;
342 osm_signal_t signal = OSM_SIGNAL_DONE;
344 OSM_LOG_ENTER(sm->p_log);
346 OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
347 "Node 0x%" PRIx64 " going to %s\n",
348 cl_ntoh64(osm_node_get_node_guid(p_node)),
349 ib_get_port_state_str(link_state));
352 Set the PortInfo for every Physical Port associated
353 with this Port. Start iterating with port 1, since the linkstate
354 is not applicable to the management port on switches.
356 num_physp = osm_node_get_num_physp(p_node);
357 for (i = 0; i < num_physp; i++) {
359 Don't bother doing anything if this Physical Port is not valid.
360 or if the state of the port is already better then the
363 p_physp = osm_node_get_physp_ptr(p_node, (uint8_t) i);
367 current_state = osm_physp_get_port_state(p_physp);
368 if (current_state == IB_LINK_DOWN)
372 Normally we only send state update if state is lower
373 then required state. However, we need to send update if
374 no state change required.
376 if (link_state != IB_LINK_NO_CHANGE &&
377 link_state <= current_state)
378 OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
379 "Physical port %u already %s. Skipping\n",
381 ib_get_port_state_str(current_state));
382 else if (__osm_link_mgr_set_physp_pi(sm, p_physp, link_state))
383 signal = OSM_SIGNAL_DONE_PENDING;
386 OSM_LOG_EXIT(sm->p_log);
390 /**********************************************************************
391 **********************************************************************/
392 osm_signal_t osm_link_mgr_process(osm_sm_t * sm, IN const uint8_t link_state)
394 cl_qmap_t *p_node_guid_tbl;
396 osm_signal_t signal = OSM_SIGNAL_DONE;
398 OSM_LOG_ENTER(sm->p_log);
400 p_node_guid_tbl = &sm->p_subn->node_guid_tbl;
402 CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
404 for (p_node = (osm_node_t *) cl_qmap_head(p_node_guid_tbl);
405 p_node != (osm_node_t *) cl_qmap_end(p_node_guid_tbl);
406 p_node = (osm_node_t *) cl_qmap_next(&p_node->map_item)) {
407 if (__osm_link_mgr_process_node(sm, p_node, link_state) ==
408 OSM_SIGNAL_DONE_PENDING)
409 signal = OSM_SIGNAL_DONE_PENDING;
412 CL_PLOCK_RELEASE(sm->p_lock);
414 OSM_LOG_EXIT(sm->p_log);