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_lr_rcv_t.
39 * This object represents the LinkRecord Receiver object.
40 * This object is part of the opensm family of objects.
45 #endif /* HAVE_CONFIG_H */
48 #include <iba/ib_types.h>
49 #include <complib/cl_qmap.h>
50 #include <complib/cl_debug.h>
51 #include <vendor/osm_vendor_api.h>
52 #include <opensm/osm_node.h>
53 #include <opensm/osm_switch.h>
54 #include <opensm/osm_helper.h>
55 #include <opensm/osm_pkey.h>
56 #include <opensm/osm_sa.h>
58 typedef struct osm_lr_item {
59 cl_list_item_t list_item;
60 ib_link_record_t link_rec;
63 /**********************************************************************
64 **********************************************************************/
66 __osm_lr_rcv_build_physp_link(IN osm_sa_t * sa,
67 IN const ib_net16_t from_lid,
68 IN const ib_net16_t to_lid,
69 IN const uint8_t from_port,
70 IN const uint8_t to_port, IN cl_qlist_t * p_list)
72 osm_lr_item_t *p_lr_item;
74 p_lr_item = malloc(sizeof(*p_lr_item));
75 if (p_lr_item == NULL) {
76 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1801: "
77 "Unable to acquire link record\n"
78 "\t\t\t\tFrom port %u\n"
79 "\t\t\t\tTo port %u\n"
80 "\t\t\t\tFrom lid %u\n"
81 "\t\t\t\tTo lid %u\n",
83 cl_ntoh16(from_lid), cl_ntoh16(to_lid));
86 memset(p_lr_item, 0, sizeof(*p_lr_item));
88 p_lr_item->link_rec.from_port_num = from_port;
89 p_lr_item->link_rec.to_port_num = to_port;
90 p_lr_item->link_rec.to_lid = to_lid;
91 p_lr_item->link_rec.from_lid = from_lid;
93 cl_qlist_insert_tail(p_list, &p_lr_item->list_item);
96 /**********************************************************************
97 **********************************************************************/
99 __get_base_lid(IN const osm_physp_t * p_physp, OUT ib_net16_t * p_base_lid)
101 if (p_physp->p_node->node_info.node_type == IB_NODE_TYPE_SWITCH)
102 *p_base_lid = osm_physp_get_base_lid
103 (osm_node_get_physp_ptr(p_physp->p_node, 0));
105 *p_base_lid = osm_physp_get_base_lid(p_physp);
108 /**********************************************************************
109 **********************************************************************/
111 __osm_lr_rcv_get_physp_link(IN osm_sa_t * sa,
112 IN const ib_link_record_t * const p_lr,
113 IN const osm_physp_t * p_src_physp,
114 IN const osm_physp_t * p_dest_physp,
115 IN const ib_net64_t comp_mask,
116 IN cl_qlist_t * const p_list,
117 IN const osm_physp_t * p_req_physp)
119 uint8_t src_port_num;
120 uint8_t dest_port_num;
121 ib_net16_t from_base_lid;
122 ib_net16_t to_base_lid;
125 OSM_LOG_ENTER(sa->p_log);
128 If only one end of the link is specified, determine
134 Ensure the two physp's are actually connected.
137 if (osm_physp_get_remote(p_src_physp) != p_dest_physp)
140 p_dest_physp = osm_physp_get_remote(p_src_physp);
141 if (p_dest_physp == NULL)
146 p_src_physp = osm_physp_get_remote(p_dest_physp);
147 if (p_src_physp == NULL)
150 goto Exit; /* no physp's, so nothing to do */
153 /* Check that the p_src_physp, p_dest_physp and p_req_physp
154 all share a pkey (doesn't have to be the same p_key). */
155 if (!osm_physp_share_pkey(sa->p_log, p_src_physp, p_dest_physp)) {
156 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
157 "Source and Dest PhysPorts do not share PKey\n");
160 if (!osm_physp_share_pkey(sa->p_log, p_src_physp, p_req_physp)) {
161 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
162 "Source and Requester PhysPorts do not share PKey\n");
165 if (!osm_physp_share_pkey(sa->p_log, p_req_physp, p_dest_physp)) {
166 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
167 "Requester and Dest PhysPorts do not share PKey\n");
171 src_port_num = osm_physp_get_port_num(p_src_physp);
172 dest_port_num = osm_physp_get_port_num(p_dest_physp);
174 if (comp_mask & IB_LR_COMPMASK_FROM_PORT)
175 if (src_port_num != p_lr->from_port_num)
178 if (comp_mask & IB_LR_COMPMASK_TO_PORT)
179 if (dest_port_num != p_lr->to_port_num)
182 __get_base_lid(p_src_physp, &from_base_lid);
183 __get_base_lid(p_dest_physp, &to_base_lid);
185 lmc_mask = ~((1 << sa->p_subn->opt.lmc) - 1);
186 lmc_mask = cl_hton16(lmc_mask);
188 if (comp_mask & IB_LR_COMPMASK_FROM_LID)
189 if (from_base_lid != (p_lr->from_lid & lmc_mask))
192 if (comp_mask & IB_LR_COMPMASK_TO_LID)
193 if (to_base_lid != (p_lr->to_lid & lmc_mask))
196 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Acquiring link record\n"
197 "\t\t\t\tsrc port 0x%" PRIx64 " (port %u)"
198 ", dest port 0x%" PRIx64 " (port %u)\n",
199 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)), src_port_num,
200 cl_ntoh64(osm_physp_get_port_guid(p_dest_physp)),
204 __osm_lr_rcv_build_physp_link(sa, from_base_lid, to_base_lid,
205 src_port_num, dest_port_num, p_list);
208 OSM_LOG_EXIT(sa->p_log);
211 /**********************************************************************
212 **********************************************************************/
214 __osm_lr_rcv_get_port_links(IN osm_sa_t * sa,
215 IN const ib_link_record_t * const p_lr,
216 IN const osm_port_t * p_src_port,
217 IN const osm_port_t * p_dest_port,
218 IN const ib_net64_t comp_mask,
219 IN cl_qlist_t * const p_list,
220 IN const osm_physp_t * p_req_physp)
222 const osm_physp_t *p_src_physp;
223 const osm_physp_t *p_dest_physp;
224 const cl_qmap_t *p_node_tbl;
228 uint8_t dest_num_ports;
229 uint8_t dest_port_num;
231 OSM_LOG_ENTER(sa->p_log);
236 Build an LR for every link connected between both ports.
237 The inner function will discard physp combinations
238 that do not actually connect. Don't bother screening
241 num_ports = osm_node_get_num_physp(p_src_port->p_node);
243 osm_node_get_num_physp(p_dest_port->p_node);
244 for (port_num = 1; port_num < num_ports; port_num++) {
246 osm_node_get_physp_ptr(p_src_port->p_node,
248 for (dest_port_num = 1;
249 dest_port_num < dest_num_ports;
252 osm_node_get_physp_ptr(p_dest_port->
255 /* both physical ports should be with data */
256 if (p_src_physp && p_dest_physp)
257 __osm_lr_rcv_get_physp_link
258 (sa, p_lr, p_src_physp,
259 p_dest_physp, comp_mask,
260 p_list, p_req_physp);
265 Build an LR for every link connected from the source port.
267 if (comp_mask & IB_LR_COMPMASK_FROM_PORT) {
268 port_num = p_lr->from_port_num;
269 /* If the port number is out of the range of the p_src_port, then
270 this couldn't be a relevant record. */
272 p_src_port->p_node->physp_tbl_size) {
274 osm_node_get_physp_ptr(p_src_port->
278 __osm_lr_rcv_get_physp_link
279 (sa, p_lr, p_src_physp,
280 NULL, comp_mask, p_list,
285 osm_node_get_num_physp(p_src_port->p_node);
286 for (port_num = 1; port_num < num_ports;
289 osm_node_get_physp_ptr(p_src_port->
293 __osm_lr_rcv_get_physp_link
294 (sa, p_lr, p_src_physp,
295 NULL, comp_mask, p_list,
303 Build an LR for every link connected to the dest port.
305 if (comp_mask & IB_LR_COMPMASK_TO_PORT) {
306 port_num = p_lr->to_port_num;
307 /* If the port number is out of the range of the p_dest_port, then
308 this couldn't be a relevant record. */
310 p_dest_port->p_node->physp_tbl_size) {
312 osm_node_get_physp_ptr(p_dest_port->
316 __osm_lr_rcv_get_physp_link
318 p_dest_physp, comp_mask,
319 p_list, p_req_physp);
323 osm_node_get_num_physp(p_dest_port->p_node);
324 for (port_num = 1; port_num < num_ports;
327 osm_node_get_physp_ptr(p_dest_port->
331 __osm_lr_rcv_get_physp_link
333 p_dest_physp, comp_mask,
334 p_list, p_req_physp);
339 Process the world (recurse once back into this function).
341 p_node_tbl = &sa->p_subn->node_guid_tbl;
342 p_node = (osm_node_t *)cl_qmap_head(p_node_tbl);
344 while (p_node != (osm_node_t *)cl_qmap_end(p_node_tbl)) {
345 num_ports = osm_node_get_num_physp(p_node);
346 for (port_num = 1; port_num < num_ports;
349 osm_node_get_physp_ptr(p_node,
352 __osm_lr_rcv_get_physp_link
353 (sa, p_lr, p_src_physp,
354 NULL, comp_mask, p_list,
357 p_node = (osm_node_t *) cl_qmap_next(&p_node->
363 OSM_LOG_EXIT(sa->p_log);
366 /**********************************************************************
367 Returns the SA status to return to the client.
368 **********************************************************************/
370 __osm_lr_rcv_get_end_points(IN osm_sa_t * sa,
371 IN const osm_madw_t * const p_madw,
372 OUT const osm_port_t ** const pp_src_port,
373 OUT const osm_port_t ** const pp_dest_port)
375 const ib_link_record_t *p_lr;
376 const ib_sa_mad_t *p_sa_mad;
377 ib_net64_t comp_mask;
378 ib_api_status_t status;
379 ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
381 OSM_LOG_ENTER(sa->p_log);
384 Determine what fields are valid and then get a pointer
385 to the source and destination port objects, if possible.
387 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
388 p_lr = (ib_link_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
390 comp_mask = p_sa_mad->comp_mask;
392 *pp_dest_port = NULL;
394 if (p_sa_mad->comp_mask & IB_LR_COMPMASK_FROM_LID) {
395 status = osm_get_port_by_base_lid(sa->p_subn,
396 p_lr->from_lid, pp_src_port);
398 if ((status != IB_SUCCESS) || (*pp_src_port == NULL)) {
400 This 'error' is the client's fault (bad lid) so
401 don't enter it as an error in our own log.
402 Return an error response to the client.
404 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
405 "No source port with LID %u\n",
406 cl_ntoh16(p_lr->from_lid));
408 sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
413 if (p_sa_mad->comp_mask & IB_LR_COMPMASK_TO_LID) {
414 status = osm_get_port_by_base_lid(sa->p_subn,
415 p_lr->to_lid, pp_dest_port);
417 if ((status != IB_SUCCESS) || (*pp_dest_port == NULL)) {
419 This 'error' is the client's fault (bad lid) so
420 don't enter it as an error in our own log.
421 Return an error response to the client.
423 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
424 "No dest port with LID %u\n",
425 cl_ntoh16(p_lr->to_lid));
427 sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
433 OSM_LOG_EXIT(sa->p_log);
437 /**********************************************************************
438 **********************************************************************/
439 void osm_lr_rcv_process(IN void *context, IN void *data)
441 osm_sa_t *sa = context;
442 osm_madw_t *p_madw = data;
443 const ib_link_record_t *p_lr;
444 const ib_sa_mad_t *p_sa_mad;
445 const osm_port_t *p_src_port;
446 const osm_port_t *p_dest_port;
448 ib_net16_t sa_status;
449 osm_physp_t *p_req_physp;
451 OSM_LOG_ENTER(sa->p_log);
455 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
456 p_lr = (ib_link_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
458 CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_LINK_RECORD);
460 /* we only support SubnAdmGet and SubnAdmGetTable methods */
461 if (p_sa_mad->method != IB_MAD_METHOD_GET &&
462 p_sa_mad->method != IB_MAD_METHOD_GETTABLE) {
463 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1804: "
464 "Unsupported Method (%s)\n",
465 ib_get_sa_method_str(p_sa_mad->method));
466 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
470 /* update the requester physical port. */
471 p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
472 osm_madw_get_mad_addr_ptr
474 if (p_req_physp == NULL) {
475 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1805: "
476 "Cannot find requester physical port\n");
480 if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG))
481 osm_dump_link_record(sa->p_log, p_lr, OSM_LOG_DEBUG);
483 cl_qlist_init(&lr_list);
486 Most SA functions (including this one) are read-only on the
487 subnet object, so we grab the lock non-exclusively.
489 cl_plock_acquire(sa->p_lock);
491 sa_status = __osm_lr_rcv_get_end_points(sa, p_madw,
492 &p_src_port, &p_dest_port);
494 if (sa_status == IB_SA_MAD_STATUS_SUCCESS)
495 __osm_lr_rcv_get_port_links(sa, p_lr, p_src_port,
496 p_dest_port, p_sa_mad->comp_mask,
497 &lr_list, p_req_physp);
499 cl_plock_release(sa->p_lock);
501 osm_sa_respond(sa, p_madw, sizeof(ib_link_record_t), &lr_list);
504 OSM_LOG_EXIT(sa->p_log);