Blame opensm/osm_node_info_rcv.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit 13e616
 * Copyright (c) 2009 HNR Consulting. 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_ni_rcv_t.
Packit 13e616
 * This object represents the NodeInfo 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 <stdlib.h>
Packit 13e616
#include <string.h>
Packit 13e616
#include <iba/ib_types.h>
Packit 13e616
#include <complib/cl_qmap.h>
Packit 13e616
#include <complib/cl_passivelock.h>
Packit 13e616
#include <complib/cl_debug.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_NODE_INFO_RCV_C
Packit 13e616
#include <opensm/osm_madw.h>
Packit 13e616
#include <opensm/osm_log.h>
Packit 13e616
#include <opensm/osm_node.h>
Packit 13e616
#include <opensm/osm_subnet.h>
Packit 13e616
#include <opensm/osm_router.h>
Packit 13e616
#include <opensm/osm_mad_pool.h>
Packit 13e616
#include <opensm/osm_helper.h>
Packit 13e616
#include <opensm/osm_msgdef.h>
Packit 13e616
#include <opensm/osm_opensm.h>
Packit 13e616
#include <opensm/osm_ucast_mgr.h>
Packit 13e616
#include <opensm/osm_db_pack.h>
Packit 13e616
Packit 13e616
static void report_duplicated_guid(IN osm_sm_t * sm, osm_physp_t * p_physp,
Packit 13e616
				   osm_node_t * p_neighbor_node,
Packit 13e616
				   const uint8_t port_num)
Packit 13e616
{
Packit 13e616
	osm_physp_t *p_old, *p_new;
Packit 13e616
	osm_dr_path_t path;
Packit 13e616
Packit 13e616
	p_old = p_physp->p_remote_physp;
Packit 13e616
	p_new = osm_node_get_physp_ptr(p_neighbor_node, port_num);
Packit 13e616
Packit 13e616
	OSM_LOG(sm->p_log, OSM_LOG_SYS | OSM_LOG_ERROR, "ERR 0D01: "
Packit 13e616
		"Found duplicated node GUID.\n"
Packit 13e616
		"Node 0x%" PRIx64 " port %u is reachable from remote node "
Packit 13e616
		"0x%" PRIx64 " port %u and remote node 0x%" PRIx64 " port %u.\n"
Packit 13e616
		"Paths are:\n",
Packit 13e616
		cl_ntoh64(p_physp->p_node->node_info.node_guid),
Packit 13e616
		p_physp->port_num,
Packit 13e616
		p_old ? cl_ntoh64(p_old->p_node->node_info.node_guid) : 0,
Packit 13e616
		p_old ? p_old->port_num : 0,
Packit 13e616
		p_new ? cl_ntoh64(p_new->p_node->node_info.node_guid) : 0,
Packit 13e616
		p_new ? p_new->port_num : 0);
Packit 13e616
Packit 13e616
	osm_dump_dr_path_v2(sm->p_log, osm_physp_get_dr_path_ptr(p_physp),
Packit 13e616
			    FILE_ID, OSM_LOG_ERROR);
Packit 13e616
Packit 13e616
	path = *osm_physp_get_dr_path_ptr(p_new);
Packit 13e616
	if (osm_dr_path_extend(&path, port_num))
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D05: "
Packit 13e616
			"DR path with hop count %d couldn't be extended\n",
Packit 13e616
			path.hop_count);
Packit 13e616
	osm_dump_dr_path_v2(sm->p_log, &path, FILE_ID, OSM_LOG_ERROR);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void requery_dup_node_info(IN osm_sm_t * sm, osm_physp_t * p_physp,
Packit 13e616
				  unsigned count)
Packit 13e616
{
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
	osm_dr_path_t path;
Packit 13e616
	cl_status_t status;
Packit 13e616
Packit 13e616
	if (!p_physp->p_remote_physp) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D0D: "
Packit 13e616
			"DR path couldn't be extended due to NULL remote physp\n");
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	path = *osm_physp_get_dr_path_ptr(p_physp->p_remote_physp);
Packit 13e616
	if (osm_dr_path_extend(&path, p_physp->p_remote_physp->port_num)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D08: "
Packit 13e616
			"DR path with hop count %d couldn't be extended\n",
Packit 13e616
			path.hop_count);
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	context.ni_context.node_guid =
Packit 13e616
	    p_physp->p_remote_physp->p_node->node_info.port_guid;
Packit 13e616
	context.ni_context.port_num = p_physp->p_remote_physp->port_num;
Packit 13e616
	context.ni_context.dup_node_guid = p_physp->p_node->node_info.node_guid;
Packit 13e616
	context.ni_context.dup_port_num = p_physp->port_num;
Packit 13e616
	context.ni_context.dup_count = count;
Packit 13e616
Packit 13e616
	status = osm_req_get(sm, &path, IB_MAD_ATTR_NODE_INFO, 0,
Packit 13e616
			     TRUE, 0, 0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D02: "
Packit 13e616
			"Failure initiating NodeInfo request (%s)\n",
Packit 13e616
			ib_get_err_str(status));
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 The plock must be held before calling this function.
Packit 13e616
**********************************************************************/
Packit 13e616
static void ni_rcv_set_links(IN osm_sm_t * sm, osm_node_t * p_node,
Packit 13e616
			     const uint8_t port_num,
Packit 13e616
			     const osm_ni_context_t * p_ni_context)
