Blame opensm/osm_lid_mgr.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. 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_lid_mgr_t.
Packit 13e616
 * This file implements the LID Manager object which is responsible for
Packit 13e616
 * assigning LIDs to all ports on the subnet.
Packit 13e616
 *
Packit 13e616
 * DATA STRUCTURES:
Packit 13e616
 *  p_subn->port_lid_tbl : a vector pointing from lid to its port.
Packit 13e616
 *  osm db guid2lid domain : a hash from guid to lid (min lid).
Packit 13e616
 *  p_subn->port_guid_tbl : a map from guid to discovered port obj.
Packit 13e616
 *
Packit 13e616
 * ALGORITHM:
Packit 13e616
 *
Packit 13e616
 * 0. we define a function to obtain the correct port lid:
Packit 13e616
 *    lid_mgr_get_port_lid( p_mgr, port, &min_lid, &max_lid ):
Packit 13e616
 *    0.1 if the port info lid matches the guid2lid return 0
Packit 13e616
 *    0.2 if the port info has a lid and that range is empty in
Packit 13e616
 *        port_lid_tbl, return 0 and update the port_lid_tbl and
Packit 13e616
 *        guid2lid
Packit 13e616
 *    0.3 else find an empty space in port_lid_tbl, update the
Packit 13e616
 *    port_lid_tbl and guid2lid, return 1 to flag a change required.
Packit 13e616
 *
Packit 13e616
 * 1. During initialization:
Packit 13e616
 *   1.1 initialize the guid2lid database domain.
Packit 13e616
 *   1.2 if reassign_lid is not set:
Packit 13e616
 *   1.2.1 read the persistent data for the domain.
Packit 13e616
 *   1.2.2 validate no duplicate use of lids and lids are 2^(lmc-1)
Packit 13e616
 *
Packit 13e616
 * 2. During SM port lid assignment:
Packit 13e616
 *   2.1 if reassign_lids is set, make it 2^lmc
Packit 13e616
 *   2.2 cleanup all port_lid_tbl and re-fill it according to guid2lid
Packit 13e616
 *   2.3 call lid_mgr_get_port_lid for the SM port
Packit 13e616
 *   2.4 set the port info
Packit 13e616
 *
Packit 13e616
 * 3. During all other ports lid assignment:
Packit 13e616
 *   3.1 go through all ports in the subnet
Packit 13e616
 *   3.1.1 call lid_mgr_get_port_lid
Packit 13e616
 *   3.1.2 if a change required send the port info
Packit 13e616
 *   3.2 if any change send the signal PENDING...
Packit 13e616
 *
Packit 13e616
 * 4. Store the guid2lid
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_debug.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_LID_MGR_C
Packit 13e616
#include <opensm/osm_lid_mgr.h>
Packit 13e616
#include <opensm/osm_sm.h>
Packit 13e616
#include <opensm/osm_log.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_msgdef.h>
Packit 13e616
#include <vendor/osm_vendor_api.h>
Packit 13e616
#include <opensm/osm_db_pack.h>
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
  lid range item of qlist
Packit 13e616
 **********************************************************************/
