Blame opensm/osm_sa_link_record.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2007 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit 13e616
 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
Packit 13e616
 *
Packit 13e616
 * This software is available to you under a choice of one of two
Packit 13e616
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit 13e616
 * General Public License (GPL) Version 2, available from the file
Packit 13e616
 * COPYING in the main directory of this source tree, or the
Packit 13e616
 * OpenIB.org BSD license below:
Packit 13e616
 *
Packit 13e616
 *     Redistribution and use in source and binary forms, with or
Packit 13e616
 *     without modification, are permitted provided that the following
Packit 13e616
 *     conditions are met:
Packit 13e616
 *
Packit 13e616
 *      - Redistributions of source code must retain the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer.
Packit 13e616
 *
Packit 13e616
 *      - Redistributions in binary form must reproduce the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer in the documentation and/or other materials
Packit 13e616
 *        provided with the distribution.
Packit 13e616
 *
Packit 13e616
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 13e616
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 13e616
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 13e616
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit 13e616
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit 13e616
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 13e616
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit 13e616
 * SOFTWARE.
Packit 13e616
 *
Packit 13e616
 */
Packit 13e616
Packit 13e616
/*
Packit 13e616
 * Abstract:
Packit 13e616
 *    Implementation of osm_lr_rcv_t.
Packit 13e616
 * This object represents the LinkRecord Receiver object.
Packit 13e616
 * This object is part of the opensm family of objects.
Packit 13e616
 */
Packit 13e616
Packit 13e616
#if HAVE_CONFIG_H
Packit 13e616
#  include <config.h>
Packit 13e616
#endif				/* HAVE_CONFIG_H */
Packit 13e616
Packit 13e616
#include <string.h>
Packit 13e616
#include <iba/ib_types.h>
Packit 13e616
#include <complib/cl_qmap.h>
Packit 13e616
#include <complib/cl_debug.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_SA_LINK_RECORD_C
Packit 13e616
#include <vendor/osm_vendor_api.h>
Packit 13e616
#include <opensm/osm_node.h>
Packit 13e616
#include <opensm/osm_switch.h>
Packit 13e616
#include <opensm/osm_helper.h>
Packit 13e616
#include <opensm/osm_pkey.h>
Packit 13e616
#include <opensm/osm_sa.h>
Packit 13e616
Packit 13e616
#define SA_LR_RESP_SIZE SA_ITEM_RESP_SIZE(link_rec)
Packit 13e616
Packit 13e616
static void lr_rcv_build_physp_link(IN osm_sa_t * sa, IN ib_net16_t from_lid,
Packit 13e616
				    IN ib_net16_t to_lid, IN uint8_t from_port,
Packit 13e616
				    IN uint8_t to_port, IN cl_qlist_t * p_list)
Packit 13e616
{
Packit 13e616
	osm_sa_item_t *p_lr_item;
Packit 13e616
Packit 13e616
	p_lr_item = malloc(SA_LR_RESP_SIZE);
Packit 13e616
	if (p_lr_item == NULL) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1801: "
Packit 13e616
			"Unable to acquire link record\n"
Packit 13e616
			"\t\t\t\tFrom port %u\n" "\t\t\t\tTo port   %u\n"
Packit 13e616
			"\t\t\t\tFrom lid  %u\n" "\t\t\t\tTo lid    %u\n",
Packit 13e616
			from_port, to_port,
Packit 13e616
			cl_ntoh16(from_lid), cl_ntoh16(to_lid));
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
	memset(p_lr_item, 0, SA_LR_RESP_SIZE);
Packit 13e616
Packit 13e616
	p_lr_item->resp.link_rec.from_port_num = from_port;
Packit 13e616
	p_lr_item->resp.link_rec.to_port_num = to_port;
Packit 13e616
	p_lr_item->resp.link_rec.to_lid = to_lid;
Packit 13e616
	p_lr_item->resp.link_rec.from_lid = from_lid;
Packit 13e616
Packit 13e616
	cl_qlist_insert_tail(p_list, &p_lr_item->list_item);