Packit 13e616
{
Packit 13e616
	osm_node_t *p_neighbor_node;
Packit 13e616
	osm_physp_t *p_physp, *p_remote_physp;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   A special case exists in which the node we're trying to
Packit 13e616
	   link is our own node.  In this case, the guid value in
Packit 13e616
	   the ni_context will be zero.
Packit 13e616
	 */
Packit 13e616
	if (p_ni_context->node_guid == 0) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Nothing to link for our own node 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit 13e616
		goto _exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_neighbor_node = osm_get_node_by_guid(sm->p_subn,
Packit 13e616
					       p_ni_context->node_guid);
Packit 13e616
	if (PF(!p_neighbor_node)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D10: "
Packit 13e616
			"Unexpected removal of neighbor node 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(p_ni_context->node_guid));
Packit 13e616
		goto _exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* When setting the link, ports on both
Packit 13e616
	   sides of the link should be initialized */
Packit 13e616
	CL_ASSERT(osm_node_link_has_valid_ports(p_node, port_num,
Packit 13e616
						p_neighbor_node,
Packit 13e616
						p_ni_context->port_num));
Packit 13e616
Packit 13e616
	if (osm_node_link_exists(p_node, port_num,
Packit 13e616
				 p_neighbor_node, p_ni_context->port_num)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Link already exists\n");
Packit 13e616
		goto _exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_physp = osm_node_get_physp_ptr(p_node, port_num);
Packit 13e616
	if (!p_physp) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR OD0E: "
Packit 13e616
			"Failed to find physp for port %d of Node GUID 0x%"
Packit 13e616
			PRIx64 "\n", port_num,
Packit 13e616
			cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit 13e616
		goto _exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * If the link went UP, after we already discovered it, we shouldn't
Packit 13e616
	 * set the link between the ports and resweep.
Packit 13e616
	 */
Packit 13e616
	if (osm_physp_get_port_state(p_physp) == IB_LINK_DOWN &&
Packit 13e616
	    p_node->physp_discovered[port_num]) {
Packit 13e616
		/* Link down on another side. Don't create a link*/
Packit 13e616
		p_node->physp_discovered[port_num] = 0;
Packit 13e616
		sm->p_subn->force_heavy_sweep = TRUE;
Packit 13e616
		goto _exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (osm_node_has_any_link(p_node, port_num) &&
Packit 13e616
	    sm->p_subn->force_heavy_sweep == FALSE &&
Packit 13e616
	    (!p_ni_context->dup_count ||
Packit 13e616
	     (p_ni_context->dup_node_guid == osm_node_get_node_guid(p_node) &&
Packit 13e616
	      p_ni_context->dup_port_num == port_num))) {
Packit 13e616
		/*
Packit 13e616
		   Uh oh...
Packit 13e616
		   This could be reconnected ports, but also duplicated GUID
Packit 13e616
		   (2 nodes have the same guid) or a 12x link with lane reversal
Packit 13e616
		   that is not configured correctly.
Packit 13e616
		   We will try to recover by querying NodeInfo again.
Packit 13e616
		   In order to catch even fast port moving to new location(s)
Packit 13e616
		   and back we will count up to 5.
Packit 13e616
		   Some crazy reconnections (newly created switch loop right
Packit 13e616
		   before targeted CA) will not be catched this way. So in worst
Packit 13e616
		   case - report GUID duplication and request new discovery.
Packit 13e616
		   When switch node is targeted NodeInfo querying will be done
Packit 13e616
		   in opposite order, this is much stronger check, unfortunately
Packit 13e616
		   it is impossible with CAs.
Packit 13e616
		 */
Packit 13e616
		p_physp = osm_node_get_physp_ptr(p_node, port_num);
Packit 13e616
		if (!p_physp) {
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR OD0F: "
Packit 13e616
				"Failed to find physp for port %d of Node GUID 0x%"
Packit 13e616
				PRIx64 "\n", port_num,
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit 13e616
			goto _exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (p_ni_context->dup_count > 5) {
Packit 13e616
			report_duplicated_guid(sm, p_physp, p_neighbor_node,
Packit 13e616
					       p_ni_context->port_num);
Packit 13e616
			sm->p_subn->force_heavy_sweep = TRUE;
Packit 13e616
		} else if (p_node->sw)
Packit 13e616
			requery_dup_node_info(sm, p_physp->p_remote_physp,
Packit 13e616
					      p_ni_context->dup_count + 1);
Packit 13e616
		else
Packit 13e616
			requery_dup_node_info(sm, p_physp,
Packit 13e616
					      p_ni_context->dup_count + 1);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   When there are only two nodes with exact same guids (connected back
Packit 13e616
	   to back) - the previous check for duplicated guid will not catch
Packit 13e616
	   them. But the link will be from the port to itself...
Packit 13e616
	   Enhanced Port 0 is an exception to this
Packit 13e616
	 */
Packit 13e616
	if (osm_node_get_node_guid(p_node) == p_ni_context->node_guid &&
Packit 13e616
	    port_num == p_ni_context->port_num &&
Packit 13e616
	    port_num != 0 && cl_qmap_count(&sm->p_subn->sw_guid_tbl) == 0) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Duplicate GUID found by link from a port to itself:"
Packit 13e616
			"node 0x%" PRIx64 ", port number %u\n",
Packit 13e616
			cl_ntoh64(osm_node_get_node_guid(p_node)), port_num);
Packit 13e616
		p_physp = osm_node_get_physp_ptr(p_node, port_num);
Packit 13e616
		if (!p_physp) {
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR OD1D: "
Packit 13e616
				"Failed to find physp for port %d of Node GUID 0x%"
Packit 13e616
				PRIx64 "\n", port_num,
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit 13e616
			goto _exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		osm_dump_dr_path_v2(sm->p_log, osm_physp_get_dr_path_ptr(p_physp),
Packit 13e616
				    FILE_ID, OSM_LOG_VERBOSE);
Packit 13e616
Packit 13e616
		if (sm->p_subn->opt.exit_on_fatal == TRUE) {
Packit 13e616
			osm_log_v2(sm->p_log, OSM_LOG_SYS, FILE_ID,
Packit 13e616
				   "Errors on subnet. Duplicate GUID found "
Packit 13e616
				   "by link from a port to itself. "
Packit 13e616
				   "See verbose opensm.log for more details\n");
Packit 13e616
			exit(1);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Creating new link between:\n\t\t\t\tnode 0x%" PRIx64
Packit 13e616
		", port number %u and\n\t\t\t\tnode 0x%" PRIx64
Packit 13e616
		", port number %u\n",
Packit 13e616
		cl_ntoh64(osm_node_get_node_guid(p_node)), port_num,
Packit 13e616
		cl_ntoh64(p_ni_context->node_guid), p_ni_context->port_num);
Packit 13e616
Packit 13e616
	if (sm->ucast_mgr.cache_valid)
Packit 13e616
		osm_ucast_cache_check_new_link(&sm->ucast_mgr, p_node, port_num,
Packit 13e616
					       p_neighbor_node,
Packit 13e616
					       p_ni_context->port_num);
Packit 13e616
Packit 13e616
	p_physp = osm_node_get_physp_ptr(p_node, port_num);
Packit 13e616
	p_remote_physp = osm_node_get_physp_ptr(p_neighbor_node,
Packit 13e616
						p_ni_context->port_num);
Packit 13e616
	if (!p_physp || !p_remote_physp)
Packit 13e616
		goto _exit;
Packit 13e616
Packit 13e616
	osm_node_link(p_node, port_num, p_neighbor_node, p_ni_context->port_num);
Packit 13e616
Packit 13e616
	osm_db_neighbor_set(sm->p_subn->p_neighbor,
Packit 13e616
			    cl_ntoh64(osm_physp_get_port_guid(p_physp)),
Packit 13e616
			    port_num,
Packit 13e616
			    cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)),
Packit 13e616
			    p_ni_context->port_num);
Packit 13e616
	osm_db_neighbor_set(sm->p_subn->p_neighbor,
Packit 13e616
			    cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)),
Packit 13e616
			    p_ni_context->port_num,
Packit 13e616
			    cl_ntoh64(osm_physp_get_port_guid(p_physp)),
Packit 13e616
			    port_num);
Packit 13e616
Packit 13e616
_exit:
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void ni_rcv_get_port_info(IN osm_sm_t * sm, IN osm_node_t * node,
Packit 13e616
				 IN const osm_madw_t * madw)
Packit 13e616
{
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
	osm_physp_t *physp;
Packit 13e616
	ib_node_info_t *ni;
Packit 13e616
	unsigned port;
Packit 13e616
	ib_api_status_t status;
Packit 13e616
	int mlnx_epi_supported = 0;
Packit 13e616
Packit 13e616
	ni = ib_smp_get_payload_ptr(osm_madw_get_smp_ptr(madw));
Packit 13e616
Packit 13e616
	port = ib_node_info_get_local_port_num(ni);
Packit 13e616
Packit 13e616
	if (sm->p_subn->opt.fdr10)
Packit 13e616
		mlnx_epi_supported = is_mlnx_ext_port_info_supported(
Packit 13e616
						ib_node_info_get_vendor_id(ni),
Packit 13e616
						ni->device_id);
Packit 13e616
Packit 13e616
	physp = osm_node_get_physp_ptr(node, port);
Packit 13e616
	if (!physp) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR OD1E: "
Packit 13e616
			"Failed to find physp for port %d of Node GUID 0x%"
Packit 13e616
			PRIx64 "\n", port,
Packit 13e616
			cl_ntoh64(osm_node_get_node_guid(node)));
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	context.pi_context.node_guid = osm_node_get_node_guid(node);
Packit 13e616
	context.pi_context.port_guid = osm_physp_get_port_guid(physp);
Packit 13e616
	context.pi_context.set_method = FALSE;
Packit 13e616
	context.pi_context.light_sweep = FALSE;
Packit 13e616
	context.pi_context.active_transition = FALSE;
Packit 13e616
	context.pi_context.client_rereg = FALSE;
Packit 13e616
Packit 13e616
	status = osm_req_get(sm, osm_physp_get_dr_path_ptr(physp),
Packit 13e616
			     IB_MAD_ATTR_PORT_INFO, cl_hton32(port),
Packit 13e616
			     TRUE, 0, 0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR OD02: "
Packit 13e616
			"Failure initiating PortInfo request (%s)\n",
Packit 13e616
			ib_get_err_str(status));
Packit 13e616
	if (mlnx_epi_supported) {
Packit 13e616
		status = osm_req_get(sm,
Packit 13e616
				     osm_physp_get_dr_path_ptr(physp),
Packit 13e616
				     IB_MAD_ATTR_MLNX_EXTENDED_PORT_INFO,
Packit 13e616
				     cl_hton32(port),
Packit 13e616
				     TRUE, 0, 0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
		if (status != IB_SUCCESS)
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D0B: "
Packit 13e616
				"Failure initiating MLNX ExtPortInfo request (%s)\n",
Packit 13e616
				ib_get_err_str(status));
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 The plock must be held before calling this function.
Packit 13e616
**********************************************************************/
Packit 13e616
void osm_req_get_node_desc(IN osm_sm_t * sm, osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
	ib_api_status_t status = IB_SUCCESS;
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	context.nd_context.node_guid =
Packit 13e616
	    osm_node_get_node_guid(osm_physp_get_node_ptr(p_physp));
Packit 13e616
Packit 13e616
	status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp),
Packit 13e616
			     IB_MAD_ATTR_NODE_DESC, 0, TRUE, 0,
Packit 13e616
			     0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D03: "
Packit 13e616
			"Failure initiating NodeDescription request (%s)\n",
Packit 13e616
			ib_get_err_str(status));
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 The plock must be held before calling this function.
Packit 13e616
**********************************************************************/
Packit 13e616
static void ni_rcv_get_node_desc(IN osm_sm_t * sm, IN osm_node_t * p_node,
Packit 13e616
				 IN const osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	ib_node_info_t *p_ni;
Packit 13e616
	ib_smp_t *p_smp;
Packit 13e616
	uint8_t port_num;
Packit 13e616
	osm_physp_t *p_physp = NULL;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit 13e616
	p_ni = ib_smp_get_payload_ptr(p_smp);
Packit 13e616
	port_num = ib_node_info_get_local_port_num(p_ni);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Request PortInfo & NodeDescription attributes for the port
Packit 13e616
	   that responded to the NodeInfo attribute.
Packit 13e616
	   Because this is a channel adapter or router, we are
Packit 13e616
	   not allowed to request PortInfo for the other ports.
Packit 13e616
	   Set the context union properly, so the recipient
Packit 13e616
	   knows which node & port are relevant.
Packit 13e616
	 */
Packit 13e616
	p_physp = osm_node_get_physp_ptr(p_node, port_num);
Packit 13e616
	if (!p_physp) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR OD1F: "
Packit 13e616
			"Failed to find physp for port %d of Node GUID 0x%"
Packit 13e616
			PRIx64 "\n", port_num,
Packit 13e616
			cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	osm_req_get_node_desc(sm, p_physp);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 The plock must be held before calling this function.
Packit 13e616
**********************************************************************/
Packit 13e616
static void ni_rcv_process_new_ca_or_router(IN osm_sm_t * sm,
Packit 13e616
					    IN osm_node_t * p_node,
Packit 13e616
					    IN const osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	ni_rcv_get_port_info(sm, p_node, p_madw);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   A node guid of 0 is the corner case that indicates
Packit 13e616
	   we discovered our own node.  Initialize the subnet
Packit 13e616
	   object with the SM's own port guid.
Packit 13e616
	 */
Packit 13e616
	if (osm_madw_get_ni_context_ptr(p_madw)->node_guid == 0)
Packit 13e616
		sm->p_subn->sm_port_guid = p_node->node_info.port_guid;
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 The plock must be held before calling this function.
Packit 13e616
**********************************************************************/
Packit 13e616
static void ni_rcv_process_existing_ca_or_router(IN osm_sm_t * sm,
Packit 13e616
						 IN osm_node_t * p_node,
Packit 13e616
						 IN const osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	ib_node_info_t *p_ni;
Packit 13e616
	ib_smp_t *p_smp;
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	osm_port_t *p_port_check;
Packit 13e616
	uint8_t port_num;
Packit 13e616
	osm_dr_path_t *p_dr_path;
Packit 13e616
	osm_alias_guid_t *p_alias_guid, *p_alias_guid_check;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit 13e616
	p_ni = ib_smp_get_payload_ptr(p_smp);
Packit 13e616
	port_num = ib_node_info_get_local_port_num(p_ni);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Determine if we have encountered this node through a
Packit 13e616
	   previously undiscovered port.  If so, build the new
Packit 13e616
	   port object.
Packit 13e616
	 */
Packit 13e616
	p_port = osm_get_port_by_guid(sm->p_subn, p_ni->port_guid);
Packit 13e616
	if (!p_port) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Creating new port object with GUID 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(p_ni->port_guid));
Packit 13e616
Packit 13e616
		osm_node_init_physp(p_node, port_num, p_madw);
Packit 13e616
Packit 13e616
		p_port = osm_port_new(p_ni, p_node);
Packit 13e616
		if (PF(p_port == NULL)) {
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D04: "
Packit 13e616
				"Unable to create new port object\n");
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Add the new port object to the database.
Packit 13e616
		 */
Packit 13e616
		p_port_check =
Packit 13e616
		    (osm_port_t *) cl_qmap_insert(&sm->p_subn->port_guid_tbl,
Packit 13e616
						  p_ni->port_guid,
Packit 13e616
						  &p_port->map_item);
Packit 13e616
		if (PF(p_port_check != p_port)) {
Packit 13e616
			/*
Packit 13e616
			   We should never be here!
Packit 13e616
			   Somehow, this port GUID already exists in the table.
Packit 13e616
			 */
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D12: "
Packit 13e616
				"Port 0x%" PRIx64 " already in the database!\n",
Packit 13e616
				cl_ntoh64(p_ni->port_guid));
Packit 13e616
Packit 13e616
			osm_port_delete(&p_port);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		p_alias_guid = osm_alias_guid_new(p_ni->port_guid,
Packit 13e616
						  p_port);
Packit 13e616
		if (PF(!p_alias_guid)) {
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D11: "
Packit 13e616
				"alias guid memory allocation failed"
Packit 13e616
				" for port GUID 0x%" PRIx64 "\n",
Packit 13e616
				cl_ntoh64(p_ni->port_guid));
Packit 13e616
			goto alias_done;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/* insert into alias guid table */
Packit 13e616
		p_alias_guid_check =
Packit 13e616
			(osm_alias_guid_t *) cl_qmap_insert(&sm->p_subn->alias_port_guid_tbl,
Packit 13e616
							    p_alias_guid->alias_guid,
Packit 13e616
							    &p_alias_guid->map_item);
Packit 13e616
		if (p_alias_guid_check != p_alias_guid) {
Packit 13e616
			/* alias GUID is a duplicate */
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D13: "
Packit 13e616
				"Duplicate alias port GUID 0x%" PRIx64 "\n",
Packit 13e616
				cl_ntoh64(p_ni->port_guid));
Packit 13e616
			osm_alias_guid_delete(&p_alias_guid);
Packit 13e616
			osm_port_delete(&p_port);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
alias_done:
Packit 13e616
		/* If we are a master, then this means the port is new on the subnet.
Packit 13e616
		   Mark it as new - need to send trap 64 for these ports.
Packit 13e616
		   The condition that we are master is true, since if we are in discovering
Packit 13e616
		   state (meaning we woke up from standby or we are just initializing),
Packit 13e616
		   then these ports may be new to us, but are not new on the subnet.
Packit 13e616
		   If we are master, then the subnet as we know it is the updated one,
Packit 13e616
		   and any new ports we encounter should cause trap 64. C14-72.1.1 */
Packit 13e616
		if (sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER)
Packit 13e616
			p_port->is_new = 1;
Packit 13e616
Packit 13e616
	} else {
Packit 13e616
		osm_physp_t *p_physp = osm_node_get_physp_ptr(p_node, port_num);
Packit 13e616
Packit 13e616
		if (PF(p_physp == NULL)) {
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D1C: "
Packit 13e616
				"No physical port found for node GUID 0x%"
Packit 13e616
				PRIx64 " port %u. Might be duplicate port GUID\n",
Packit 13e616
				cl_ntoh64(p_node->node_info.node_guid),
Packit 13e616
				port_num);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Update the DR Path to the port,
Packit 13e616
		   in case the old one is no longer available.
Packit 13e616
		 */
Packit 13e616
		p_dr_path = osm_physp_get_dr_path_ptr(p_physp);
Packit 13e616
Packit 13e616
		osm_dr_path_init(p_dr_path, p_smp->hop_count,
Packit 13e616
				 p_smp->initial_path);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	ni_rcv_get_port_info(sm, p_node, p_madw);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void ni_rcv_process_switch(IN osm_sm_t * sm, IN osm_node_t * p_node,
Packit 13e616
				  IN const osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	ib_api_status_t status = IB_SUCCESS;
Packit 13e616
	osm_physp_t *p_physp;
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
	osm_dr_path_t *path;
Packit 13e616
	ib_smp_t *p_smp;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit 13e616
Packit 13e616
	p_physp = osm_node_get_physp_ptr(p_node, 0);
Packit 13e616
	/* update DR path of already initialized switch port 0 */
Packit 13e616
	path = osm_physp_get_dr_path_ptr(p_physp);
Packit 13e616
	osm_dr_path_init(path, p_smp->hop_count, p_smp->initial_path);
Packit 13e616
Packit 13e616
	context.si_context.node_guid = osm_node_get_node_guid(p_node);
Packit 13e616
	context.si_context.set_method = FALSE;
Packit 13e616
	context.si_context.light_sweep = FALSE;
Packit 13e616
	context.si_context.lft_top_change = FALSE;
Packit 13e616
Packit 13e616
	/* Request a SwitchInfo attribute */
Packit 13e616
	status = osm_req_get(sm, path, IB_MAD_ATTR_SWITCH_INFO, 0, TRUE, 0,
Packit 13e616
			     0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		/* continue despite error */
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D06: "
Packit 13e616
			"Failure initiating SwitchInfo request (%s)\n",
Packit 13e616
			ib_get_err_str(status));
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 The plock must be held before calling this function.
Packit 13e616
**********************************************************************/
Packit 13e616
static void ni_rcv_process_existing_switch(IN osm_sm_t * sm,
Packit 13e616
					   IN osm_node_t * p_node,
Packit 13e616
					   IN const osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   If this switch has already been probed during this sweep,
Packit 13e616
	   then don't bother reprobing it.
Packit 13e616
	 */
Packit 13e616
	if (p_node->discovery_count == 1)
Packit 13e616
		ni_rcv_process_switch(sm, p_node, p_madw);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 The plock must be held before calling this function.
Packit 13e616
**********************************************************************/
Packit 13e616
static void ni_rcv_process_new_switch(IN osm_sm_t * sm, IN osm_node_t * p_node,
Packit 13e616
				      IN const osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	ni_rcv_process_switch(sm, p_node, p_madw);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   A node guid of 0 is the corner case that indicates
Packit 13e616
	   we discovered our own node.  Initialize the subnet
Packit 13e616
	   object with the SM's own port guid.
Packit 13e616
	 */
Packit 13e616
	if (osm_madw_get_ni_context_ptr(p_madw)->node_guid == 0)
Packit 13e616
		sm->p_subn->sm_port_guid = p_node->node_info.port_guid;
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 The plock must NOT be held before calling this function.
Packit 13e616
**********************************************************************/
Packit 13e616
static void ni_rcv_process_new(IN osm_sm_t * sm, IN const osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	osm_node_t *p_node;
Packit 13e616
	osm_node_t *p_node_check;
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	osm_port_t *p_port_check;
Packit 13e616
	osm_router_t *p_rtr = NULL;
Packit 13e616
	osm_router_t *p_rtr_check;
Packit 13e616
	cl_qmap_t *p_rtr_guid_tbl;
Packit 13e616
	ib_node_info_t *p_ni;
Packit 13e616
	ib_smp_t *p_smp;
Packit 13e616
	osm_ni_context_t *p_ni_context;
Packit 13e616
	osm_alias_guid_t *p_alias_guid, *p_alias_guid_check;
Packit 13e616
	uint8_t port_num;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit 13e616
	p_ni = ib_smp_get_payload_ptr(p_smp);
Packit 13e616
	p_ni_context = osm_madw_get_ni_context_ptr(p_madw);
Packit 13e616
	port_num = ib_node_info_get_local_port_num(p_ni);
Packit 13e616
Packit 13e616
	osm_dump_smp_dr_path_v2(sm->p_log, p_smp, FILE_ID, OSM_LOG_VERBOSE);
Packit 13e616
Packit 13e616
	OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
		"Discovered new %s node,"
Packit 13e616
		"\n\t\t\t\tGUID 0x%" PRIx64 ", TID 0x%" PRIx64 "\n",
Packit 13e616
		ib_get_node_type_str(p_ni->node_type),
Packit 13e616
		cl_ntoh64(p_ni->node_guid), cl_ntoh64(p_smp->trans_id));
Packit 13e616
Packit 13e616
	if (PF(port_num > p_ni->num_ports)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D0A: "
Packit 13e616
			"New %s node GUID 0x%" PRIx64 "is non-compliant and "
Packit 13e616
			"is being ignored since the "
Packit 13e616
			"local port num %u > num ports %u\n",
Packit 13e616
			ib_get_node_type_str(p_ni->node_type),
Packit 13e616
			cl_ntoh64(p_ni->node_guid), port_num,
Packit 13e616
			p_ni->num_ports);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_node = osm_node_new(p_madw);
Packit 13e616
	if (PF(p_node == NULL)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D07: "
Packit 13e616
			"Unable to create new node object\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Create a new port object to represent this node's physical
Packit 13e616
	   ports in the port table.
Packit 13e616
	 */
Packit 13e616
	p_port = osm_port_new(p_ni, p_node);
Packit 13e616
	if (PF(p_port == NULL)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D14: "
Packit 13e616
			"Unable to create new port object\n");
Packit 13e616
		osm_node_delete(&p_node);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Add the new port object to the database.
Packit 13e616
	 */
Packit 13e616
	p_port_check =
Packit 13e616
	    (osm_port_t *) cl_qmap_insert(&sm->p_subn->port_guid_tbl,
Packit 13e616
					  p_ni->port_guid, &p_port->map_item);
Packit 13e616
	if (PF(p_port_check != p_port)) {
Packit 13e616
		/*
Packit 13e616
		   We should never be here!
Packit 13e616
		   Somehow, this port GUID already exists in the table.
Packit 13e616
		 */
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D15: "
Packit 13e616
			"Duplicate Port GUID 0x%" PRIx64
Packit 13e616
			"! Found by the two directed routes:\n",
Packit 13e616
			cl_ntoh64(p_ni->port_guid));
Packit 13e616
		osm_dump_dr_path_v2(sm->p_log,
Packit 13e616
				    osm_physp_get_dr_path_ptr(p_port->p_physp),
Packit 13e616
				    FILE_ID, OSM_LOG_ERROR);
Packit 13e616
		osm_dump_dr_path_v2(sm->p_log,
Packit 13e616
				    osm_physp_get_dr_path_ptr(p_port_check->
Packit 13e616
							   p_physp),
Packit 13e616
				    FILE_ID, OSM_LOG_ERROR);
Packit 13e616
		osm_port_delete(&p_port);
Packit 13e616
		osm_node_delete(&p_node);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_alias_guid = osm_alias_guid_new(p_ni->port_guid,
Packit 13e616
					  p_port);
Packit 13e616
	if (PF(!p_alias_guid)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D18: "
Packit 13e616
			"alias guid memory allocation failed"
Packit 13e616
			" for port GUID 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(p_ni->port_guid));
Packit 13e616
		goto alias_done2;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* insert into alias guid table */
Packit 13e616
	p_alias_guid_check =
Packit 13e616
		(osm_alias_guid_t *) cl_qmap_insert(&sm->p_subn->alias_port_guid_tbl,
Packit 13e616
						    p_alias_guid->alias_guid,
Packit 13e616
						    &p_alias_guid->map_item);
Packit 13e616
	if (p_alias_guid_check != p_alias_guid) {
Packit 13e616
		/* alias GUID is a duplicate */
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D19: "
Packit 13e616
			"Duplicate alias port GUID 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(p_ni->port_guid));
Packit 13e616
		osm_alias_guid_delete(&p_alias_guid);
Packit 13e616
	}
Packit 13e616
Packit 13e616
alias_done2:
Packit 13e616
	/* If we are a master, then this means the port is new on the subnet.
Packit 13e616
	   Mark it as new - need to send trap 64 on these ports.
Packit 13e616
	   The condition that we are master is true, since if we are in discovering
Packit 13e616
	   state (meaning we woke up from standby or we are just initializing),
Packit 13e616
	   then these ports may be new to us, but are not new on the subnet.
Packit 13e616
	   If we are master, then the subnet as we know it is the updated one,
Packit 13e616
	   and any new ports we encounter should cause trap 64. C14-72.1.1 */
Packit 13e616
	if (sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER)
Packit 13e616
		p_port->is_new = 1;
Packit 13e616
Packit 13e616
	/* If there were RouterInfo or other router attribute,
Packit 13e616
	   this would be elsewhere */
Packit 13e616
	if (p_ni->node_type == IB_NODE_TYPE_ROUTER) {
Packit 13e616
		if (PF((p_rtr = osm_router_new(p_port)) == NULL))
Packit 13e616
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D1A: "
Packit 13e616
				"Unable to create new router object\n");
Packit 13e616
		else {
Packit 13e616
			p_rtr_guid_tbl = &sm->p_subn->rtr_guid_tbl;
Packit 13e616
			p_rtr_check =
Packit 13e616
			    (osm_router_t *) cl_qmap_insert(p_rtr_guid_tbl,
Packit 13e616
							    p_ni->port_guid,
Packit 13e616
							    &p_rtr->map_item);
Packit 13e616
			if (PF(p_rtr_check != p_rtr))
Packit 13e616
				OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D1B: "
Packit 13e616
					"Unable to add port GUID:0x%016" PRIx64
Packit 13e616
					" to router table\n",
Packit 13e616
					cl_ntoh64(p_ni->port_guid));
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_node_check =
Packit 13e616
	    (osm_node_t *) cl_qmap_insert(&sm->p_subn->node_guid_tbl,
Packit 13e616
					  p_ni->node_guid, &p_node->map_item);
Packit 13e616
	if (PF(p_node_check != p_node)) {
Packit 13e616
		/*
Packit 13e616
		   This node must have been inserted by another thread.
Packit 13e616
		   This is unexpected, but is not an error.
Packit 13e616
		   We can simply clean-up, since the other thread will
Packit 13e616
		   see this processing through to completion.
Packit 13e616
		 */
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Discovery race detected at node 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(p_ni->node_guid));
Packit 13e616
		osm_node_delete(&p_node);
Packit 13e616
		p_node = p_node_check;
Packit 13e616
		ni_rcv_set_links(sm, p_node, port_num, p_ni_context);
Packit 13e616
		goto Exit;
Packit 13e616
	} else
Packit 13e616
		ni_rcv_set_links(sm, p_node, port_num, p_ni_context);
Packit 13e616
Packit 13e616
	p_node->discovery_count++;
Packit 13e616
	ni_rcv_get_node_desc(sm, p_node, p_madw);
Packit 13e616
Packit 13e616
	switch (p_ni->node_type) {
Packit 13e616
	case IB_NODE_TYPE_CA:
Packit 13e616
	case IB_NODE_TYPE_ROUTER:
Packit 13e616
		ni_rcv_process_new_ca_or_router(sm, p_node, p_madw);
Packit 13e616
		break;
Packit 13e616
	case IB_NODE_TYPE_SWITCH:
Packit 13e616
		ni_rcv_process_new_switch(sm, p_node, p_madw);
Packit 13e616
		break;
Packit 13e616
	default:
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D16: "
Packit 13e616
			"Unknown node type %u with GUID 0x%" PRIx64 "\n",
Packit 13e616
			p_ni->node_type, cl_ntoh64(p_ni->node_guid));
Packit 13e616
		break;
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 The plock must be held before calling this function.
Packit 13e616
**********************************************************************/
Packit 13e616
static void ni_rcv_process_existing(IN osm_sm_t * sm, IN osm_node_t * p_node,
Packit 13e616
				    IN const osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	ib_node_info_t *p_ni;
Packit 13e616
	ib_smp_t *p_smp;
Packit 13e616
	osm_ni_context_t *p_ni_context;
Packit 13e616
	uint8_t port_num;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit 13e616
	p_ni = ib_smp_get_payload_ptr(p_smp);
Packit 13e616
	p_ni_context = osm_madw_get_ni_context_ptr(p_madw);
Packit 13e616
	port_num = ib_node_info_get_local_port_num(p_ni);
Packit 13e616
Packit 13e616
	OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit 13e616
		"Rediscovered %s node 0x%" PRIx64 " TID 0x%" PRIx64
Packit 13e616
		", discovered %u times already\n",
Packit 13e616
		ib_get_node_type_str(p_ni->node_type),
Packit 13e616
		cl_ntoh64(p_ni->node_guid),
Packit 13e616
		cl_ntoh64(p_smp->trans_id), p_node->discovery_count);
Packit 13e616
Packit 13e616
	if (PF(port_num > p_ni->num_ports)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D0C: "
Packit 13e616
			"Existing %s node GUID 0x%" PRIx64 "is non-compliant "
Packit 13e616
			"and is being ignored since the "
Packit 13e616
			"local port num %u > num ports %u\n",
Packit 13e616
			ib_get_node_type_str(p_ni->node_type),
Packit 13e616
			cl_ntoh64(p_ni->node_guid), port_num,
Packit 13e616
			p_ni->num_ports);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   If we haven't already encountered this existing node
Packit 13e616
	   on this particular sweep, then process further.
Packit 13e616
	 */
Packit 13e616
	p_node->discovery_count++;
Packit 13e616
Packit 13e616
	switch (p_ni->node_type) {
Packit 13e616
	case IB_NODE_TYPE_CA:
Packit 13e616
	case IB_NODE_TYPE_ROUTER:
Packit 13e616
		ni_rcv_process_existing_ca_or_router(sm, p_node, p_madw);
Packit 13e616
		break;
Packit 13e616
Packit 13e616
	case IB_NODE_TYPE_SWITCH:
Packit 13e616
		ni_rcv_process_existing_switch(sm, p_node, p_madw);
Packit 13e616
		break;
Packit 13e616
Packit 13e616
	default:
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D09: "
Packit 13e616
			"Unknown node type %u with GUID 0x%" PRIx64 "\n",
Packit 13e616
			p_ni->node_type, cl_ntoh64(p_ni->node_guid));
Packit 13e616
		break;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if ( p_ni->sys_guid != p_node->node_info.sys_guid) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Updated SysImageGUID: 0x%"
Packit 13e616
			PRIx64 " for node 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(p_ni->sys_guid),
Packit 13e616
			cl_ntoh64(p_ni->node_guid));
Packit 13e616
	}
Packit 13e616
	ni_rcv_set_links(sm, p_node, port_num, p_ni_context);
Packit 13e616
	p_node->node_info = *p_ni;
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_ni_rcv_process(IN void *context, IN void *data)
Packit 13e616
{
Packit 13e616
	osm_sm_t *sm = context;
Packit 13e616
	osm_madw_t *p_madw = data;
Packit 13e616
	ib_node_info_t *p_ni;
Packit 13e616
	ib_smp_t *p_smp;
Packit 13e616
	osm_node_t *p_node;
Packit 13e616
Packit 13e616
	CL_ASSERT(sm);
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_madw);
Packit 13e616
Packit 13e616
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit 13e616
	p_ni = ib_smp_get_payload_ptr(p_smp);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_NODE_INFO);
Packit 13e616
Packit 13e616
	if (PF(p_ni->node_guid == 0)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D16: "
Packit 13e616
			"Got Zero Node GUID! Found on the directed route:\n");
Packit 13e616
		osm_dump_smp_dr_path_v2(sm->p_log, p_smp, FILE_ID, OSM_LOG_ERROR);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (PF(p_ni->port_guid == 0)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D17: "
Packit 13e616
			"Got Zero Port GUID! Found on the directed route:\n");
Packit 13e616
		osm_dump_smp_dr_path_v2(sm->p_log, p_smp, FILE_ID, OSM_LOG_ERROR);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (ib_smp_get_status(p_smp)) {
Packit 13e616
		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"MAD status 0x%x received\n",
Packit 13e616
			cl_ntoh16(ib_smp_get_status(p_smp)));
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Determine if this node has already been discovered,
Packit 13e616
	   and process accordingly.
Packit 13e616
	   During processing of this node, hold the shared lock.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	CL_PLOCK_EXCL_ACQUIRE(sm->p_lock);
Packit 13e616
	p_node = osm_get_node_by_guid(sm->p_subn, p_ni->node_guid);
Packit 13e616
Packit 13e616
	osm_dump_node_info_v2(sm->p_log, p_ni, FILE_ID, OSM_LOG_DEBUG);
Packit 13e616
Packit 13e616
	if (!p_node)
Packit 13e616
		ni_rcv_process_new(sm, p_madw);
Packit 13e616
	else
Packit 13e616
		ni_rcv_process_existing(sm, p_node, p_madw);
Packit 13e616
Packit 13e616
	CL_PLOCK_RELEASE(sm->p_lock);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sm->p_log);
Packit 13e616
}