Packit 13e616
typedef struct osm_lid_mgr_range {
Packit 13e616
	cl_list_item_t item;
Packit 13e616
	uint16_t min_lid;
Packit 13e616
	uint16_t max_lid;
Packit 13e616
} osm_lid_mgr_range_t;
Packit 13e616
Packit 13e616
void osm_lid_mgr_construct(IN osm_lid_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	memset(p_mgr, 0, sizeof(*p_mgr));
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_lid_mgr_destroy(IN osm_lid_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	cl_list_item_t *p_item;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	while ((p_item = cl_qlist_remove_head(&p_mgr->free_ranges)) !=
Packit 13e616
	       cl_qlist_end(&p_mgr->free_ranges))
Packit 13e616
		free((osm_lid_mgr_range_t *) p_item);
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
Validate the guid to lid data by making sure that under the current
Packit 13e616
LMC we did not get duplicates. If we do flag them as errors and remove
Packit 13e616
the entry.
Packit 13e616
**********************************************************************/
Packit 13e616
static void lid_mgr_validate_db(IN osm_lid_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	cl_qlist_t guids;
Packit 13e616
	osm_db_guid_elem_t *p_item;
Packit 13e616
	uint16_t lid;
Packit 13e616
	uint16_t min_lid;
Packit 13e616
	uint16_t max_lid;
Packit 13e616
	uint16_t lmc_mask;
Packit 13e616
	boolean_t lids_ok;
Packit 13e616
	uint8_t lmc_num_lids = (uint8_t) (1 << p_mgr->p_subn->opt.lmc);
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	lmc_mask = ~(lmc_num_lids - 1);
Packit 13e616
Packit 13e616
	cl_qlist_init(&guids);
Packit 13e616
Packit 13e616
	if (osm_db_guid2lid_guids(p_mgr->p_g2l, &guids)) {
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0310: "
Packit 13e616
			"could not get guid list\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	while ((p_item = (osm_db_guid_elem_t *) cl_qlist_remove_head(&guids))
Packit 13e616
	       != (osm_db_guid_elem_t *) cl_qlist_end(&guids)) {
Packit 13e616
		if (osm_db_guid2lid_get(p_mgr->p_g2l, p_item->guid,
Packit 13e616
					&min_lid, &max_lid))
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0311: "
Packit 13e616
				"could not get lid for guid:0x%016" PRIx64 "\n",
Packit 13e616
				p_item->guid);
Packit 13e616
		else {
Packit 13e616
			lids_ok = TRUE;
Packit 13e616
Packit 13e616
			if (min_lid > max_lid || min_lid == 0
Packit 13e616
			    || p_item->guid == 0
Packit 13e616
			    || max_lid > p_mgr->p_subn->max_ucast_lid_ho) {
Packit 13e616
				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit 13e616
					"ERR 0312: "
Packit 13e616
					"Illegal LID range [%u:%u] for "
Packit 13e616
					"guid:0x%016" PRIx64 "\n", min_lid,
Packit 13e616
					max_lid, p_item->guid);
Packit 13e616
				lids_ok = FALSE;
Packit 13e616
			} else if (min_lid != max_lid
Packit 13e616
				   && (min_lid & lmc_mask) != min_lid) {
Packit 13e616
				/* check that if the lids define a range that is
Packit 13e616
				   valid for the current LMC mask */
Packit 13e616
				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit 13e616
					"ERR 0313: "
Packit 13e616
					"LID range [%u:%u] for guid:0x%016"
Packit 13e616
					PRIx64
Packit 13e616
					" is not aligned according to mask:0x%04x\n",
Packit 13e616
					min_lid, max_lid, p_item->guid,
Packit 13e616
					lmc_mask);
Packit 13e616
				lids_ok = FALSE;
Packit 13e616
			} else {
Packit 13e616
				/* check if the lids were not previously assigned */
Packit 13e616
				for (lid = min_lid; lid <= max_lid; lid++) {
Packit 13e616
					if (p_mgr->used_lids[lid]) {
Packit 13e616
						OSM_LOG(p_mgr->p_log,
Packit 13e616
							OSM_LOG_ERROR,
Packit 13e616
							"ERR 0314: "
Packit 13e616
							"0x%04x for guid:0x%016"
Packit 13e616
							PRIx64
Packit 13e616
							" was previously used\n",
Packit 13e616
							lid, p_item->guid);
Packit 13e616
						lids_ok = FALSE;
Packit 13e616
					}
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
Packit 13e616
			if (lids_ok)
Packit 13e616
				/* mark that it was visited */
Packit 13e616
				for (lid = min_lid; lid <= max_lid; lid++) {
Packit 13e616
					if (lid < min_lid + lmc_num_lids)
Packit 13e616
						p_mgr->used_lids[lid] = 1;
Packit 13e616
				}
Packit 13e616
			else if (osm_db_guid2lid_delete(p_mgr->p_g2l,
Packit 13e616
							p_item->guid))
Packit 13e616
				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit 13e616
					"ERR 0315: failed to delete entry for "
Packit 13e616
					"guid:0x%016" PRIx64 "\n",
Packit 13e616
					p_item->guid);
Packit 13e616
		}		/* got a lid */
Packit 13e616
		free(p_item);
Packit 13e616
	}			/* all guids */
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
ib_api_status_t osm_lid_mgr_init(IN osm_lid_mgr_t * p_mgr, IN osm_sm_t * sm)
Packit 13e616
{
Packit 13e616
	ib_api_status_t status = IB_SUCCESS;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	osm_lid_mgr_construct(p_mgr);
Packit 13e616
Packit 13e616
	p_mgr->sm = sm;
Packit 13e616
	p_mgr->p_log = sm->p_log;
Packit 13e616
	p_mgr->p_subn = sm->p_subn;
Packit 13e616
	p_mgr->p_db = sm->p_db;
Packit 13e616
	p_mgr->p_lock = sm->p_lock;
Packit 13e616
Packit 13e616
	/* we initialize and restore the db domain of guid to lid map */
Packit 13e616
	p_mgr->p_g2l = osm_db_domain_init(p_mgr->p_db, "guid2lid");
Packit 13e616
	if (!p_mgr->p_g2l) {
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0316: "
Packit 13e616
			"Error initializing Guid-to-Lid persistent database\n");
Packit 13e616
		status = IB_ERROR;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	cl_qlist_init(&p_mgr->free_ranges);
Packit 13e616
Packit 13e616
	/* we use the stored guid to lid table if not forced to reassign */
Packit 13e616
	if (!p_mgr->p_subn->opt.reassign_lids) {
Packit 13e616
		if (osm_db_restore(p_mgr->p_g2l)) {
Packit 13e616
#ifndef __WIN__
Packit 13e616
			/*
Packit 13e616
			 * When Windows is BSODing, it might corrupt files that
Packit 13e616
			 * were previously opened for writing, even if the files
Packit 13e616
			 * are closed, so we might see corrupted guid2lid file.
Packit 13e616
			 */
Packit 13e616
			if (p_mgr->p_subn->opt.exit_on_fatal) {
Packit 13e616
				osm_log_v2(p_mgr->p_log, OSM_LOG_SYS, FILE_ID,
Packit 13e616
					   "FATAL: Error restoring Guid-to-Lid "
Packit 13e616
					   "persistent database\n");
Packit 13e616
				status = IB_ERROR;
Packit 13e616
				goto Exit;
Packit 13e616
			} else
Packit 13e616
#endif
Packit 13e616
				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit 13e616
					"ERR 0317: Error restoring Guid-to-Lid "
Packit 13e616
					"persistent database\n");
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/* we need to make sure we did not get duplicates with
Packit 13e616
		   current lmc */
Packit 13e616
		lid_mgr_validate_db(p_mgr);
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
static uint16_t trim_lid(IN uint16_t lid)
Packit 13e616
{
Packit 13e616
	if (lid > IB_LID_UCAST_END_HO || lid < IB_LID_UCAST_START_HO)
Packit 13e616
		return 0;
Packit 13e616
	return lid;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 initialize the manager for a new sweep:
Packit 13e616
 scans the known persistent assignment and port_lid_tbl
Packit 13e616
 re-calculate all empty ranges.
Packit 13e616
 cleanup invalid port_lid_tbl entries
Packit 13e616
**********************************************************************/
Packit 13e616
static int lid_mgr_init_sweep(IN osm_lid_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl;
Packit 13e616
	uint16_t max_defined_lid, max_persistent_lid, max_discovered_lid;
Packit 13e616
	uint16_t disc_min_lid, disc_max_lid, db_min_lid, db_max_lid;
Packit 13e616
	int status = 0;
Packit 13e616
	cl_list_item_t *p_item;
Packit 13e616
	boolean_t is_free;
Packit 13e616
	osm_lid_mgr_range_t *p_range = NULL;
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	cl_qmap_t *p_port_guid_tbl;
Packit 13e616
	uint8_t lmc_num_lids = (uint8_t) (1 << p_mgr->p_subn->opt.lmc);
Packit 13e616
	uint16_t lmc_mask, req_lid, num_lids, lid;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
Packit 13e616
Packit 13e616
	/* We must discard previous guid2lid db if this is the first master
Packit 13e616
	 * sweep and reassign_lids option is TRUE.
Packit 13e616
	 * If we came out of standby and honor_guid2lid_file option is TRUE, we
Packit 13e616
	 * must restore guid2lid db. Otherwise if honor_guid2lid_file option is
Packit 13e616
	 * FALSE we must discard previous guid2lid db.
Packit 13e616
	 */
Packit 13e616
	if (p_mgr->p_subn->first_time_master_sweep == TRUE &&
Packit 13e616
	    p_mgr->p_subn->opt.reassign_lids == TRUE) {
Packit 13e616
		osm_db_clear(p_mgr->p_g2l);
Packit 13e616
		memset(p_mgr->used_lids, 0, sizeof(p_mgr->used_lids));
Packit 13e616
	} else if (p_mgr->p_subn->coming_out_of_standby == TRUE) {
Packit 13e616
		osm_db_clear(p_mgr->p_g2l);
Packit 13e616
		memset(p_mgr->used_lids, 0, sizeof(p_mgr->used_lids));
Packit 13e616
		if (p_mgr->p_subn->opt.honor_guid2lid_file == FALSE)
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Ignore guid2lid file when coming out of standby\n");
Packit 13e616
		else {
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Honor current guid2lid file when coming out "
Packit 13e616
				"of standby\n");
Packit 13e616
			if (osm_db_restore(p_mgr->p_g2l))
Packit 13e616
				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit 13e616
					"ERR 0306: "
Packit 13e616
					"Error restoring Guid-to-Lid "
Packit 13e616
					"persistent database. Ignoring it\n");
Packit 13e616
			lid_mgr_validate_db(p_mgr);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* we need to cleanup the empty ranges list */
Packit 13e616
	while ((p_item = cl_qlist_remove_head(&p_mgr->free_ranges)) !=
Packit 13e616
	       cl_qlist_end(&p_mgr->free_ranges))
Packit 13e616
		free((osm_lid_mgr_range_t *) p_item);
Packit 13e616
Packit 13e616
	/* first clean up the port_by_lid_tbl */
Packit 13e616
	for (lid = 0; lid < cl_ptr_vector_get_size(p_discovered_vec); lid++)
Packit 13e616
		cl_ptr_vector_set(p_discovered_vec, lid, NULL);
Packit 13e616
Packit 13e616
	/* we if are in the first sweep and in reassign lids mode
Packit 13e616
	   we should ignore all the available info and simply define one
Packit 13e616
	   huge empty range */
Packit 13e616
	if (p_mgr->p_subn->first_time_master_sweep == TRUE &&
Packit 13e616
	    p_mgr->p_subn->opt.reassign_lids == TRUE) {
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Skipping all lids as we are reassigning them\n");
Packit 13e616
		p_range = malloc(sizeof(osm_lid_mgr_range_t));
Packit 13e616
		if (p_range)
Packit 13e616
			p_range->min_lid = 1;
Packit 13e616
		goto AfterScanningLids;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* go over all discovered ports and mark their entries */
Packit 13e616
	p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl;
Packit 13e616
Packit 13e616
	for (p_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl);
Packit 13e616
	     p_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl);
Packit 13e616
	     p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) {
Packit 13e616
		osm_port_get_lid_range_ho(p_port, &disc_min_lid, &disc_max_lid);
Packit 13e616
		disc_min_lid = trim_lid(disc_min_lid);
Packit 13e616
		disc_max_lid = trim_lid(disc_max_lid);
Packit 13e616
		for (lid = disc_min_lid; lid <= disc_max_lid; lid++) {
Packit 13e616
			if (lid < disc_min_lid + lmc_num_lids)
Packit 13e616
				cl_ptr_vector_set(p_discovered_vec, lid, p_port);
Packit 13e616
			else
Packit 13e616
				cl_ptr_vector_set(p_discovered_vec, lid, NULL);
Packit 13e616
		}
Packit 13e616
		/* make sure the guid2lid entry is valid. If not, clean it. */
Packit 13e616
		if (osm_db_guid2lid_get(p_mgr->p_g2l,
Packit 13e616
					cl_ntoh64(osm_port_get_guid(p_port)),
Packit 13e616
					&db_min_lid, &db_max_lid))
Packit 13e616
			continue;
Packit 13e616
Packit 13e616
		if (!p_port->p_node->sw ||
Packit 13e616
		    osm_switch_sp0_is_lmc_capable(p_port->p_node->sw,
Packit 13e616
						  p_mgr->p_subn))
Packit 13e616
			num_lids = lmc_num_lids;
Packit 13e616
		else
Packit 13e616
			num_lids = 1;
Packit 13e616
Packit 13e616
		if (num_lids != 1 &&
Packit 13e616
		    ((db_min_lid & lmc_mask) != db_min_lid ||
Packit 13e616
		     db_max_lid - db_min_lid + 1 < num_lids)) {
Packit 13e616
			/* Not aligned, or not wide enough, then remove the entry */
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Cleaning persistent entry for guid:"
Packit 13e616
				"0x%016" PRIx64 " illegal range:[0x%x:0x%x]\n",
Packit 13e616
				cl_ntoh64(osm_port_get_guid(p_port)),
Packit 13e616
				db_min_lid, db_max_lid);
Packit 13e616
			osm_db_guid2lid_delete(p_mgr->p_g2l,
Packit 13e616
					       cl_ntoh64
Packit 13e616
					       (osm_port_get_guid(p_port)));
Packit 13e616
			for (lid = db_min_lid; lid <= db_max_lid; lid++)
Packit 13e616
				p_mgr->used_lids[lid] = 0;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Our task is to find free lid ranges.
Packit 13e616
	   A lid can be used if
Packit 13e616
	   1. a persistent assignment exists
Packit 13e616
	   2. the lid is used by a discovered port that does not have a
Packit 13e616
	   persistent assignment.
Packit 13e616
Packit 13e616
	   scan through all lid values of both the persistent table and
Packit 13e616
	   discovered table.
Packit 13e616
	   If the lid has an assigned port in the discovered table:
Packit 13e616
	   * make sure the lid matches the persistent table, or
Packit 13e616
	   * there is no other persistent assignment for that lid.
Packit 13e616
	   * else cleanup the port_by_lid_tbl, mark this as empty range.
Packit 13e616
	   Else if the lid does not have an entry in the persistent table
Packit 13e616
	   mark it as free.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	/* find the range of lids to scan */
Packit 13e616
	max_discovered_lid =
Packit 13e616
	    (uint16_t) cl_ptr_vector_get_size(p_discovered_vec);
Packit 13e616
	max_persistent_lid = sizeof(p_mgr->used_lids) - 1;
Packit 13e616
Packit 13e616
	/* but the vectors have one extra entry for lid=0 */
Packit 13e616
	if (max_discovered_lid)
Packit 13e616
		max_discovered_lid--;
Packit 13e616
Packit 13e616
	if (max_persistent_lid > max_discovered_lid)
Packit 13e616
		max_defined_lid = max_persistent_lid;
Packit 13e616
	else
Packit 13e616
		max_defined_lid = max_discovered_lid;
Packit 13e616
Packit 13e616
	for (lid = 1; lid <= max_defined_lid; lid++) {
Packit 13e616
		is_free = TRUE;
Packit 13e616
		/* first check to see if the lid is used by a persistent assignment */
Packit 13e616
		if (lid <= max_persistent_lid && p_mgr->used_lids[lid]) {
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"0x%04x is not free as its mapped by the "
Packit 13e616
				"persistent db\n", lid);
Packit 13e616
			is_free = FALSE;
Packit 13e616
			/* check this is a discovered port */
Packit 13e616
		} else if (lid <= max_discovered_lid &&
Packit 13e616
			   (p_port = cl_ptr_vector_get(p_discovered_vec,
Packit 13e616
						       lid))) {
Packit 13e616
			/* we have a port. Now lets see if we can preserve its lid range. */
Packit 13e616
			/* For that, we need to make sure:
Packit 13e616
			   1. The port has a (legal) persistency entry. Then the
Packit 13e616
			   local lid is free (we will use the persistency value).
Packit 13e616
			   2. Can the port keep its local assignment?
Packit 13e616
			   a. Make sure the lid is aligned.
Packit 13e616
			   b. Make sure all needed lids (for the lmc) are free
Packit 13e616
			   according to persistency table.
Packit 13e616
			 */
Packit 13e616
			/* qualify the guid of the port is not persistently
Packit 13e616
			   mapped to another range */
Packit 13e616
			if (!osm_db_guid2lid_get(p_mgr->p_g2l,
Packit 13e616
						 cl_ntoh64
Packit 13e616
						 (osm_port_get_guid(p_port)),
Packit 13e616
						 &db_min_lid, &db_max_lid)) {
Packit 13e616
				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
					"0x%04x is free as it was "
Packit 13e616
					"discovered but mapped by the "
Packit 13e616
					"persistent db to [0x%04x:0x%04x]\n",
Packit 13e616
					lid, db_min_lid, db_max_lid);
Packit 13e616
			} else {
Packit 13e616
				/* can the port keep its assignment ? */
Packit 13e616
				/* get the lid range of that port, and the
Packit 13e616
				   required number of lids we are about to
Packit 13e616
				   assign to it */
Packit 13e616
				osm_port_get_lid_range_ho(p_port,
Packit 13e616
							  &disc_min_lid,
Packit 13e616
							  &disc_max_lid);
Packit 13e616
				if (!p_port->p_node->sw ||
Packit 13e616
				    osm_switch_sp0_is_lmc_capable
Packit 13e616
				    (p_port->p_node->sw, p_mgr->p_subn)) {
Packit 13e616
					disc_max_lid =
Packit 13e616
					    disc_min_lid + lmc_num_lids - 1;
Packit 13e616
					num_lids = lmc_num_lids;
Packit 13e616
				} else
Packit 13e616
					num_lids = 1;
Packit 13e616
Packit 13e616
				/* Make sure the lid is aligned */
Packit 13e616
				if (num_lids != 1
Packit 13e616
				    && (disc_min_lid & lmc_mask) !=
Packit 13e616
				    disc_min_lid) {
Packit 13e616
					/* The lid cannot be used */
Packit 13e616
					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
						"0x%04x is free as it was "
Packit 13e616
						"discovered but not aligned\n",
Packit 13e616
						lid);
Packit 13e616
				} else {
Packit 13e616
					/* check that all needed lids are not persistently mapped */
Packit 13e616
					is_free = FALSE;
Packit 13e616
					for (req_lid = disc_min_lid + 1;
Packit 13e616
					     req_lid <= disc_max_lid;
Packit 13e616
					     req_lid++) {
Packit 13e616
						if (req_lid <=
Packit 13e616
						    max_persistent_lid &&
Packit 13e616
						    p_mgr->used_lids[req_lid]) {
Packit 13e616
							OSM_LOG(p_mgr->p_log,
Packit 13e616
								OSM_LOG_DEBUG,
Packit 13e616
								"0x%04x is free as it was discovered "
Packit 13e616
								"but mapped\n",
Packit 13e616
								lid);
Packit 13e616
							is_free = TRUE;
Packit 13e616
							break;
Packit 13e616
						}
Packit 13e616
					}
Packit 13e616
Packit 13e616
					if (is_free == FALSE) {
Packit 13e616
						/* This port will use its local lid, and consume the entire required lid range.
Packit 13e616
						   Thus we can skip that range. */
Packit 13e616
						/* If the disc_max_lid is greater then lid, we can skip right to it,
Packit 13e616
						   since we've done all neccessary checks on the lids in between. */
Packit 13e616
						if (disc_max_lid > lid)
Packit 13e616
							lid = disc_max_lid;
Packit 13e616
					}
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (is_free) {
Packit 13e616
			if (p_range)
Packit 13e616
				p_range->max_lid = lid;
Packit 13e616
			else {
Packit 13e616
				p_range = malloc(sizeof(osm_lid_mgr_range_t));
Packit 13e616
				if (p_range) {
Packit 13e616
					p_range->min_lid = lid;
Packit 13e616
					p_range->max_lid = lid;
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
		/* this lid is used so we need to finalize the previous free range */
Packit 13e616
		} else if (p_range) {
Packit 13e616
			cl_qlist_insert_tail(&p_mgr->free_ranges,
Packit 13e616
					     &p_range->item);
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"new free lid range [%u:%u]\n",
Packit 13e616
				p_range->min_lid, p_range->max_lid);
Packit 13e616
			p_range = NULL;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
AfterScanningLids:
Packit 13e616
	/* after scanning all known lids we need to extend the last range
Packit 13e616
	   to the max allowed lid */
Packit 13e616
	if (!p_range) {
Packit 13e616
		p_range = malloc(sizeof(osm_lid_mgr_range_t));
Packit 13e616
		/*
Packit 13e616
		   The p_range can be NULL in one of 2 cases:
Packit 13e616
		   1. If max_defined_lid == 0. In this case, we want the
Packit 13e616
		   entire range.
Packit 13e616
		   2. If all lids discovered in the loop where mapped. In this
Packit 13e616
		   case, no free range exists and we want to define it after the
Packit 13e616
		   last mapped lid.
Packit 13e616
		 */
Packit 13e616
		if (p_range)
Packit 13e616
			p_range->min_lid = lid;
Packit 13e616
	}
Packit 13e616
	if (p_range) {
Packit 13e616
		p_range->max_lid = p_mgr->p_subn->max_ucast_lid_ho;
Packit 13e616
		cl_qlist_insert_tail(&p_mgr->free_ranges, &p_range->item);
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"final free lid range [%u:%u]\n",
Packit 13e616
			p_range->min_lid, p_range->max_lid);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 check if the given range of lids is free
Packit 13e616
**********************************************************************/
Packit 13e616
static boolean_t lid_mgr_is_range_not_persistent(IN osm_lid_mgr_t * p_mgr,
Packit 13e616
						 IN uint16_t lid,
Packit 13e616
						 IN uint16_t num_lids)
Packit 13e616
{
Packit 13e616
	uint16_t i;
Packit 13e616
Packit 13e616
	for (i = lid; i < lid + num_lids; i++)
Packit 13e616
		if (p_mgr->used_lids[i])
Packit 13e616
			return FALSE;
Packit 13e616
Packit 13e616
	return TRUE;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
find a free lid range
Packit 13e616
**********************************************************************/
Packit 13e616
static void lid_mgr_find_free_lid_range(IN osm_lid_mgr_t * p_mgr,
Packit 13e616
					IN uint8_t num_lids,
Packit 13e616
					OUT uint16_t * p_min_lid,
Packit 13e616
					OUT uint16_t * p_max_lid)
Packit 13e616
{
Packit 13e616
	uint16_t lid;
Packit 13e616
	cl_list_item_t *p_item;
Packit 13e616
	cl_list_item_t *p_next_item;
Packit 13e616
	osm_lid_mgr_range_t *p_range = NULL;
Packit 13e616
	uint8_t lmc_num_lids;
Packit 13e616
	uint16_t lmc_mask;
Packit 13e616
Packit 13e616
	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "LMC = %u, number LIDs = %u\n",
Packit 13e616
		p_mgr->p_subn->opt.lmc, num_lids);
Packit 13e616
Packit 13e616
	lmc_num_lids = (1 << p_mgr->p_subn->opt.lmc);
Packit 13e616
	lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Search the list of free lid ranges for a range which is big enough
Packit 13e616
	 */
Packit 13e616
	p_item = cl_qlist_head(&p_mgr->free_ranges);
Packit 13e616
	while (p_item != cl_qlist_end(&p_mgr->free_ranges)) {
Packit 13e616
		p_next_item = cl_qlist_next(p_item);
Packit 13e616
		p_range = (osm_lid_mgr_range_t *) p_item;
Packit 13e616
Packit 13e616
		lid = p_range->min_lid;
Packit 13e616
Packit 13e616
		/* if we require more then one lid we must align to LMC */
Packit 13e616
		if (num_lids > 1) {
Packit 13e616
			if ((lid & lmc_mask) != lid)
Packit 13e616
				lid = (lid + lmc_num_lids) & lmc_mask;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/* but we can be out of the range */
Packit 13e616
		if (lid + num_lids - 1 <= p_range->max_lid) {
Packit 13e616
			/* ok let us use that range */
Packit 13e616
			if (lid + num_lids - 1 == p_range->max_lid) {
Packit 13e616
				/* we consumed the entire range */
Packit 13e616
				cl_qlist_remove_item(&p_mgr->free_ranges,
Packit 13e616
						     p_item);
Packit 13e616
				free(p_item);
Packit 13e616
			} else
Packit 13e616
				/* only update the available range */
Packit 13e616
				p_range->min_lid = lid + num_lids;
Packit 13e616
Packit 13e616
			*p_min_lid = lid;
Packit 13e616
			*p_max_lid = (uint16_t) (lid + num_lids - 1);
Packit 13e616
			return;
Packit 13e616
		}
Packit 13e616
		p_item = p_next_item;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Couldn't find a free range of lids.
Packit 13e616
	 */
Packit 13e616
	*p_min_lid = *p_max_lid = 0;
Packit 13e616
	/* if we run out of lids, give an error and abort! */
Packit 13e616
	OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0307: "
Packit 13e616
		"OPENSM RAN OUT OF LIDS!!!\n");
Packit 13e616
	CL_ASSERT(0);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void lid_mgr_cleanup_discovered_port_lid_range(IN osm_lid_mgr_t * p_mgr,
Packit 13e616
						      IN osm_port_t * p_port)
Packit 13e616
{
Packit 13e616
	cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl;
Packit 13e616
	uint16_t lid, min_lid, max_lid;
Packit 13e616
	uint16_t max_tbl_lid =
Packit 13e616
	    (uint16_t) (cl_ptr_vector_get_size(p_discovered_vec));
Packit 13e616
Packit 13e616
	osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid);
Packit 13e616
	min_lid = trim_lid(min_lid);
Packit 13e616
	max_lid = trim_lid(max_lid);
Packit 13e616
	for (lid = min_lid; lid <= max_lid; lid++)
Packit 13e616
		if (lid < max_tbl_lid &&
Packit 13e616
		    p_port == cl_ptr_vector_get(p_discovered_vec, lid))
Packit 13e616
			cl_ptr_vector_set(p_discovered_vec, lid, NULL);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 0.1 if the port info lid matches the guid2lid return 0
Packit 13e616
 0.2 if the port info has a lid and that range is empty in
Packit 13e616
     port_lid_tbl, return 0 and update the port_lid_tbl and
Packit 13e616
     guid2lid
Packit 13e616
 0.3 else find an empty space in port_lid_tbl, update the
Packit 13e616
 port_lid_tbl and guid2lid, return 1 to flag a change required.
Packit 13e616
**********************************************************************/
Packit 13e616
static int lid_mgr_get_port_lid(IN osm_lid_mgr_t * p_mgr,
Packit 13e616
				IN osm_port_t * p_port,
Packit 13e616
				OUT uint16_t * p_min_lid,
Packit 13e616
				OUT uint16_t * p_max_lid)
Packit 13e616
{
Packit 13e616
	uint16_t lid, min_lid, max_lid;
Packit 13e616
	uint64_t guid;
Packit 13e616
	uint8_t num_lids = (1 << p_mgr->p_subn->opt.lmc);
Packit 13e616
	int lid_changed = 0;
Packit 13e616
	uint16_t lmc_mask;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	/* get the lid from the guid2lid */
Packit 13e616
	guid = cl_ntoh64(osm_port_get_guid(p_port));
Packit 13e616
Packit 13e616
	/* if the port is a base switch port 0 then we only need one lid */
Packit 13e616
	if (p_port->p_node->sw &&
Packit 13e616
	    !osm_switch_sp0_is_lmc_capable(p_port->p_node->sw, p_mgr->p_subn))
Packit 13e616
		num_lids = 1;
Packit 13e616
Packit 13e616
	if (p_mgr->p_subn->first_time_master_sweep == TRUE &&
Packit 13e616
	    p_mgr->p_subn->opt.reassign_lids == TRUE)
Packit 13e616
		goto AssignLid;
Packit 13e616
Packit 13e616
	lmc_mask = ~(num_lids - 1);
Packit 13e616
Packit 13e616
	/* if the port matches the guid2lid */
Packit 13e616
	if (!osm_db_guid2lid_get(p_mgr->p_g2l, guid, &min_lid, &max_lid)) {
Packit 13e616
		*p_min_lid = min_lid;
Packit 13e616
		*p_max_lid = min_lid + num_lids - 1;
Packit 13e616
		if (min_lid == cl_ntoh16(osm_port_get_base_lid(p_port)))
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "0x%016" PRIx64
Packit 13e616
				" matches its known lid:%u\n", guid, min_lid);
Packit 13e616
		else {
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"0x%016" PRIx64 " with lid:%u "
Packit 13e616
				"does not match its known lid:%u\n",
Packit 13e616
				guid, cl_ntoh16(osm_port_get_base_lid(p_port)),
Packit 13e616
				min_lid);
Packit 13e616
			lid_mgr_cleanup_discovered_port_lid_range(p_mgr,
Packit 13e616
								  p_port);
Packit 13e616
			/* we still need to send the setting to the target port */
Packit 13e616
			lid_changed = 1;
Packit 13e616
		}
Packit 13e616
		goto NewLidSet;
Packit 13e616
	} else
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"0x%016" PRIx64 " has no persistent lid assigned\n",
Packit 13e616
			guid);
Packit 13e616
Packit 13e616
	/* if the port info carries a lid it must be lmc aligned and not mapped
Packit 13e616
	   by the persistent storage  */
Packit 13e616
	min_lid = cl_ntoh16(osm_port_get_base_lid(p_port));
Packit 13e616
Packit 13e616
	/* we want to ignore the discovered lid if we are also on first sweep of
Packit 13e616
	   reassign lids flow */
Packit 13e616
	if (min_lid) {
Packit 13e616
		/* make sure lid is valid */
Packit 13e616
		if ((min_lid & lmc_mask) == min_lid) {
Packit 13e616
			/* is it free */
Packit 13e616
			if (lid_mgr_is_range_not_persistent
Packit 13e616
			    (p_mgr, min_lid, num_lids)) {
Packit 13e616
				*p_min_lid = min_lid;
Packit 13e616
				*p_max_lid = min_lid + num_lids - 1;
Packit 13e616
				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
					"0x%016" PRIx64
Packit 13e616
					" lid range:[%u-%u] is free\n",
Packit 13e616
					guid, *p_min_lid, *p_max_lid);
Packit 13e616
				goto NewLidSet;
Packit 13e616
			} else
Packit 13e616
				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
					"0x%016" PRIx64 " existing lid "
Packit 13e616
					"range:[%u:%u] is not free\n",
Packit 13e616
					guid, min_lid, min_lid + num_lids - 1);
Packit 13e616
		} else
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"0x%016" PRIx64 " existing lid range:"
Packit 13e616
				"[%u:%u] is not lmc aligned\n",
Packit 13e616
				guid, min_lid, min_lid + num_lids - 1);
Packit 13e616
	}
Packit 13e616
Packit 13e616
AssignLid:
Packit 13e616
	/* first cleanup the existing discovered lid range */
Packit 13e616
	lid_mgr_cleanup_discovered_port_lid_range(p_mgr, p_port);
Packit 13e616
Packit 13e616
	/* find an empty space */
Packit 13e616
	lid_mgr_find_free_lid_range(p_mgr, num_lids, p_min_lid, p_max_lid);
Packit 13e616
	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"0x%016" PRIx64 " assigned a new lid range:[%u-%u]\n",
Packit 13e616
		guid, *p_min_lid, *p_max_lid);
Packit 13e616
	lid_changed = 1;
Packit 13e616
Packit 13e616
NewLidSet:
Packit 13e616
	/* update the guid2lid db and used_lids */
Packit 13e616
	osm_db_guid2lid_set(p_mgr->p_g2l, guid, *p_min_lid, *p_max_lid);
Packit 13e616
	for (lid = *p_min_lid; lid <= *p_max_lid; lid++)
Packit 13e616
		p_mgr->used_lids[lid] = 1;
Packit 13e616
Packit 13e616
	/* make sure the assigned lids are marked in port_lid_tbl */
Packit 13e616
	for (lid = *p_min_lid; lid <= *p_max_lid; lid++)
Packit 13e616
		cl_ptr_vector_set(&p_mgr->p_subn->port_lid_tbl, lid, p_port);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
	return lid_changed;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Set to INIT the remote port of the given physical port
Packit 13e616
 **********************************************************************/
Packit 13e616
static void lid_mgr_set_remote_pi_state_to_init(IN osm_lid_mgr_t * p_mgr,
Packit 13e616
						IN osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
	osm_physp_t *p_rem_physp = osm_physp_get_remote(p_physp);
Packit 13e616
Packit 13e616
	if (p_rem_physp == NULL)
Packit 13e616
		return;
Packit 13e616
Packit 13e616
	/* but in some rare cases the remote side might be non responsive */
Packit 13e616
	ib_port_info_set_port_state(&p_rem_physp->port_info, IB_LINK_INIT);
Packit 13e616
}
Packit 13e616
Packit 13e616
static int lid_mgr_set_physp_pi(IN osm_lid_mgr_t * p_mgr,
Packit 13e616
				IN osm_port_t * p_port,
Packit 13e616
				IN osm_physp_t * p_physp, IN ib_net16_t lid)
Packit 13e616
{
Packit 13e616
	uint8_t payload[IB_SMP_DATA_SIZE];
Packit 13e616
	ib_port_info_t *p_pi = (ib_port_info_t *) payload;
Packit 13e616
	const ib_port_info_t *p_old_pi;
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
	osm_node_t *p_node;
Packit 13e616
	ib_api_status_t status;
Packit 13e616
	uint8_t mtu;
Packit 13e616
	uint8_t op_vls;
Packit 13e616
	uint8_t port_num;
Packit 13e616
	boolean_t send_set = FALSE;
Packit 13e616
	boolean_t send_client_rereg = FALSE;
Packit 13e616
	boolean_t update_mkey = FALSE;
Packit 13e616
	int ret = 0;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Don't bother doing anything if this Physical Port is not valid.
Packit 13e616
	   This allows simplified code in the caller.
Packit 13e616
	 */
Packit 13e616
	if (!p_physp)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	port_num = osm_physp_get_port_num(p_physp);
Packit 13e616
	p_node = osm_physp_get_node_ptr(p_physp);
Packit 13e616
Packit 13e616
	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && port_num != 0) {
Packit 13e616
		/*
Packit 13e616
		   Switch ports that are not numbered 0 should not be set
Packit 13e616
		   with the following attributes as they are set later
Packit 13e616
		   (during NO_CHANGE state in link mgr).
Packit 13e616
		 */
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Skipping switch port %u, GUID 0x%016" PRIx64 "\n",
Packit 13e616
			port_num, cl_ntoh64(osm_physp_get_port_guid(p_physp)));
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_old_pi = &p_physp->port_info;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   First, copy existing parameters from the PortInfo attribute we
Packit 13e616
	   already have for this node.
Packit 13e616
Packit 13e616
	   Second, update with default values that we know must be set for
Packit 13e616
	   every Physical Port and the LID and set the neighbor MTU field
Packit 13e616
	   appropriately.
Packit 13e616
Packit 13e616
	   Third, send the SMP to this physical port.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	memcpy(payload, p_old_pi, sizeof(ib_port_info_t));
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Should never write back a value that is bigger then 3 in
Packit 13e616
	   the PortPhysicalState field, so cannot simply copy!
Packit 13e616
Packit 13e616
	   Actually we want to write there:
Packit 13e616
	   port physical state - no change
Packit 13e616
	   link down default state = polling
Packit 13e616
	   port state - no change
Packit 13e616
	 */
Packit 13e616
	p_pi->state_info2 = 0x02;
Packit 13e616
	ib_port_info_set_port_state(p_pi, IB_LINK_NO_CHANGE);
Packit 13e616
Packit 13e616
	if (ib_port_info_get_link_down_def_state(p_pi) !=
Packit 13e616
	    ib_port_info_get_link_down_def_state(p_old_pi))
Packit 13e616
		send_set = TRUE;
Packit 13e616
Packit 13e616
	/* didn't get PortInfo before */
Packit 13e616
	if (!ib_port_info_get_port_state(p_old_pi))
Packit 13e616
		send_set = TRUE;
Packit 13e616
Packit 13e616
	p_pi->m_key = p_mgr->p_subn->opt.m_key;
Packit 13e616
	if (memcmp(&p_pi->m_key, &p_old_pi->m_key, sizeof(p_pi->m_key))) {
Packit 13e616
		update_mkey = TRUE;
Packit 13e616
		send_set = TRUE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_pi->subnet_prefix = p_mgr->p_subn->opt.subnet_prefix;
Packit 13e616
	if (memcmp(&p_pi->subnet_prefix, &p_old_pi->subnet_prefix,
Packit 13e616
		   sizeof(p_pi->subnet_prefix)))
Packit 13e616
		send_set = TRUE;
Packit 13e616
Packit 13e616
	p_port->lid = lid;
Packit 13e616
	p_pi->base_lid = lid;
Packit 13e616
	if (memcmp(&p_pi->base_lid, &p_old_pi->base_lid,
Packit 13e616
		   sizeof(p_pi->base_lid))) {
Packit 13e616
		/*
Packit 13e616
		 * Reset stored base_lid.
Packit 13e616
		 * On successful send, we'll update it when we'll get a reply.
Packit 13e616
		 */
Packit 13e616
		osm_physp_set_base_lid(p_physp, 0);
Packit 13e616
		send_set = TRUE;
Packit 13e616
		p_mgr->dirty = TRUE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   We are updating the ports with our local sm_base_lid
Packit 13e616
	   if for some reason currently received SM LID is different from our SM LID,
Packit 13e616
	   need to send client reregister to this port
Packit 13e616
	*/
Packit 13e616
	p_pi->master_sm_base_lid = p_mgr->p_subn->sm_base_lid;
Packit 13e616
	if (memcmp(&p_pi->master_sm_base_lid, &p_old_pi->master_sm_base_lid,
Packit 13e616
		   sizeof(p_pi->master_sm_base_lid))) {
Packit 13e616
		send_client_rereg = TRUE;
Packit 13e616
		send_set = TRUE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_pi->m_key_lease_period = p_mgr->p_subn->opt.m_key_lease_period;
Packit 13e616
	if (memcmp(&p_pi->m_key_lease_period, &p_old_pi->m_key_lease_period,
Packit 13e616
		   sizeof(p_pi->m_key_lease_period)))
Packit 13e616
		send_set = TRUE;
Packit 13e616
Packit 13e616
	p_pi->mkey_lmc = 0;
Packit 13e616
	ib_port_info_set_mpb(p_pi, p_mgr->p_subn->opt.m_key_protect_bits);
Packit 13e616
	if (ib_port_info_get_mpb(p_pi) != ib_port_info_get_mpb(p_old_pi))
Packit 13e616
		send_set = TRUE;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   we want to set the timeout for both the switch port 0
Packit 13e616
	   and the CA ports
Packit 13e616
	 */
Packit 13e616
	ib_port_info_set_timeout(p_pi, p_mgr->p_subn->opt.subnet_timeout);
Packit 13e616
	if (ib_port_info_get_timeout(p_pi) !=
Packit 13e616
	    ib_port_info_get_timeout(p_old_pi))
Packit 13e616
		send_set = TRUE;
Packit 13e616
Packit 13e616
	if (port_num != 0) {
Packit 13e616
		/*
Packit 13e616
		   CAs don't have a port 0, and for switch port 0,
Packit 13e616
		   the state bits are ignored.
Packit 13e616
		   This is not the switch management port
Packit 13e616
		 */
Packit 13e616
Packit 13e616
		/* p_pi->mkey_lmc is initialized earlier */
Packit 13e616
		ib_port_info_set_lmc(p_pi, p_mgr->p_subn->opt.lmc);
Packit 13e616
		if (ib_port_info_get_lmc(p_pi) !=
Packit 13e616
		    ib_port_info_get_lmc(p_old_pi))
Packit 13e616
			send_set = TRUE;
Packit 13e616
Packit 13e616
		/* calc new op_vls and mtu */
Packit 13e616
		op_vls = osm_physp_calc_link_op_vls(p_mgr->p_log, p_mgr->p_subn,
Packit 13e616
					      p_physp,
Packit 13e616
					      ib_port_info_get_op_vls(p_old_pi));
Packit 13e616
		mtu = osm_physp_calc_link_mtu(p_mgr->p_log, p_physp,
Packit 13e616
					      ib_port_info_get_neighbor_mtu(p_old_pi));
Packit 13e616
Packit 13e616
		ib_port_info_set_neighbor_mtu(p_pi, mtu);
Packit 13e616
Packit 13e616
		if (ib_port_info_get_neighbor_mtu(p_pi) !=
Packit 13e616
		    ib_port_info_get_neighbor_mtu(p_old_pi))
Packit 13e616
			send_set = TRUE;
Packit 13e616
Packit 13e616
		ib_port_info_set_op_vls(p_pi, op_vls);
Packit 13e616
		if (ib_port_info_get_op_vls(p_pi) !=
Packit 13e616
		    ib_port_info_get_op_vls(p_old_pi))
Packit 13e616
			send_set = TRUE;
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Several timeout mechanisms:
Packit 13e616
		 */
Packit 13e616
		ib_port_info_set_phy_and_overrun_err_thd(p_pi,
Packit 13e616
							 p_mgr->p_subn->opt.
Packit 13e616
							 local_phy_errors_threshold,
Packit 13e616
							 p_mgr->p_subn->opt.
Packit 13e616
							 overrun_errors_threshold);
Packit 13e616
Packit 13e616
		if (p_pi->error_threshold != p_old_pi->error_threshold)
Packit 13e616
			send_set = TRUE;
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   To reset the port state machine we can send
Packit 13e616
		   PortInfo.State = DOWN. (see: 7.2.7 p171 lines:10-19)
Packit 13e616
		 */
Packit 13e616
		if (mtu != ib_port_info_get_neighbor_mtu(p_old_pi) ||
Packit 13e616
		    op_vls != ib_port_info_get_op_vls(p_old_pi)) {
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Sending Link Down to GUID 0x%016"
Packit 13e616
				PRIx64 " port %d due to op_vls or "
Packit 13e616
				"mtu change. MTU:%u,%u VL_CAP:%u,%u\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_physp)),
Packit 13e616
				port_num, mtu,
Packit 13e616
				ib_port_info_get_neighbor_mtu(p_old_pi),
Packit 13e616
				op_vls, ib_port_info_get_op_vls(p_old_pi));
Packit 13e616
Packit 13e616
			/*
Packit 13e616
			   we need to make sure the internal DB will follow the
Packit 13e616
			   fact that the remote port is also going through
Packit 13e616
			   "down" state into "init"...
Packit 13e616
			 */
Packit 13e616
			lid_mgr_set_remote_pi_state_to_init(p_mgr, p_physp);
Packit 13e616
Packit 13e616
			ib_port_info_set_port_state(p_pi, IB_LINK_DOWN);
Packit 13e616
			if (ib_port_info_get_port_state(p_pi) !=
Packit 13e616
			    ib_port_info_get_port_state(p_old_pi))
Packit 13e616
				send_set = TRUE;
Packit 13e616
		}
Packit 13e616
	} else if (ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)) {
Packit 13e616
		/*
Packit 13e616
		 * Configure Enh. SP0:
Packit 13e616
		 * Set MTU according to the mtu_cap.
Packit 13e616
		 * Set LMC if lmc_esp0 is defined.
Packit 13e616
		 */
Packit 13e616
		ib_port_info_set_neighbor_mtu(p_pi,
Packit 13e616
					      ib_port_info_get_mtu_cap
Packit 13e616
					      (p_old_pi));
Packit 13e616
		if (ib_port_info_get_neighbor_mtu(p_pi) !=
Packit 13e616
		    ib_port_info_get_neighbor_mtu(p_old_pi))
Packit 13e616
			send_set = TRUE;
Packit 13e616
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Updating neighbor_mtu on switch GUID 0x%016" PRIx64
Packit 13e616
			" port 0 to:%u\n",
Packit 13e616
			cl_ntoh64(osm_physp_get_port_guid(p_physp)),
Packit 13e616
			ib_port_info_get_neighbor_mtu(p_pi));
Packit 13e616
Packit 13e616
		/* Configure LMC on enhanced SP0 */
Packit 13e616
		if (p_mgr->p_subn->opt.lmc_esp0) {
Packit 13e616
			/* p_pi->mkey_lmc is initialized earlier */
Packit 13e616
			ib_port_info_set_lmc(p_pi, p_mgr->p_subn->opt.lmc);
Packit 13e616
			if (ib_port_info_get_lmc(p_pi) !=
Packit 13e616
			    ib_port_info_get_lmc(p_old_pi))
Packit 13e616
				send_set = TRUE;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	context.pi_context.node_guid = osm_node_get_node_guid(p_node);
Packit 13e616
	context.pi_context.port_guid = osm_physp_get_port_guid(p_physp);
Packit 13e616
	context.pi_context.set_method = TRUE;
Packit 13e616
	context.pi_context.light_sweep = FALSE;
Packit 13e616
	context.pi_context.active_transition = FALSE;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	  For ports supporting the ClientReregistration Vol1 (v1.2) p811 14.4.11:
Packit 13e616
	  need to set the cli_rereg bit when current SM LID at the Host
Packit 13e616
	  is different from our SM LID,
Packit 13e616
	  also if we are in first_time_master_sweep,
Packit 13e616
	  also if this port was just now discovered, then we should also set
Packit 13e616
	  the cli_rereg bit (we know that the port was just discovered
Packit 13e616
	  if its is_new field is set).
Packit 13e616
	*/
Packit 13e616
	if  ((send_client_rereg ||
Packit 13e616
	    p_mgr->p_subn->first_time_master_sweep == TRUE || p_port->is_new)
Packit 13e616
	    && !p_mgr->p_subn->opt.no_clients_rereg
Packit 13e616
	    && (p_old_pi->capability_mask & IB_PORT_CAP_HAS_CLIENT_REREG)) {
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Setting client rereg on %s, port %d\n",
Packit 13e616
			p_port->p_node->print_desc, p_port->p_physp->port_num);
Packit 13e616
		ib_port_info_set_client_rereg(p_pi, 1);
Packit 13e616
		context.pi_context.client_rereg = TRUE;
Packit 13e616
		send_set = TRUE;
Packit 13e616
	} else {
Packit 13e616
		ib_port_info_set_client_rereg(p_pi, 0);
Packit 13e616
		context.pi_context.client_rereg = FALSE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* We need to send the PortInfo Set request with the new sm_lid
Packit 13e616
	   in the following cases:
Packit 13e616
	   1. There is a change in the values (send_set == TRUE)
Packit 13e616
	   2. first_time_master_sweep flag on the subnet is TRUE. This means the
Packit 13e616
	   SM just became master, and it then needs to send a PortInfo Set to
Packit 13e616
	   every port.
Packit 13e616
	 */
Packit 13e616
	if (p_mgr->p_subn->first_time_master_sweep == TRUE)
Packit 13e616
		send_set = TRUE;
Packit 13e616
Packit 13e616
	if (!send_set)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	status = osm_req_set(p_mgr->sm, osm_physp_get_dr_path_ptr(p_physp),
Packit 13e616
			     payload, sizeof(payload), IB_MAD_ATTR_PORT_INFO,
Packit 13e616
			     cl_hton32(osm_physp_get_port_num(p_physp)),
Packit 13e616
			     FALSE, ib_port_info_get_m_key(&p_physp->port_info),
Packit 13e616
			     0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		ret = -1;
Packit 13e616
	/* If we sent a new mkey above, update our guid2mkey map
Packit 13e616
	   now, on the assumption that the SubnSet succeeds
Packit 13e616
	*/
Packit 13e616
	if (update_mkey)
Packit 13e616
		osm_db_guid2mkey_set(p_mgr->p_subn->p_g2m,
Packit 13e616
				     cl_ntoh64(p_physp->port_guid),
Packit 13e616
				     cl_ntoh64(p_pi->m_key));
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
	return ret;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Processes our own node
Packit 13e616
 Lock must already be held.
Packit 13e616
**********************************************************************/
Packit 13e616
static int lid_mgr_process_our_sm_node(IN osm_lid_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	uint16_t min_lid_ho;
Packit 13e616
	uint16_t max_lid_ho;
Packit 13e616
	int ret;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Acquire our own port object.
Packit 13e616
	 */
Packit 13e616
	p_port = osm_get_port_by_guid(p_mgr->p_subn,
Packit 13e616
				      p_mgr->p_subn->sm_port_guid);
Packit 13e616
	if (!p_port) {
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0308: "
Packit 13e616
			"Can't acquire SM's port object, GUID 0x%016" PRIx64
Packit 13e616
			"\n", cl_ntoh64(p_mgr->p_subn->sm_port_guid));
Packit 13e616
		ret = -1;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Determine the LID this SM will use for its own port.
Packit 13e616
	   Be careful.  With an LMC > 0, the bottom of the LID range becomes
Packit 13e616
	   unusable, since port hardware will mask off least significant bits,
Packit 13e616
	   leaving a LID of 0 (invalid).  Therefore, make sure that we always
Packit 13e616
	   configure the SM with a LID that has non-zero bits, even after
Packit 13e616
	   LMC masking by hardware.
Packit 13e616
	 */
Packit 13e616
	lid_mgr_get_port_lid(p_mgr, p_port, &min_lid_ho, &max_lid_ho);
Packit 13e616
	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Current base LID is %u\n", min_lid_ho);
Packit 13e616
	/*
Packit 13e616
	   Update subnet object.
Packit 13e616
	 */
Packit 13e616
	p_mgr->p_subn->master_sm_base_lid = cl_hton16(min_lid_ho);
Packit 13e616
	p_mgr->p_subn->sm_base_lid = cl_hton16(min_lid_ho);
Packit 13e616
Packit 13e616
	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
Packit 13e616
		"Assigning SM's port 0x%016" PRIx64
Packit 13e616
		"\n\t\t\t\tto LID range [%u,%u]\n",
Packit 13e616
		cl_ntoh64(osm_port_get_guid(p_port)), min_lid_ho, max_lid_ho);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Set the PortInfo the Physical Port associated with this Port.
Packit 13e616
	 */
Packit 13e616
	ret = lid_mgr_set_physp_pi(p_mgr, p_port, p_port->p_physp,
Packit 13e616
				   cl_hton16(min_lid_ho));
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
	return ret;
Packit 13e616
}
Packit 13e616
Packit 13e616
int osm_lid_mgr_process_sm(IN osm_lid_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	int ret;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_mgr->p_subn->sm_port_guid);
Packit 13e616
Packit 13e616
	CL_PLOCK_EXCL_ACQUIRE(p_mgr->p_lock);
Packit 13e616
Packit 13e616
	/* initialize the port_lid_tbl and empty ranges list following the
Packit 13e616
	   persistent db */
Packit 13e616
	lid_mgr_init_sweep(p_mgr);
Packit 13e616
Packit 13e616
	ret = lid_mgr_process_our_sm_node(p_mgr);
Packit 13e616
Packit 13e616
	CL_PLOCK_RELEASE(p_mgr->p_lock);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
	return ret;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 1 go through all ports in the subnet.
Packit 13e616
 1.1 call lid_mgr_get_port_lid
Packit 13e616
 1.2 if a change is required send the port info
Packit 13e616
 2 if any change send the signal PENDING...
Packit 13e616
**********************************************************************/
Packit 13e616
int osm_lid_mgr_process_subnet(IN osm_lid_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	cl_qmap_t *p_port_guid_tbl;
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	ib_net64_t port_guid;
Packit 13e616
	int lid_changed, ret = 0;
Packit 13e616
	uint16_t min_lid_ho, max_lid_ho;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_mgr);
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	CL_PLOCK_EXCL_ACQUIRE(p_mgr->p_lock);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_mgr->p_subn->sm_port_guid);
Packit 13e616
Packit 13e616
	p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl;
Packit 13e616
Packit 13e616
	for (p_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl);
Packit 13e616
	     p_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl);
Packit 13e616
	     p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) {
Packit 13e616
		port_guid = osm_port_get_guid(p_port);
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Our own port is a special case in that we want to
Packit 13e616
		   assign a LID to ourselves first, since we have to
Packit 13e616
		   advertise that LID value to the other ports.
Packit 13e616
Packit 13e616
		   For that reason, our node is treated separately and
Packit 13e616
		   we will not add it to any of these lists.
Packit 13e616
		 */
Packit 13e616
		if (port_guid == p_mgr->p_subn->sm_port_guid) {
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Skipping our own port 0x%016" PRIx64 "\n",
Packit 13e616
				cl_ntoh64(port_guid));
Packit 13e616
			continue;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   get the port lid range - we need to send it on first active
Packit 13e616
		   sweep or if there was a change (the result of
Packit 13e616
		   lid_mgr_get_port_lid)
Packit 13e616
		 */
Packit 13e616
		lid_changed = lid_mgr_get_port_lid(p_mgr, p_port,
Packit 13e616
						   &min_lid_ho, &max_lid_ho);
Packit 13e616
Packit 13e616
		/* we can call the function to update the port info as it known
Packit 13e616
		   to look for any field change and will only send an updated
Packit 13e616
		   if required */
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Assigned port 0x%016" PRIx64 ", %s LID [%u,%u]\n",
Packit 13e616
			cl_ntoh64(port_guid), lid_changed ? "new" : "",
Packit 13e616
			min_lid_ho, max_lid_ho);
Packit 13e616
Packit 13e616
		/* the proc returns the fact it sent a set port info */
Packit 13e616
		if (lid_mgr_set_physp_pi(p_mgr, p_port, p_port->p_physp,
Packit 13e616
					 cl_hton16(min_lid_ho)))
Packit 13e616
			ret = -1;
Packit 13e616
	}			/* all ports */
Packit 13e616
Packit 13e616
	/* store the guid to lid table in persistent db */
Packit 13e616
	osm_db_store(p_mgr->p_g2l, p_mgr->p_subn->opt.fsync_high_avail_files);
Packit 13e616
Packit 13e616
	CL_PLOCK_RELEASE(p_mgr->p_lock);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
	return ret;
Packit 13e616
}