Packit 13e616
}
Packit 13e616
Packit 13e616
static ib_net16_t get_base_lid(IN const osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
	if (p_physp->p_node->node_info.node_type == IB_NODE_TYPE_SWITCH)
Packit 13e616
		p_physp = osm_node_get_physp_ptr(p_physp->p_node, 0);
Packit 13e616
	return osm_physp_get_base_lid(p_physp);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void lr_rcv_get_physp_link(IN osm_sa_t * sa,
Packit 13e616
				  IN const ib_link_record_t * p_lr,
Packit 13e616
				  IN const osm_physp_t * p_src_physp,
Packit 13e616
				  IN const osm_physp_t * p_dest_physp,
Packit 13e616
				  IN const ib_net64_t comp_mask,
Packit 13e616
				  IN cl_qlist_t * p_list,
Packit 13e616
				  IN const osm_physp_t * p_req_physp)
Packit 13e616
{
Packit 13e616
	uint8_t src_port_num;
Packit 13e616
	uint8_t dest_port_num;
Packit 13e616
	ib_net16_t from_base_lid;
Packit 13e616
	ib_net16_t to_base_lid;
Packit 13e616
	ib_net16_t lmc_mask;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   If only one end of the link is specified, determine
Packit 13e616
	   the other side.
Packit 13e616
	 */
Packit 13e616
	if (p_src_physp) {
Packit 13e616
		if (p_dest_physp) {
Packit 13e616
			/*
Packit 13e616
			   Ensure the two physp's are actually connected.
Packit 13e616
			   If not, bail out.
Packit 13e616
			 */
Packit 13e616
			if (osm_physp_get_remote(p_src_physp) != p_dest_physp)
Packit 13e616
				goto Exit;
Packit 13e616
		} else {
Packit 13e616
			p_dest_physp = osm_physp_get_remote(p_src_physp);
Packit 13e616
			if (p_dest_physp == NULL)
Packit 13e616
				goto Exit;
Packit 13e616
		}
Packit 13e616
	} else {
Packit 13e616
		if (p_dest_physp) {
Packit 13e616
			p_src_physp = osm_physp_get_remote(p_dest_physp);
Packit 13e616
			if (p_src_physp == NULL)
Packit 13e616
				goto Exit;
Packit 13e616
		} else
Packit 13e616
			goto Exit;	/* no physp's, so nothing to do */
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Check that the p_src_physp, p_dest_physp and p_req_physp
Packit 13e616
	   all share a pkey (doesn't have to be the same p_key). */
Packit 13e616
	if (!osm_physp_share_pkey(sa->p_log, p_src_physp, p_dest_physp,
Packit 13e616
				  sa->p_subn->opt.allow_both_pkeys)) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Source and Dest PhysPorts do not share PKey\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
	if (!osm_physp_share_pkey(sa->p_log, p_src_physp, p_req_physp,
Packit 13e616
				  sa->p_subn->opt.allow_both_pkeys)) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Source and Requester PhysPorts do not share PKey\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
	if (!osm_physp_share_pkey(sa->p_log, p_req_physp, p_dest_physp,
Packit 13e616
				  sa->p_subn->opt.allow_both_pkeys)) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Requester and Dest PhysPorts do not share PKey\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	src_port_num = osm_physp_get_port_num(p_src_physp);
Packit 13e616
	dest_port_num = osm_physp_get_port_num(p_dest_physp);
Packit 13e616
Packit 13e616
	if (comp_mask & IB_LR_COMPMASK_FROM_PORT)
Packit 13e616
		if (src_port_num != p_lr->from_port_num)
Packit 13e616
			goto Exit;
Packit 13e616
Packit 13e616
	if (comp_mask & IB_LR_COMPMASK_TO_PORT)
Packit 13e616
		if (dest_port_num != p_lr->to_port_num)
Packit 13e616
			goto Exit;
Packit 13e616
Packit 13e616
	from_base_lid = get_base_lid(p_src_physp);
Packit 13e616
	to_base_lid = get_base_lid(p_dest_physp);
Packit 13e616
Packit 13e616
	lmc_mask = ~((1 << sa->p_subn->opt.lmc) - 1);
Packit 13e616
	lmc_mask = cl_hton16(lmc_mask);
Packit 13e616
Packit 13e616
	if (comp_mask & IB_LR_COMPMASK_FROM_LID)
Packit 13e616
		if (from_base_lid != (p_lr->from_lid & lmc_mask))
Packit 13e616
			goto Exit;
Packit 13e616
Packit 13e616
	if (comp_mask & IB_LR_COMPMASK_TO_LID)
Packit 13e616
		if (to_base_lid != (p_lr->to_lid & lmc_mask))
Packit 13e616
			goto Exit;
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Acquiring link record\n"
Packit 13e616
		"\t\t\t\tsrc port 0x%" PRIx64 " (port %u)"
Packit 13e616
		", dest port 0x%" PRIx64 " (port %u)\n",
Packit 13e616
		cl_ntoh64(osm_physp_get_port_guid(p_src_physp)), src_port_num,
Packit 13e616
		cl_ntoh64(osm_physp_get_port_guid(p_dest_physp)),
Packit 13e616
		dest_port_num);
Packit 13e616
Packit 13e616
	lr_rcv_build_physp_link(sa, from_base_lid, to_base_lid, src_port_num,
Packit 13e616
				dest_port_num, p_list);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void lr_rcv_get_port_links(IN osm_sa_t * sa,
Packit 13e616
				  IN const ib_link_record_t * p_lr,
Packit 13e616
				  IN const osm_port_t * p_src_port,
Packit 13e616
				  IN const osm_port_t * p_dest_port,
Packit 13e616
				  IN const ib_net64_t comp_mask,
Packit 13e616
				  IN cl_qlist_t * p_list,
Packit 13e616
				  IN const osm_physp_t * p_req_physp)
Packit 13e616
{
Packit 13e616
	const osm_physp_t *p_src_physp;
Packit 13e616
	const osm_physp_t *p_dest_physp;
Packit 13e616
	const cl_qmap_t *p_node_tbl;
Packit 13e616
	osm_node_t *p_node;
Packit 13e616
	uint8_t port_num;
Packit 13e616
	uint8_t num_ports;
Packit 13e616
	uint8_t dest_num_ports;
Packit 13e616
	uint8_t dest_port_num;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	if (p_src_port) {
Packit 13e616
		if (p_dest_port) {
Packit 13e616
			/*
Packit 13e616
			   Build an LR for every link connected between both ports.
Packit 13e616
			   The inner function will discard physp combinations
Packit 13e616
			   that do not actually connect.  Don't bother screening
Packit 13e616
			   for that here.
Packit 13e616
			 */
Packit 13e616
			num_ports = osm_node_get_num_physp(p_src_port->p_node);
Packit 13e616
			dest_num_ports =
Packit 13e616
			    osm_node_get_num_physp(p_dest_port->p_node);
Packit 13e616
			for (port_num = 1; port_num < num_ports; port_num++) {
Packit 13e616
				p_src_physp =
Packit 13e616
				    osm_node_get_physp_ptr(p_src_port->p_node,
Packit 13e616
							   port_num);
Packit 13e616
				for (dest_port_num = 1;
Packit 13e616
				     dest_port_num < dest_num_ports;
Packit 13e616
				     dest_port_num++) {
Packit 13e616
					p_dest_physp =
Packit 13e616
					    osm_node_get_physp_ptr(p_dest_port->
Packit 13e616
								   p_node,
Packit 13e616
								   dest_port_num);
Packit 13e616
					/* both physical ports should be with data */
Packit 13e616
					if (p_src_physp && p_dest_physp)
Packit 13e616
						lr_rcv_get_physp_link
Packit 13e616
						    (sa, p_lr, p_src_physp,
Packit 13e616
						     p_dest_physp, comp_mask,
Packit 13e616
						     p_list, p_req_physp);
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
		} else {
Packit 13e616
			/*
Packit 13e616
			   Build an LR for every link connected from the source port.
Packit 13e616
			 */
Packit 13e616
			if (comp_mask & IB_LR_COMPMASK_FROM_PORT) {
Packit 13e616
				port_num = p_lr->from_port_num;
Packit 13e616
				/* If the port number is out of the range of the p_src_port, then
Packit 13e616
				   this couldn't be a relevant record. */
Packit 13e616
				if (port_num <
Packit 13e616
				    p_src_port->p_node->physp_tbl_size) {
Packit 13e616
					p_src_physp =
Packit 13e616
					    osm_node_get_physp_ptr(p_src_port->
Packit 13e616
								   p_node,
Packit 13e616
								   port_num);
Packit 13e616
					if (p_src_physp)
Packit 13e616
						lr_rcv_get_physp_link
Packit 13e616
						    (sa, p_lr, p_src_physp,
Packit 13e616
						     NULL, comp_mask, p_list,
Packit 13e616
						     p_req_physp);
Packit 13e616
				}
Packit 13e616
			} else {
Packit 13e616
				num_ports =
Packit 13e616
				    osm_node_get_num_physp(p_src_port->p_node);
Packit 13e616
				for (port_num = 1; port_num < num_ports;
Packit 13e616
				     port_num++) {
Packit 13e616
					p_src_physp =
Packit 13e616
					    osm_node_get_physp_ptr(p_src_port->
Packit 13e616
								   p_node,
Packit 13e616
								   port_num);
Packit 13e616
					if (p_src_physp)
Packit 13e616
						lr_rcv_get_physp_link
Packit 13e616
						    (sa, p_lr, p_src_physp,
Packit 13e616
						     NULL, comp_mask, p_list,
Packit 13e616
						     p_req_physp);
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
	} else {
Packit 13e616
		if (p_dest_port) {
Packit 13e616
			/*
Packit 13e616
			   Build an LR for every link connected to the dest port.
Packit 13e616
			 */
Packit 13e616
			if (comp_mask & IB_LR_COMPMASK_TO_PORT) {
Packit 13e616
				port_num = p_lr->to_port_num;
Packit 13e616
				/* If the port number is out of the range of the p_dest_port, then
Packit 13e616
				   this couldn't be a relevant record. */
Packit 13e616
				if (port_num <
Packit 13e616
				    p_dest_port->p_node->physp_tbl_size) {
Packit 13e616
					p_dest_physp =
Packit 13e616
					    osm_node_get_physp_ptr(p_dest_port->
Packit 13e616
								   p_node,
Packit 13e616
								   port_num);
Packit 13e616
					if (p_dest_physp)
Packit 13e616
						lr_rcv_get_physp_link
Packit 13e616
						    (sa, p_lr, NULL,
Packit 13e616
						     p_dest_physp, comp_mask,
Packit 13e616
						     p_list, p_req_physp);
Packit 13e616
				}
Packit 13e616
			} else {
Packit 13e616
				num_ports =
Packit 13e616
				    osm_node_get_num_physp(p_dest_port->p_node);
Packit 13e616
				for (port_num = 1; port_num < num_ports;
Packit 13e616
				     port_num++) {
Packit 13e616
					p_dest_physp =
Packit 13e616
					    osm_node_get_physp_ptr(p_dest_port->
Packit 13e616
								   p_node,
Packit 13e616
								   port_num);
Packit 13e616
					if (p_dest_physp)
Packit 13e616
						lr_rcv_get_physp_link
Packit 13e616
						    (sa, p_lr, NULL,
Packit 13e616
						     p_dest_physp, comp_mask,
Packit 13e616
						     p_list, p_req_physp);
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
		} else {
Packit 13e616
			/*
Packit 13e616
			   Process the world (recurse once back into this function).
Packit 13e616
			 */
Packit 13e616
			p_node_tbl = &sa->p_subn->node_guid_tbl;
Packit 13e616
			p_node = (osm_node_t *) cl_qmap_head(p_node_tbl);
Packit 13e616
Packit 13e616
			while (p_node != (osm_node_t *) cl_qmap_end(p_node_tbl)) {
Packit 13e616
				num_ports = osm_node_get_num_physp(p_node);
Packit 13e616
				for (port_num = 1; port_num < num_ports;
Packit 13e616
				     port_num++) {
Packit 13e616
					p_src_physp =
Packit 13e616
					    osm_node_get_physp_ptr(p_node,
Packit 13e616
								   port_num);
Packit 13e616
					if (p_src_physp)
Packit 13e616
						lr_rcv_get_physp_link
Packit 13e616
						    (sa, p_lr, p_src_physp,
Packit 13e616
						     NULL, comp_mask, p_list,
Packit 13e616
						     p_req_physp);
Packit 13e616
				}
Packit 13e616
				p_node = (osm_node_t *) cl_qmap_next(&p_node->
Packit 13e616
								     map_item);
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Returns the SA status to return to the client.
Packit 13e616
 **********************************************************************/
Packit 13e616
static ib_net16_t lr_rcv_get_end_points(IN osm_sa_t * sa,
Packit 13e616
					IN const osm_madw_t * p_madw,
Packit 13e616
					OUT const osm_port_t ** pp_src_port,
Packit 13e616
					OUT const osm_port_t ** pp_dest_port)
Packit 13e616
{
Packit 13e616
	const ib_link_record_t *p_lr;
Packit 13e616
	const ib_sa_mad_t *p_sa_mad;
Packit 13e616
	ib_net64_t comp_mask;
Packit 13e616
	ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Determine what fields are valid and then get a pointer
Packit 13e616
	   to the source and destination port objects, if possible.
Packit 13e616
	 */
Packit 13e616
	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
Packit 13e616
	p_lr = (ib_link_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
Packit 13e616
Packit 13e616
	comp_mask = p_sa_mad->comp_mask;
Packit 13e616
	*pp_src_port = NULL;
Packit 13e616
	*pp_dest_port = NULL;
Packit 13e616
Packit 13e616
	if (comp_mask & IB_LR_COMPMASK_FROM_LID) {
Packit 13e616
		*pp_src_port = osm_get_port_by_lid(sa->p_subn, p_lr->from_lid);
Packit 13e616
		if (!*pp_src_port) {
Packit 13e616
			/*
Packit 13e616
			   This 'error' is the client's fault (bad lid) so
Packit 13e616
			   don't enter it as an error in our own log.
Packit 13e616
			   Return an error response to the client.
Packit 13e616
			 */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"No source port with LID %u\n",
Packit 13e616
				cl_ntoh16(p_lr->from_lid));
Packit 13e616
Packit 13e616
			sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (comp_mask & IB_LR_COMPMASK_TO_LID) {
Packit 13e616
		*pp_dest_port = osm_get_port_by_lid(sa->p_subn, p_lr->to_lid);
Packit 13e616
		if (!*pp_dest_port) {
Packit 13e616
			/*
Packit 13e616
			   This 'error' is the client's fault (bad lid) so
Packit 13e616
			   don't enter it as an error in our own log.
Packit 13e616
			   Return an error response to the client.
Packit 13e616
			 */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"No dest port with LID %u\n",
Packit 13e616
				cl_ntoh16(p_lr->to_lid));
Packit 13e616
Packit 13e616
			sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return sa_status;
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_lr_rcv_process(IN void *context, IN void *data)
Packit 13e616
{
Packit 13e616
	osm_sa_t *sa = context;
Packit 13e616
	osm_madw_t *p_madw = data;
Packit 13e616
	const ib_link_record_t *p_lr;
Packit 13e616
	const ib_sa_mad_t *p_sa_mad;
Packit 13e616
	const osm_port_t *p_src_port;
Packit 13e616
	const osm_port_t *p_dest_port;
Packit 13e616
	cl_qlist_t lr_list;
Packit 13e616
	ib_net16_t status;
Packit 13e616
	osm_physp_t *p_req_physp;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_madw);
Packit 13e616
Packit 13e616
	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
Packit 13e616
	p_lr = ib_sa_mad_get_payload_ptr(p_sa_mad);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_LINK_RECORD);
Packit 13e616
Packit 13e616
	/* we only support SubnAdmGet and SubnAdmGetTable methods */
Packit 13e616
	if (p_sa_mad->method != IB_MAD_METHOD_GET &&
Packit 13e616
	    p_sa_mad->method != IB_MAD_METHOD_GETTABLE) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1804: "
Packit 13e616
			"Unsupported Method (%s) for LinkRecord request\n",
Packit 13e616
			ib_get_sa_method_str(p_sa_mad->method));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	cl_plock_acquire(sa->p_lock);
Packit 13e616
Packit 13e616
	/* update the requester physical port */
Packit 13e616
	p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
Packit 13e616
						osm_madw_get_mad_addr_ptr
Packit 13e616
						(p_madw));
Packit 13e616
	if (p_req_physp == NULL) {
Packit 13e616
		cl_plock_release(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1805: "
Packit 13e616
			"Cannot find requester physical port\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Requester port GUID 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
Packit 13e616
		osm_dump_link_record_v2(sa->p_log, p_lr, FILE_ID, OSM_LOG_DEBUG);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	cl_qlist_init(&lr_list);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Most SA functions (including this one) are read-only on the
Packit 13e616
	   subnet object, so we grab the lock non-exclusively.
Packit 13e616
	 */
Packit 13e616
	status = lr_rcv_get_end_points(sa, p_madw, &p_src_port, &p_dest_port);
Packit 13e616
Packit 13e616
	if (status == IB_SA_MAD_STATUS_SUCCESS)
Packit 13e616
		lr_rcv_get_port_links(sa, p_lr, p_src_port, p_dest_port,
Packit 13e616
				      p_sa_mad->comp_mask, &lr_list,
Packit 13e616
				      p_req_physp);
Packit 13e616
Packit 13e616
	cl_plock_release(sa->p_lock);
Packit 13e616
Packit 13e616
	osm_sa_respond(sa, p_madw, sizeof(ib_link_record_t), &lr_list);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}