1 /*
2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2012 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 * Copyright (c) 2009 HNR Consulting. All rights reserved.
6 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
7 *
8 * This software is available to you under a choice of one of two
9 * licenses. You may choose to be licensed under the terms of the GNU
10 * General Public License (GPL) Version 2, available from the file
11 * COPYING in the main directory of this source tree, or the
12 * OpenIB.org BSD license below:
13 *
14 * Redistribution and use in source and binary forms, with or
15 * without modification, are permitted provided that the following
16 * conditions are met:
17 *
18 * - Redistributions of source code must retain the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer.
21 *
22 * - Redistributions in binary form must reproduce the above
23 * copyright notice, this list of conditions and the following
24 * disclaimer in the documentation and/or other materials
25 * provided with the distribution.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34 * SOFTWARE.
35 *
36 */
37
38 /*
39 * Abstract:
40 * Implementation of osm_pi_rcv_t.
41 * This object represents the PortInfo Receiver object.
42 * This object is part of the opensm family of objects.
43 */
44
45 #if HAVE_CONFIG_H
46 # include <config.h>
47 #endif /* HAVE_CONFIG_H */
48
49 #include <string.h>
50 #include <stdlib.h>
51 #include <iba/ib_types.h>
52 #include <complib/cl_qmap.h>
53 #include <complib/cl_passivelock.h>
54 #include <complib/cl_debug.h>
55 #include <opensm/osm_file_ids.h>
56 #define FILE_ID OSM_FILE_PORT_INFO_RCV_C
57 #include <vendor/osm_vendor_api.h>
58 #include <opensm/osm_madw.h>
59 #include <opensm/osm_log.h>
60 #include <opensm/osm_node.h>
61 #include <opensm/osm_subnet.h>
62 #include <opensm/osm_mad_pool.h>
63 #include <opensm/osm_msgdef.h>
64 #include <opensm/osm_helper.h>
65 #include <opensm/osm_pkey.h>
66 #include <opensm/osm_remote_sm.h>
67 #include <opensm/osm_opensm.h>
68 #include <opensm/osm_ucast_mgr.h>
69
pi_rcv_check_and_fix_lid(osm_log_t * log,ib_port_info_t * pi,osm_physp_t * p)70 static void pi_rcv_check_and_fix_lid(osm_log_t * log, ib_port_info_t * pi,
71 osm_physp_t * p)
72 {
73 if (PF(cl_ntoh16(pi->base_lid) > IB_LID_UCAST_END_HO)) {
74 OSM_LOG(log, OSM_LOG_ERROR, "ERR 0F04: "
75 "Got invalid base LID %u from the network. "
76 "Corrected to %u\n", cl_ntoh16(pi->base_lid),
77 cl_ntoh16(p->port_info.base_lid));
78 pi->base_lid = p->port_info.base_lid;
79 }
80 }
81
pi_rcv_process_endport(IN osm_sm_t * sm,IN osm_physp_t * p_physp,IN const ib_port_info_t * p_pi)82 static void pi_rcv_process_endport(IN osm_sm_t * sm, IN osm_physp_t * p_physp,
83 IN const ib_port_info_t * p_pi)
84 {
85 osm_madw_context_t context;
86 ib_api_status_t status;
87 ib_net64_t port_guid;
88 int extended;
89 uint8_t rate, mtu, mpb;
90 unsigned data_vls;
91 cl_qmap_t *p_sm_tbl;
92 osm_remote_sm_t *p_sm;
93
94 OSM_LOG_ENTER(sm->p_log);
95
96 port_guid = osm_physp_get_port_guid(p_physp);
97
98 /* HACK extended port 0 should be handled too! */
99 if (osm_physp_get_port_num(p_physp) != 0 &&
100 ib_port_info_get_port_state(p_pi) != IB_LINK_DOWN) {
101 /* track the minimal endport MTU, rate, and operational VLs */
102 mtu = ib_port_info_get_mtu_cap(p_pi);
103 if (mtu < sm->p_subn->min_ca_mtu) {
104 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
105 "Setting endport minimal MTU to:%u defined by port:0x%"
106 PRIx64 "\n", mtu, cl_ntoh64(port_guid));
107 sm->p_subn->min_ca_mtu = mtu;
108 }
109
110 extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
111 rate = ib_port_info_compute_rate(p_pi, extended);
112 if (ib_path_compare_rates(rate, sm->p_subn->min_ca_rate) < 0) {
113 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
114 "Setting endport minimal rate to:%u defined by port:0x%"
115 PRIx64 "\n", rate, cl_ntoh64(port_guid));
116 sm->p_subn->min_ca_rate = rate;
117 }
118
119 data_vls = 1U << (ib_port_info_get_vl_cap(p_pi) - 1);
120 if (data_vls > 1U << (sm->p_subn->opt.max_op_vls - 1))
121 data_vls = 1U << (sm->p_subn->opt.max_op_vls - 1);
122 if (data_vls >= IB_MAX_NUM_VLS)
123 data_vls = IB_MAX_NUM_VLS - 1;
124 if ((uint8_t)data_vls < sm->p_subn->min_data_vls) {
125 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
126 "Setting endport minimal data VLs to:%u defined by port:0x%"
127 PRIx64 "\n", data_vls, cl_ntoh64(port_guid));
128 sm->p_subn->min_data_vls = data_vls;
129 }
130 }
131
132 /* Check M_Key vs M_Key protect, can we control the port ? */
133 mpb = ib_port_info_get_mpb(p_pi);
134 if (mpb > 0 && p_pi->m_key == 0) {
135 OSM_LOG(sm->p_log, OSM_LOG_INFO,
136 "Port 0x%" PRIx64 " has unknown M_Key, protection level %u\n",
137 cl_ntoh64(port_guid), mpb);
138 }
139
140 if (port_guid != sm->p_subn->sm_port_guid) {
141 p_sm_tbl = &sm->p_subn->sm_guid_tbl;
142 if (p_pi->capability_mask & IB_PORT_CAP_IS_SM) {
143 /*
144 * Before querying the SM - we want to make sure we
145 * clean its state, so if the querying fails we
146 * recognize that this SM is not active.
147 */
148 p_sm =
149 (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl,
150 port_guid);
151 if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl))
152 /* clean it up */
153 p_sm->smi.pri_state =
154 0xF0 & p_sm->smi.pri_state;
155 if (sm->p_subn->opt.ignore_other_sm)
156 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
157 "Ignoring SM on port 0x%" PRIx64 "\n",
158 cl_ntoh64(port_guid));
159 else {
160 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
161 "Detected another SM. Requesting SMInfo "
162 "from port 0x%" PRIx64 "\n",
163 cl_ntoh64(port_guid));
164
165 /*
166 This port indicates it's an SM and
167 it's not our own port.
168 Acquire the SMInfo Attribute.
169 */
170 memset(&context, 0, sizeof(context));
171 context.smi_context.set_method = FALSE;
172 context.smi_context.port_guid = port_guid;
173 status = osm_req_get(sm,
174 osm_physp_get_dr_path_ptr
175 (p_physp),
176 IB_MAD_ATTR_SM_INFO, 0,
177 FALSE,
178 ib_port_info_get_m_key(&p_physp->port_info),
179 CL_DISP_MSGID_NONE,
180 &context);
181
182 if (status != IB_SUCCESS)
183 OSM_LOG(sm->p_log, OSM_LOG_ERROR,
184 "ERR 0F05: "
185 "Failure requesting SMInfo (%s) "
186 "from port 0x%" PRIx64 "\n",
187 ib_get_err_str(status),
188 cl_ntoh64(port_guid));
189 }
190 } else {
191 p_sm =
192 (osm_remote_sm_t *) cl_qmap_remove(p_sm_tbl,
193 port_guid);
194 if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl))
195 free(p_sm);
196 }
197 }
198
199 OSM_LOG_EXIT(sm->p_log);
200 }
201
202 /**********************************************************************
203 The plock must be held before calling this function.
204 **********************************************************************/
pi_rcv_process_switch_port0(IN osm_sm_t * sm,IN osm_node_t * p_node,IN osm_physp_t * p_physp,IN ib_port_info_t * p_pi)205 static void pi_rcv_process_switch_port0(IN osm_sm_t * sm,
206 IN osm_node_t * p_node,
207 IN osm_physp_t * p_physp,
208 IN ib_port_info_t * p_pi)
209 {
210 ib_api_status_t status;
211 osm_madw_context_t context;
212 uint8_t port, num_ports;
213
214 OSM_LOG_ENTER(sm->p_log);
215
216 if (p_physp->need_update)
217 sm->p_subn->ignore_existing_lfts = TRUE;
218
219 pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp);
220
221 /* Update the PortInfo attribute */
222 osm_physp_set_port_info(p_physp, p_pi, sm);
223
224 /* Determine if base switch port 0 */
225 if (p_node->sw &&
226 !ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info))
227 /* PortState is not used on BSP0 but just in case it is DOWN */
228 p_physp->port_info = *p_pi;
229
230 /* Now, query PortInfo for the switch external ports */
231 num_ports = osm_node_get_num_physp(p_node);
232
233 context.pi_context.node_guid = osm_node_get_node_guid(p_node);
234 context.pi_context.port_guid = osm_physp_get_port_guid(p_physp);
235 context.pi_context.set_method = FALSE;
236 context.pi_context.light_sweep = FALSE;
237 context.pi_context.active_transition = FALSE;
238 context.pi_context.client_rereg = FALSE;
239
240 for (port = 1; port < num_ports; port++) {
241 status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp),
242 IB_MAD_ATTR_PORT_INFO, cl_hton32(port),
243 FALSE,
244 ib_port_info_get_m_key(&p_physp->port_info),
245 CL_DISP_MSGID_NONE, &context);
246 if (status != IB_SUCCESS)
247 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F16: "
248 "Failure initiating PortInfo request (%s)\n",
249 ib_get_err_str(status));
250 }
251
252 pi_rcv_process_endport(sm, p_physp, p_pi);
253 OSM_LOG_EXIT(sm->p_log);
254 }
255
256 /**********************************************************************
257 The plock must be held before calling this function.
258 **********************************************************************/
pi_rcv_process_switch_ext_port(IN osm_sm_t * sm,IN osm_node_t * p_node,IN osm_physp_t * p_physp,IN ib_port_info_t * p_pi)259 static void pi_rcv_process_switch_ext_port(IN osm_sm_t * sm,
260 IN osm_node_t * p_node,
261 IN osm_physp_t * p_physp,
262 IN ib_port_info_t * p_pi)
263 {
264 ib_api_status_t status = IB_SUCCESS;
265 osm_madw_context_t context;
266 osm_physp_t *p_remote_physp, *physp0;
267 osm_node_t *p_remote_node;
268 ib_net64_t m_key;
269 unsigned data_vls;
270 uint8_t port_num;
271 uint8_t remote_port_num;
272 osm_dr_path_t path;
273 int mlnx_epi_supported = 0;
274
275 OSM_LOG_ENTER(sm->p_log);
276
277 /*
278 Check the state of the physical port.
279 If there appears to be something on the other end of the wire,
280 then ask for NodeInfo. Ignore the switch management port.
281 */
282 port_num = osm_physp_get_port_num(p_physp);
283
284 if (sm->p_subn->opt.fdr10)
285 mlnx_epi_supported = is_mlnx_ext_port_info_supported(
286 ib_node_info_get_vendor_id(&p_node->node_info),
287 p_node->node_info.device_id);
288
289 /* if in_sweep_hop_0 is TRUE, then this means the SM is on the switch,
290 and we got switchInfo of our local switch. Do not continue
291 probing through the switch. */
292 switch (ib_port_info_get_port_state(p_pi)) {
293 case IB_LINK_DOWN:
294 p_remote_physp = osm_physp_get_remote(p_physp);
295 if (p_remote_physp) {
296 p_remote_node =
297 osm_physp_get_node_ptr(p_remote_physp);
298 remote_port_num =
299 osm_physp_get_port_num(p_remote_physp);
300
301 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
302 "Unlinking local node 0x%" PRIx64
303 ", port %u"
304 "\n\t\t\t\tand remote node 0x%" PRIx64
305 ", port %u\n",
306 cl_ntoh64(osm_node_get_node_guid
307 (p_node)), port_num,
308 cl_ntoh64(osm_node_get_node_guid
309 (p_remote_node)),
310 remote_port_num);
311
312 if (sm->ucast_mgr.cache_valid)
313 osm_ucast_cache_add_link(&sm->ucast_mgr,
314 p_physp,
315 p_remote_physp);
316
317 osm_node_unlink(p_node, (uint8_t) port_num,
318 p_remote_node,
319 (uint8_t) remote_port_num);
320
321 }
322 break;
323
324 case IB_LINK_INIT:
325 case IB_LINK_ARMED:
326 case IB_LINK_ACTIVE:
327 physp0 = osm_node_get_physp_ptr(p_node, 0);
328 if (mlnx_epi_supported) {
329 m_key = ib_port_info_get_m_key(&physp0->port_info);
330
331 context.pi_context.node_guid = osm_node_get_node_guid(p_node);
332 context.pi_context.port_guid = osm_physp_get_port_guid(p_physp);
333 context.pi_context.set_method = FALSE;
334 context.pi_context.light_sweep = FALSE;
335 context.pi_context.active_transition = FALSE;
336 context.pi_context.client_rereg = FALSE;
337 status = osm_req_get(sm,
338 osm_physp_get_dr_path_ptr(p_physp),
339 IB_MAD_ATTR_MLNX_EXTENDED_PORT_INFO,
340 cl_hton32(port_num), FALSE, m_key,
341 CL_DISP_MSGID_NONE, &context);
342 if (status != IB_SUCCESS)
343 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F11: "
344 "Failure initiating MLNX ExtPortInfo request (%s)\n",
345 ib_get_err_str(status));
346 }
347 if (sm->p_subn->in_sweep_hop_0 == FALSE) {
348 /*
349 To avoid looping forever, only probe the port if it
350 is NOT the port that responded to the SMP.
351
352 Request node info from the other end of this link:
353 1) Copy the current path from the parent node.
354 2) Extend the path to the next hop thru this port.
355 3) Request node info with the new path
356
357 */
358 if (p_pi->local_port_num !=
359 osm_physp_get_port_num(p_physp)) {
360 path = *osm_physp_get_dr_path_ptr(p_physp);
361
362 if (osm_dr_path_extend(&path,
363 osm_physp_get_port_num
364 (p_physp))) {
365 OSM_LOG(sm->p_log, OSM_LOG_ERROR,
366 "ERR 0F08: "
367 "DR path with hop count %d couldn't be extended\n",
368 path.hop_count);
369 break;
370 }
371
372 memset(&context, 0, sizeof(context));
373 context.ni_context.node_guid =
374 osm_node_get_node_guid(p_node);
375 context.ni_context.port_num =
376 osm_physp_get_port_num(p_physp);
377
378 status = osm_req_get(sm, &path,
379 IB_MAD_ATTR_NODE_INFO, 0,
380 TRUE, 0,
381 CL_DISP_MSGID_NONE,
382 &context);
383
384 if (status != IB_SUCCESS)
385 OSM_LOG(sm->p_log, OSM_LOG_ERROR,
386 "ERR 0F02: "
387 "Failure initiating NodeInfo request (%s)\n",
388 ib_get_err_str(status));
389 } else
390 OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
391 "Skipping SMP responder port %u\n",
392 p_pi->local_port_num);
393 }
394 break;
395
396 default:
397 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F03: "
398 "Unknown link state = %u, port = %u\n",
399 ib_port_info_get_port_state(p_pi),
400 p_pi->local_port_num);
401 break;
402 }
403
404 if (ib_port_info_get_port_state(p_pi) > IB_LINK_INIT && p_node->sw &&
405 !ib_switch_info_get_state_change(&p_node->sw->switch_info) &&
406 p_node->sw->need_update == 1)
407 p_node->sw->need_update = 0;
408
409 if (p_physp->need_update)
410 sm->p_subn->ignore_existing_lfts = TRUE;
411
412 /*
413 Update the PortInfo attribute.
414 */
415 osm_physp_set_port_info(p_physp, p_pi, sm);
416
417 if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN)
418 goto Exit;
419
420 p_remote_physp = osm_physp_get_remote(p_physp);
421 if (p_remote_physp) {
422 p_remote_node = osm_physp_get_node_ptr(p_remote_physp);
423 if (p_remote_node->sw) {
424 data_vls = 1U << (ib_port_info_get_vl_cap(p_pi) - 1);
425 if (data_vls > 1U << (sm->p_subn->opt.max_op_vls - 1))
426 data_vls = 1U << (sm->p_subn->opt.max_op_vls - 1);
427 if (data_vls >= IB_MAX_NUM_VLS)
428 data_vls = IB_MAX_NUM_VLS - 1;
429 if ((uint8_t)data_vls < sm->p_subn->min_sw_data_vls) {
430 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
431 "Setting switch port minimal data VLs "
432 "to:%u defined by node:0x%"
433 PRIx64 ", port:%u\n", data_vls,
434 cl_ntoh64(osm_node_get_node_guid(p_node)),
435 port_num);
436 sm->p_subn->min_sw_data_vls = data_vls;
437 }
438 }
439 }
440
441 Exit:
442 OSM_LOG_EXIT(sm->p_log);
443 }
444
pi_rcv_process_ca_or_router_port(IN osm_sm_t * sm,IN osm_node_t * p_node,IN osm_physp_t * p_physp,IN ib_port_info_t * p_pi)445 static void pi_rcv_process_ca_or_router_port(IN osm_sm_t * sm,
446 IN osm_node_t * p_node,
447 IN osm_physp_t * p_physp,
448 IN ib_port_info_t * p_pi)
449 {
450 OSM_LOG_ENTER(sm->p_log);
451
452 UNUSED_PARAM(p_node);
453
454 pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp);
455
456 osm_physp_set_port_info(p_physp, p_pi, sm);
457
458 pi_rcv_process_endport(sm, p_physp, p_pi);
459
460 OSM_LOG_EXIT(sm->p_log);
461 }
462
463 #define IBM_VENDOR_ID (0x5076)
get_pkey_table(IN osm_log_t * p_log,IN osm_sm_t * sm,IN osm_node_t * p_node,IN osm_physp_t * p_physp)464 static void get_pkey_table(IN osm_log_t * p_log, IN osm_sm_t * sm,
465 IN osm_node_t * p_node, IN osm_physp_t * p_physp)
466 {
467
468 osm_madw_context_t context;
469 ib_api_status_t status;
470 osm_dr_path_t path;
471 osm_physp_t *physp0;
472 ib_net64_t m_key;
473 uint8_t port_num;
474 uint16_t block_num, max_blocks;
475 uint32_t attr_mod_ho;
476
477 OSM_LOG_ENTER(p_log);
478
479 path = *osm_physp_get_dr_path_ptr(p_physp);
480
481 context.pkey_context.node_guid = osm_node_get_node_guid(p_node);
482 context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp);
483 context.pkey_context.set_method = FALSE;
484
485 port_num = p_physp->port_num;
486
487 if (!p_node->sw || port_num == 0)
488 /* The maximum blocks is defined by the node info partition cap
489 for CA, router, and switch management ports. */
490 max_blocks =
491 (cl_ntoh16(p_node->node_info.partition_cap) +
492 IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1)
493 / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
494 else {
495 /* This is a switch, and not a management port. The maximum blocks
496 is defined in the switch info partition enforcement cap. */
497
498 /* Check for IBM eHCA firmware defect in reporting partition enforcement cap */
499 if (cl_ntoh32(ib_node_info_get_vendor_id(&p_node->node_info)) ==
500 IBM_VENDOR_ID)
501 p_node->sw->switch_info.enforce_cap = 0;
502
503 /* Bail out if this is a switch with no partition enforcement capability */
504 if (cl_ntoh16(p_node->sw->switch_info.enforce_cap) == 0)
505 goto Exit;
506
507 max_blocks = (cl_ntoh16(p_node->sw->switch_info.enforce_cap) +
508 IB_NUM_PKEY_ELEMENTS_IN_BLOCK -
509 1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
510 }
511
512 p_physp->pkeys.rcv_blocks_cnt = max_blocks;
513 for (block_num = 0; block_num < max_blocks; block_num++) {
514 if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH ||
515 osm_physp_get_port_num(p_physp) == 0) {
516 attr_mod_ho = block_num;
517 m_key = ib_port_info_get_m_key(&p_physp->port_info);
518 } else {
519 attr_mod_ho = block_num | (port_num << 16);
520 physp0 = osm_node_get_physp_ptr(p_node, 0);
521 m_key = ib_port_info_get_m_key(&physp0->port_info);
522 }
523 status = osm_req_get(sm, &path, IB_MAD_ATTR_P_KEY_TABLE,
524 cl_hton32(attr_mod_ho), FALSE,
525 m_key, CL_DISP_MSGID_NONE, &context);
526
527 if (status != IB_SUCCESS) {
528 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0F12: "
529 "Failure initiating PKeyTable request (%s)\n",
530 ib_get_err_str(status));
531 goto Exit;
532 }
533 }
534
535 Exit:
536 OSM_LOG_EXIT(p_log);
537 }
538
pi_rcv_get_pkey_slvl_vla_tables(IN osm_sm_t * sm,IN osm_node_t * p_node,IN osm_physp_t * p_physp)539 static void pi_rcv_get_pkey_slvl_vla_tables(IN osm_sm_t * sm,
540 IN osm_node_t * p_node,
541 IN osm_physp_t * p_physp)
542 {
543 OSM_LOG_ENTER(sm->p_log);
544
545 get_pkey_table(sm->p_log, sm, p_node, p_physp);
546
547 OSM_LOG_EXIT(sm->p_log);
548 }
549
osm_pi_rcv_update_self(IN osm_sm_t * sm,IN osm_physp_t * p_physp,IN ib_port_info_t * p_pi)550 static int osm_pi_rcv_update_self(IN osm_sm_t *sm, IN osm_physp_t *p_physp,
551 IN ib_port_info_t *p_pi)
552 {
553 if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN)
554 return 0;
555
556 if (sm->p_subn->need_update || p_physp->need_update > 1 ||
557 ib_port_info_get_port_state(p_pi) == IB_LINK_INIT)
558 return 1;
559
560 return 0;
561 }
562
pi_rcv_process_set(IN osm_sm_t * sm,IN osm_node_t * p_node,IN uint8_t port_num,IN osm_madw_t * p_madw)563 static void pi_rcv_process_set(IN osm_sm_t * sm, IN osm_node_t * p_node,
564 IN uint8_t port_num, IN osm_madw_t * p_madw)
565 {
566 osm_physp_t *p_physp;
567 ib_net64_t port_guid;
568 ib_smp_t *p_smp;
569 ib_port_info_t *p_pi;
570 osm_pi_context_t *p_context;
571 osm_log_level_t level;
572
573 OSM_LOG_ENTER(sm->p_log);
574
575 p_context = osm_madw_get_pi_context_ptr(p_madw);
576
577 CL_ASSERT(p_node);
578
579 p_physp = osm_node_get_physp_ptr(p_node, port_num);
580 CL_ASSERT(p_physp);
581
582 port_guid = osm_physp_get_port_guid(p_physp);
583
584 p_smp = osm_madw_get_smp_ptr(p_madw);
585 p_pi = ib_smp_get_payload_ptr(p_smp);
586
587 /* check for error */
588 if (cl_ntoh16(p_smp->status) & 0x7fff) {
589 /* If port already ACTIVE, don't treat status 7 as error */
590 if (p_context->active_transition &&
591 (cl_ntoh16(p_smp->status) & 0x7fff) == 0x1c) {
592 level = OSM_LOG_INFO;
593 OSM_LOG(sm->p_log, OSM_LOG_INFO,
594 "Received error status 0x%x for SetResp() during ACTIVE transition\n",
595 cl_ntoh16(p_smp->status) & 0x7fff);
596 /* Should there be a subsequent Get to validate that port is ACTIVE ? */
597 } else {
598 level = OSM_LOG_ERROR;
599 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F10: "
600 "Received error status for SetResp()\n");
601 }
602 osm_dump_port_info_v2(sm->p_log, osm_node_get_node_guid(p_node),
603 port_guid, port_num, p_pi, FILE_ID, level);
604 } else
605 osm_physp_set_port_info(p_physp, p_pi, sm);
606
607 OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
608 "Received logical SetResp() for GUID 0x%" PRIx64
609 ", port num %u"
610 "\n\t\t\t\tfor parent node GUID 0x%" PRIx64
611 " TID 0x%" PRIx64 "\n",
612 cl_ntoh64(port_guid), port_num,
613 cl_ntoh64(osm_node_get_node_guid(p_node)),
614 cl_ntoh64(p_smp->trans_id));
615
616
617 OSM_LOG_EXIT(sm->p_log);
618 }
619
osm_pi_rcv_update_neighbor(IN osm_physp_t * p_physp)620 static int osm_pi_rcv_update_neighbor(IN osm_physp_t *p_physp)
621 {
622 osm_physp_t *p_rem_physp = p_physp->p_remote_physp;
623 osm_node_t *p_node;
624
625 /*
626 * Our own port - this is the only case where CA port
627 * is discovered before its' neighbor port
628 */
629 if (!p_rem_physp)
630 return p_physp->need_update;
631
632 p_node = osm_physp_get_node_ptr(p_rem_physp);
633 CL_ASSERT(p_node);
634
635 /* CA/RTR to CA/RTR connection */
636 if (!p_node->sw)
637 return p_physp->need_update;
638
639 return (ib_switch_info_get_state_change(&p_node->sw->switch_info) ? 1 : p_physp->need_update);
640 }
641
osm_pi_rcv_process(IN void * context,IN void * data)642 void osm_pi_rcv_process(IN void *context, IN void *data)
643 {
644 osm_sm_t *sm = context;
645 osm_madw_t *p_madw = data;
646 ib_port_info_t *p_pi;
647 ib_smp_t *p_smp;
648 osm_port_t *p_port;
649 osm_physp_t *p_physp;
650 osm_dr_path_t *p_dr_path;
651 osm_node_t *p_node;
652 osm_pi_context_t *p_context;
653 ib_net64_t port_guid, node_guid;
654 uint8_t port_num;
655
656 CL_ASSERT(sm);
657
658 OSM_LOG_ENTER(sm->p_log);
659
660 CL_ASSERT(p_madw);
661
662 p_smp = osm_madw_get_smp_ptr(p_madw);
663 p_context = osm_madw_get_pi_context_ptr(p_madw);
664 p_pi = ib_smp_get_payload_ptr(p_smp);
665
666 CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_PORT_INFO);
667
668 /*
669 * Attribute modifier has already been validated upon MAD receive,
670 * which means that port_num has to be valid - it originated from
671 * the request attribute modifier.
672 */
673 port_num = (uint8_t) cl_ntoh32(p_smp->attr_mod);
674
675 port_guid = p_context->port_guid;
676 node_guid = p_context->node_guid;
677
678 osm_dump_port_info_v2(sm->p_log, node_guid, port_guid, port_num, p_pi,
679 FILE_ID, OSM_LOG_DEBUG);
680
681 /* On receipt of client reregister, clear the reregister bit so
682 reregistering won't be sent again and again */
683 if (p_context->set_method &&
684 (ib_port_info_get_client_rereg(p_pi) || p_context->client_rereg)) {
685 OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
686 "Client reregister received on response\n");
687 ib_port_info_set_client_rereg(p_pi, 0);
688 p_context->client_rereg = FALSE;
689 }
690
691 /*
692 we might get a response during a light sweep looking for a change in
693 the status of a remote port that did not respond in earlier sweeps.
694 So if the context of the Get was light_sweep - we do not need to
695 do anything with the response - just flag that we need a heavy sweep
696 */
697 if (p_context->light_sweep == TRUE) {
698 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
699 "Got light sweep response from remote port of parent node "
700 "GUID 0x%" PRIx64 " port 0x%016" PRIx64
701 ", Commencing heavy sweep\n",
702 cl_ntoh64(node_guid), cl_ntoh64(port_guid));
703 sm->p_subn->force_heavy_sweep = TRUE;
704 sm->p_subn->ignore_existing_lfts = TRUE;
705 goto Exit;
706 }
707
708 CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
709 p_port = osm_get_port_by_guid(sm->p_subn, port_guid);
710 if (PF(!p_port)) {
711 CL_PLOCK_RELEASE(sm->p_lock);
712 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F06: "
713 "No port object for port with GUID 0x%" PRIx64
714 "\n\t\t\t\tfor parent node GUID 0x%" PRIx64
715 ", TID 0x%" PRIx64 "\n",
716 cl_ntoh64(port_guid),
717 cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id));
718 goto Exit;
719 }
720
721 p_node = p_port->p_node;
722 CL_ASSERT(p_node);
723
724 if (PF(p_pi->local_port_num > p_node->node_info.num_ports)) {
725 CL_PLOCK_RELEASE(sm->p_lock);
726 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F15: "
727 "Received PortInfo for port GUID 0x%" PRIx64 " is "
728 "non-compliant and is being ignored since the "
729 "local port num %u > num ports %u\n",
730 cl_ntoh64(port_guid), p_pi->local_port_num,
731 p_node->node_info.num_ports);
732 goto Exit;
733 }
734
735 /*
736 If we were setting the PortInfo, then receiving
737 this attribute was not part of sweeping the subnet.
738 In this case, just update the PortInfo attribute.
739
740 In an unfortunate blunder, the IB spec defines the
741 return method for Set() as a GetResp(). Thus, we can't
742 use the method (what would have been SetResp()) to determine
743 our course of action. So, we have to carry this extra
744 boolean around to determine if we were doing Get() or Set().
745 */
746 if (p_context->set_method)
747 pi_rcv_process_set(sm, p_node, port_num, p_madw);
748 else {
749
750 /*
751 This PortInfo arrived because we did a Get() method,
752 most likely due to a subnet sweep in progress.
753 */
754 OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
755 "Discovered port num %u with GUID 0x%" PRIx64
756 " for parent node GUID 0x%" PRIx64
757 ", TID 0x%" PRIx64 "\n",
758 port_num, cl_ntoh64(port_guid),
759 cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id));
760
761 p_physp = osm_node_get_physp_ptr(p_node, port_num);
762
763 CL_ASSERT(p_physp);
764
765 /* Update the directed route path to this port
766 in case the old path is no longer usable. */
767 p_dr_path = osm_physp_get_dr_path_ptr(p_physp);
768 osm_dr_path_init(p_dr_path, p_smp->hop_count,
769 p_smp->initial_path);
770
771 p_physp->need_update = osm_pi_rcv_update_self(sm, p_physp, p_pi);
772
773 switch (osm_node_get_type(p_node)) {
774 case IB_NODE_TYPE_CA:
775 case IB_NODE_TYPE_ROUTER:
776 if (!p_node->physp_discovered[port_num]) {
777 p_port->discovery_count++;
778 p_node->physp_discovered[port_num] = 1;
779 }
780 p_physp->need_update = osm_pi_rcv_update_neighbor(p_physp);
781 pi_rcv_process_ca_or_router_port(sm, p_node, p_physp,
782 p_pi);
783 break;
784 case IB_NODE_TYPE_SWITCH:
785 if (!p_node->physp_discovered[port_num]) {
786 p_port->discovery_count++;
787 p_node->physp_discovered[port_num] = 1;
788 }
789 if (port_num == 0)
790 pi_rcv_process_switch_port0(sm, p_node,
791 p_physp, p_pi);
792 else
793 pi_rcv_process_switch_ext_port(sm, p_node,
794 p_physp, p_pi);
795 break;
796 default:
797 OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F07: "
798 "Unknown node type %u with GUID 0x%" PRIx64
799 "\n", osm_node_get_type(p_node),
800 cl_ntoh64(node_guid));
801 break;
802 }
803
804 /*
805 Get the tables on the physp.
806 */
807 if (p_physp->need_update || (p_node->sw &&
808 p_node->sw->need_update))
809 pi_rcv_get_pkey_slvl_vla_tables(sm, p_node, p_physp);
810
811 }
812
813 CL_PLOCK_RELEASE(sm->p_lock);
814
815 Exit:
816 /*
817 Release the lock before jumping here!!
818 */
819 OSM_LOG_EXIT(sm->p_log);
820 }
821