Esempio n. 1
0
void __osm_vendor_timer_callback(IN void *context)
{
	uint64_t current_time;
	mad_bind_info_t *p_mad_bind_info;
	umadt_obj_t *p_umadt_obj;
	uint32_t timeout;

	cl_list_item_t *p_list_item, *p_next_list_item;

	CL_ASSERT(context);

	p_mad_bind_info = (mad_bind_info_t *) context;
	p_umadt_obj = p_mad_bind_info->p_umadt_obj;
	timeout = p_umadt_obj->timeout * 1000;

	current_time = cl_get_time_stamp();

	cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock);

	p_list_item = cl_qlist_head(&p_mad_bind_info->trans_ctxt_list);
	while (p_list_item != cl_qlist_end(&p_mad_bind_info->trans_ctxt_list)) {

		p_next_list_item = cl_qlist_next(p_list_item);

		/*  DEFAULT_PKT_TIMEOUT is in milli seconds */
		if (current_time - ((trans_context_t *) p_list_item)->sent_time
		    > timeout) {
			/*  Add this transaction to the timeout_list */
			cl_qlist_remove_item(&p_mad_bind_info->trans_ctxt_list,
					     p_list_item);
			cl_qlist_insert_tail(&p_mad_bind_info->timeout_list,
					     p_list_item);
		}

		p_list_item = p_next_list_item;
	}

	cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock);

	p_list_item = cl_qlist_head(&p_mad_bind_info->timeout_list);
	while (p_list_item != cl_qlist_end(&p_mad_bind_info->timeout_list)) {
		osm_log(p_mad_bind_info->p_umadt_obj->p_log, OSM_LOG_DEBUG,
			"__osm_vendor_timer_callback: "
			"Timing out transaction context [0x%p].\n",
			((trans_context_t *) p_list_item)->context);

		(*(p_mad_bind_info->mad_recv_callback)) (NULL,
							 p_mad_bind_info->
							 client_context,
							 ((trans_context_t *)
							  p_list_item)->
							 context);

		p_next_list_item = cl_qlist_next(p_list_item);
		cl_qlist_remove_item(&p_mad_bind_info->timeout_list,
				     p_list_item);
		free(p_list_item);
		p_list_item = p_next_list_item;
	}

	cl_timer_start(&p_mad_bind_info->timeout_timer,
		       DEFAULT_TIMER_INTERVAL_MSEC);

}
static uint32_t mpr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
					    IN const ib_multipath_rec_t * p_mpr,
					    IN const osm_port_t * p_req_port,
					    IN const osm_alias_guid_t * p_src_alias_guid,
					    IN const osm_alias_guid_t * p_dest_alias_guid,
					    IN const uint32_t rem_paths,
					    IN const ib_net64_t comp_mask,
					    IN cl_qlist_t * p_list)
{
	osm_sa_item_t *p_pr_item;
	uint16_t src_lid_min_ho;
	uint16_t src_lid_max_ho;
	uint16_t dest_lid_min_ho;
	uint16_t dest_lid_max_ho;
	uint16_t src_lid_ho;
	uint16_t dest_lid_ho;
	uint32_t path_num = 0;
	uint8_t preference;
	unsigned src_offset, dest_offset;

	OSM_LOG_ENTER(sa->p_log);

	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
		"Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n",
		cl_ntoh64(p_src_alias_guid->alias_guid),
		cl_ntoh64(p_dest_alias_guid->alias_guid));

	/* Check that the req_port, src_port and dest_port all share a
	   pkey. The check is done on the default physical port of the ports. */
	if (osm_port_share_pkey(sa->p_log, p_req_port,
				p_src_alias_guid->p_base_port,
				sa->p_subn->opt.allow_both_pkeys) == FALSE
	    || osm_port_share_pkey(sa->p_log, p_req_port,
				   p_dest_alias_guid->p_base_port,
				   sa->p_subn->opt.allow_both_pkeys) == FALSE
	    || osm_port_share_pkey(sa->p_log, p_src_alias_guid->p_base_port,
				   p_dest_alias_guid->p_base_port,
				   sa->p_subn->opt.allow_both_pkeys) == FALSE)
		/* One of the pairs doesn't share a pkey so the path is disqualified. */
		goto Exit;

	/*
	   We shouldn't be here if the paths are disqualified in some way...
	   Thus, we assume every possible connection is valid.

	   We desire to return high-quality paths first.
	   In OpenSM, higher quality mean least overlap with other paths.
	   This is acheived in practice by returning paths with
	   different LID value on each end, which means these
	   paths are more redundant that paths with the same LID repeated
	   on one side.  For example, in OpenSM the paths between two
	   endpoints with LMC = 1 might be as follows:

	   Port A, LID 1 <-> Port B, LID 3
	   Port A, LID 1 <-> Port B, LID 4
	   Port A, LID 2 <-> Port B, LID 3
	   Port A, LID 2 <-> Port B, LID 4

	   The OpenSM unicast routing algorithms attempt to disperse each path
	   to as varied a physical path as is reasonable.  1<->3 and 1<->4 have
	   more physical overlap (hence less redundancy) than 1<->3 and 2<->4.

	   OpenSM ranks paths in three preference groups:

	   Preference Value           Description
	   ----------------           -------------------------------------------
	   0                  Redundant in both directions with other
	   pref value = 0 paths

	   1                  Redundant in one direction with other
	   pref value = 0 and pref value = 1 paths

	   2                  Not redundant in either direction with
	   other paths

	   3-FF                       Unused

	   SA clients don't need to know these details, only that the lower
	   preference paths are preferred, as stated in the spec.  The paths
	   may not actually be physically redundant depending on the topology
	   of the subnet, but the point of LMC > 0 is to offer redundancy,
	   so I assume the subnet is physically appropriate for the specified
	   LMC value.  A more advanced implementation could inspect for physical
	   redundancy, but I'm not going to bother with that now.
	 */

	osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
				  &src_lid_min_ho, &src_lid_max_ho);
	osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
				  &dest_lid_min_ho, &dest_lid_max_ho);

	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID [%u-%u], Dest LID [%u-%u]\n",
		src_lid_min_ho, src_lid_max_ho,
		dest_lid_min_ho, dest_lid_max_ho);

	src_lid_ho = src_lid_min_ho;
	dest_lid_ho = dest_lid_min_ho;

	/*
	   Preferred paths come first in OpenSM
	 */
	preference = 0;

	while (path_num < rem_paths) {
		/*
		   These paths are "fully redundant"
		 */
		p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
						      p_src_alias_guid,
						      p_dest_alias_guid,
						      src_lid_ho, dest_lid_ho,
						      comp_mask, preference);

		if (p_pr_item) {
			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
			++path_num;
		}

		if (++src_lid_ho > src_lid_max_ho)
			break;

		if (++dest_lid_ho > dest_lid_max_ho)
			break;
	}

	/*
	   Check if we've accumulated all the paths that the user cares to see
	 */
	if (path_num == rem_paths)
		goto Exit;

	/*
	   Don't bother reporting preference 1 paths for now.
	   It's more trouble than it's worth and can only occur
	   if ports have different LMC values, which isn't supported
	   by OpenSM right now anyway.
	 */
	preference = 2;
	src_lid_ho = src_lid_min_ho;
	dest_lid_ho = dest_lid_min_ho;
	src_offset = 0;
	dest_offset = 0;

	/*
	   Iterate over the remaining paths
	 */
	while (path_num < rem_paths) {
		dest_offset++;
		dest_lid_ho++;

		if (dest_lid_ho > dest_lid_max_ho) {
			src_offset++;
			src_lid_ho++;

			if (src_lid_ho > src_lid_max_ho)
				break;	/* done */

			dest_offset = 0;
			dest_lid_ho = dest_lid_min_ho;
		}

		/*
		   These paths are "fully non-redundant" with paths already
		   identified above and consequently not of much value.

		   Don't return paths we already identified above, as indicated
		   by the offset values being equal.
		 */
		if (src_offset == dest_offset)
			continue;	/* already reported */

		p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
						      p_src_alias_guid,
						      p_dest_alias_guid,
						      src_lid_ho, dest_lid_ho,
						      comp_mask, preference);

		if (p_pr_item) {
			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
			++path_num;
		}
	}

Exit:
	OSM_LOG_EXIT(sa->p_log);
	return path_num;
}
Esempio n. 3
0
static void
__osm_sa_inform_info_rec_by_comp_mask(IN osm_sa_t * sa,
				      IN const osm_infr_t * const p_infr,
				      osm_iir_search_ctxt_t * const p_ctxt)
{
	const ib_inform_info_record_t *p_rcvd_rec = NULL;
	ib_net64_t comp_mask;
	ib_net64_t portguid;
	osm_port_t *p_subscriber_port;
	osm_physp_t *p_subscriber_physp;
	const osm_physp_t *p_req_physp;
	osm_iir_item_t *p_rec_item;

	OSM_LOG_ENTER(sa->p_log);

	p_rcvd_rec = p_ctxt->p_rcvd_rec;
	comp_mask = p_ctxt->comp_mask;
	p_req_physp = p_ctxt->p_req_physp;

	if (comp_mask & IB_IIR_COMPMASK_SUBSCRIBERGID &&
	    memcmp(&p_infr->inform_record.subscriber_gid,
	    	   &p_ctxt->subscriber_gid,
		   sizeof(p_infr->inform_record.subscriber_gid)))
		goto Exit;

	if (comp_mask & IB_IIR_COMPMASK_ENUM &&
	    p_infr->inform_record.subscriber_enum != p_ctxt->subscriber_enum)
		goto Exit;

	/* Implement any other needed search cases */

	/* Ensure pkey is shared before returning any records */
	portguid = p_infr->inform_record.subscriber_gid.unicast.interface_id;
	p_subscriber_port = osm_get_port_by_guid(sa->p_subn, portguid);
	if (p_subscriber_port == NULL) {
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 430D: "
			"Invalid subscriber port guid: 0x%016" PRIx64 "\n",
			cl_ntoh64(portguid));
		goto Exit;
	}

	/* get the subscriber InformInfo physical port */
	p_subscriber_physp = p_subscriber_port->p_physp;
	/* make sure that the requester and subscriber port can access each other
	   according to the current partitioning. */
	if (!osm_physp_share_pkey
	    (sa->p_log, p_req_physp, p_subscriber_physp)) {
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
			"requester and subscriber ports don't share pkey\n");
		goto Exit;
	}

	p_rec_item = malloc(sizeof(*p_rec_item));
	if (p_rec_item == NULL) {
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 430E: "
			"rec_item alloc failed\n");
		goto Exit;
	}

	memcpy((void *)&p_rec_item->rec, (void *)&p_infr->inform_record,
	       sizeof(ib_inform_info_record_t));
	cl_qlist_insert_tail(p_ctxt->p_list, &p_rec_item->list_item);

Exit:
	OSM_LOG_EXIT(sa->p_log);
}
Esempio n. 4
0
cl_status_t cl_qcpool_grow(IN cl_qcpool_t * const p_pool, IN size_t obj_count)
{
	cl_status_t status = CL_SUCCESS;
	uint8_t *p_objects;
	cl_pool_item_t *p_pool_item;
	uint32_t i;
	size_t obj_size;

	CL_ASSERT(p_pool);
	CL_ASSERT(p_pool->state == CL_INITIALIZED);
	CL_ASSERT(obj_count);

	/* Validate that growth is possible. */
	if (p_pool->num_objects == p_pool->max_objects)
		return (CL_INSUFFICIENT_MEMORY);

	/* Cap the growth to the desired maximum. */
	if (obj_count > (p_pool->max_objects - p_pool->num_objects))
		obj_count = p_pool->max_objects - p_pool->num_objects;

	/* Calculate the size of an object. */
	obj_size = 0;
	for (i = 0; i < p_pool->num_components; i++)
		obj_size += p_pool->component_sizes[i];

	/* Allocate the buffer for the new objects. */
	p_objects = (uint8_t *)
	    malloc(sizeof(cl_list_item_t) + (obj_size * obj_count));

	/* Make sure the allocation succeeded. */
	if (!p_objects)
		return (CL_INSUFFICIENT_MEMORY);
	else
		memset(p_objects, 0,
		       sizeof(cl_list_item_t) + (obj_size * obj_count));

	/* Insert the allocation in our list. */
	cl_qlist_insert_tail(&p_pool->alloc_list, (cl_list_item_t *) p_objects);
	p_objects += sizeof(cl_list_item_t);

	/* initialize the new elements and add them to the free list */
	while (obj_count--) {
		/* Setup the array of components for the current object. */
		p_pool->p_components[0] = p_objects;
		for (i = 1; i < p_pool->num_components; i++) {
			/* Calculate the pointer to the next component. */
			p_pool->p_components[i] =
			    (uint8_t *) p_pool->p_components[i - 1] +
			    p_pool->component_sizes[i - 1];
		}

		/*
		 * call the user's initializer
		 * this can fail!
		 */
		if (p_pool->pfn_init) {
			p_pool_item = NULL;
			status = p_pool->pfn_init(p_pool->p_components,
						  p_pool->num_components,
						  (void *)p_pool->context,
						  &p_pool_item);
			if (status != CL_SUCCESS) {
				/*
				 * User initialization failed
				 * we may have only grown the pool by some partial amount
				 * Invoke the destructor for the object that failed
				 * initialization.
				 */
				if (p_pool->pfn_dtor)
					p_pool->pfn_dtor(p_pool_item,
							 (void *)p_pool->
							 context);

				/* Return the user's status. */
				return (status);
			}
			CL_ASSERT(p_pool_item);
		} else {
			/*
			 * If no initializer is provided, assume that the pool item
			 * is stored at the beginning of the first component.
			 */
			p_pool_item =
			    (cl_pool_item_t *) p_pool->p_components[0];
		}

#ifdef _DEBUG_
		/*
		 * Set the pool item's pool pointer to this pool so that we can
		 * check that items get returned to the correct pool.
		 */
		p_pool_item->p_pool = p_pool;
#endif

		/* Insert the new item in the free list, traping for failure. */
		cl_qlist_insert_head(&p_pool->free_list,
				     &p_pool_item->list_item);

		p_pool->num_objects++;

		/* move the pointer to the next item */
		p_objects += obj_size;
	}

	return (status);
}
static void mpr_rcv_get_apm_paths(IN osm_sa_t * sa,
				  IN const ib_multipath_rec_t * p_mpr,
				  IN const osm_port_t * p_req_port,
				  IN osm_alias_guid_t ** _pp_alias_guids,
				  IN const ib_net64_t comp_mask,
				  IN cl_qlist_t * p_list)
{
	osm_alias_guid_t *pp_alias_guids[4];
	osm_sa_item_t *matrix[2][2];
	int base_offs, src_lid_ho, dest_lid_ho;
	int sumA, sumB, minA, minB;

	OSM_LOG_ENTER(sa->p_log);

	/*
	 * We want to:
	 *    1. use different lid offsets (from base) for the resultant paths
	 *    to increase the probability of redundant paths or in case
	 *    of Clos - to ensure it (different offset => different spine!)
	 *    2. keep consistent paths no matter of direction and order of ports
	 *    3. distibute the lid offsets to balance the load
	 * So, we sort the ports (within the srcs, and within the dests),
	 * hash the lids of S0, D0 (after the sort), and call mpr_rcv_get_apm_port_pair_paths
	 * with base_lid for S0, D0 and base_lid + 1 for S1, D1. This way we will get
	 * always the same offsets - order independent, and make sure different spines are used.
	 * Note that the diagonals on a Clos have the same number of hops, so it doesn't
	 * really matter which diagonal we use.
	 */
	if (_pp_alias_guids[0]->p_base_port->guid <
	    _pp_alias_guids[1]->p_base_port->guid) {
		pp_alias_guids[0] = _pp_alias_guids[0];
		pp_alias_guids[1] = _pp_alias_guids[1];
	} else {
		pp_alias_guids[0] = _pp_alias_guids[1];
		pp_alias_guids[1] = _pp_alias_guids[0];
	}
	if (_pp_alias_guids[2]->p_base_port->guid <
	    _pp_alias_guids[3]->p_base_port->guid) {
		pp_alias_guids[2] = _pp_alias_guids[2];
		pp_alias_guids[3] = _pp_alias_guids[3];
	} else {
		pp_alias_guids[2] = _pp_alias_guids[3];
		pp_alias_guids[3] = _pp_alias_guids[2];
	}

	src_lid_ho = osm_port_get_base_lid(pp_alias_guids[0]->p_base_port);
	dest_lid_ho = osm_port_get_base_lid(pp_alias_guids[2]->p_base_port);

	base_offs = src_lid_ho < dest_lid_ho ?
	    hash_lids(src_lid_ho, dest_lid_ho, sa->p_subn->opt.lmc) :
	    hash_lids(dest_lid_ho, src_lid_ho, sa->p_subn->opt.lmc);

	matrix[0][0] =
	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[0],
					    pp_alias_guids[2], base_offs,
					    comp_mask, p_list);
	matrix[0][1] =
	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[0],
					    pp_alias_guids[3], base_offs,
					    comp_mask, p_list);
	matrix[1][0] =
	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[1],
					    pp_alias_guids[2], base_offs + 1,
					    comp_mask, p_list);
	matrix[1][1] =
	    mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[1],
					    pp_alias_guids[3], base_offs + 1,
					    comp_mask, p_list);

	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "APM matrix:\n"
		"\t{0,0} 0x%X->0x%X (%d)\t| {0,1} 0x%X->0x%X (%d)\n"
		"\t{1,0} 0x%X->0x%X (%d)\t| {1,1} 0x%X->0x%X (%d)\n",
		matrix[0][0]->resp.mpr_rec.path_rec.slid,
		matrix[0][0]->resp.mpr_rec.path_rec.dlid,
		matrix[0][0]->resp.mpr_rec.hops,
		matrix[0][1]->resp.mpr_rec.path_rec.slid,
		matrix[0][1]->resp.mpr_rec.path_rec.dlid,
		matrix[0][1]->resp.mpr_rec.hops,
		matrix[1][0]->resp.mpr_rec.path_rec.slid,
		matrix[1][0]->resp.mpr_rec.path_rec.dlid,
		matrix[1][0]->resp.mpr_rec.hops,
		matrix[1][1]->resp.mpr_rec.path_rec.slid,
		matrix[1][1]->resp.mpr_rec.path_rec.dlid,
		matrix[1][1]->resp.mpr_rec.hops);

	/* check diagonal A {(0,0), (1,1)} */
	sumA = matrix[0][0]->resp.mpr_rec.hops + matrix[1][1]->resp.mpr_rec.hops;
	minA = min(matrix[0][0]->resp.mpr_rec.hops, matrix[1][1]->resp.mpr_rec.hops);

	/* check diagonal B {(0,1), (1,0)} */
	sumB = matrix[0][1]->resp.mpr_rec.hops + matrix[1][0]->resp.mpr_rec.hops;
	minB = min(matrix[0][1]->resp.mpr_rec.hops, matrix[1][0]->resp.mpr_rec.hops);

	/* and the winner is... */
	if (minA <= minB || (minA == minB && sumA < sumB)) {
		/* Diag A */
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
			"Diag {0,0} & {1,1} is the best:\n"
			"\t{0,0} 0x%X->0x%X (%d)\t & {1,1} 0x%X->0x%X (%d)\n",
			matrix[0][0]->resp.mpr_rec.path_rec.slid,
			matrix[0][0]->resp.mpr_rec.path_rec.dlid,
			matrix[0][0]->resp.mpr_rec.hops,
			matrix[1][1]->resp.mpr_rec.path_rec.slid,
			matrix[1][1]->resp.mpr_rec.path_rec.dlid,
			matrix[1][1]->resp.mpr_rec.hops);
		cl_qlist_insert_tail(p_list, &matrix[0][0]->list_item);
		cl_qlist_insert_tail(p_list, &matrix[1][1]->list_item);
		free(matrix[0][1]);
		free(matrix[1][0]);
	} else {
		/* Diag B */
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
			"Diag {0,1} & {1,0} is the best:\n"
			"\t{0,1} 0x%X->0x%X (%d)\t & {1,0} 0x%X->0x%X (%d)\n",
			matrix[0][1]->resp.mpr_rec.path_rec.slid,
			matrix[0][1]->resp.mpr_rec.path_rec.dlid,
			matrix[0][1]->resp.mpr_rec.hops,
			matrix[1][0]->resp.mpr_rec.path_rec.slid,
			matrix[1][0]->resp.mpr_rec.path_rec.dlid,
			matrix[1][0]->resp.mpr_rec.hops);
		cl_qlist_insert_tail(p_list, &matrix[0][1]->list_item);
		cl_qlist_insert_tail(p_list, &matrix[1][0]->list_item);
		free(matrix[0][0]);
		free(matrix[1][1]);
	}

	OSM_LOG_EXIT(sa->p_log);
}
Esempio n. 6
0
ib_api_status_t
osm_transaction_mgr_insert_madw(IN osm_bind_handle_t * const p_bind,
				IN osm_madw_t * p_madw)
{
#ifdef OSM_VENDOR_INTF_MTL
	osm_vendor_t *const p_vend = ((osm_mtl_bind_info_t *) p_bind)->p_vend;
#else
	osm_vendor_t *const p_vend = ((osm_ts_bind_info_t *) p_bind)->p_vend;
#endif
	osm_transaction_mgr_t *trans_mgr_p;
	osm_madw_req_t *osm_madw_req_p;
	uint64_t timeout;
	uint64_t waking_time;
	cl_status_t cl_status;
	uint64_t key;
	const ib_mad_t *mad_p = p_madw->p_mad;

	OSM_LOG_ENTER(p_vend->p_log);

	CL_ASSERT(mad_p);

	trans_mgr_p = (osm_transaction_mgr_t *) p_vend->p_transaction_mgr;

	timeout = (uint64_t) (p_vend->timeout) * 1000;	/* change the miliseconds value of timeout to microseconds. */
	waking_time = timeout + cl_get_time_stamp();

	osm_madw_req_p = (osm_madw_req_t *) malloc(sizeof(osm_madw_req_t));

	osm_madw_req_p->p_madw = p_madw;
	osm_madw_req_p->waking_time = waking_time;
	osm_madw_req_p->retry_cnt = OSM_DEFAULT_RETRY_COUNT;
	osm_madw_req_p->p_bind = p_bind;

	osm_log(p_vend->p_log, OSM_LOG_DEBUG,
		"osm_transaction_mgr_insert_madw: "
		"Inserting MADW:%p with waking_time: <0x%" PRIx64 ">  TID:<0x%"
		PRIx64 ">.\n", p_madw, waking_time, p_madw->p_mad->trans_id);

	/* Get the lock on the manager */
	cl_spinlock_acquire(&(trans_mgr_p->transaction_mgr_lock));
	/* If the list is empty - need to start the timer with timer of timeout (in miliseconds) */
	if (cl_is_qlist_empty(trans_mgr_p->madw_reqs_list_p)) {
		/*  stop the timer if it is running */
		cl_timer_stop(&trans_mgr_p->madw_list_timer);

		/*  start the timer to the timeout (in miliseconds) */
		cl_status = cl_timer_start(&trans_mgr_p->madw_list_timer,
					   p_vend->timeout);
		if (cl_status != CL_SUCCESS) {
			osm_log(p_vend->p_log, OSM_LOG_ERROR,
				"osm_transaction_mgr_insert_madw : ERROR 1000: "
				"Failed to start timer\n");
		}
	}

	/*  insert the object to the qlist and the qmap */
	cl_qlist_insert_tail(trans_mgr_p->madw_reqs_list_p,
			     &(osm_madw_req_p->list_item));
	/*  get the key */
	key = (uint64_t) mad_p->trans_id;
	cl_qmap_insert(trans_mgr_p->madw_by_tid_map_p, key,
		       &(osm_madw_req_p->map_item));
	cl_spinlock_release(&trans_mgr_p->transaction_mgr_lock);

	OSM_LOG_EXIT(p_vend->p_log);

	return (IB_SUCCESS);
}
Esempio n. 7
0
/* this is the callback function of the timer */
void __osm_transaction_mgr_callback(IN void *context)
{
	osm_transaction_mgr_t *trans_mgr_p;
	osm_vendor_t *p_vend = (osm_vendor_t *) context;
	cl_list_item_t *p_list_item;
	cl_list_item_t *p_list_next_item;
	osm_madw_req_t *osm_madw_req_p;
	uint64_t current_time;	/*  [usec] */
	uint32_t new_timeout;	/*  [msec] */
	cl_status_t cl_status;
	ib_mad_t *p_mad;
#ifdef OSM_VENDOR_INTF_MTL
	osm_mtl_bind_info_t *p_bind;
#else
	osm_ts_bind_info_t *p_bind;
#endif
	cl_list_t tmp_madw_p_list;	/*  this list will include all the madw_p that should be removed. */
	cl_list_t retry_madw_p_list;	/*  this list will include all the madw_p that were retried and need to be removed. */
	osm_madw_t *madw_p;

	OSM_LOG_ENTER(p_vend->p_log);

	trans_mgr_p = (osm_transaction_mgr_t *) p_vend->p_transaction_mgr;

	/*  initialize the tmp_madw_p_list */
	cl_list_construct(&tmp_madw_p_list);
	cl_status = cl_list_init(&tmp_madw_p_list, 50);
	if (cl_status != CL_SUCCESS) {
		osm_log(p_vend->p_log, OSM_LOG_ERROR,
			"__osm_transaction_mgr_callback : ERROR 1000: "
			"Failed to create tmp_madw_p_list\n");
	}

	cl_list_construct(&retry_madw_p_list);
	cl_status = cl_list_init(&retry_madw_p_list, 50);
	if (cl_status != CL_SUCCESS) {
		osm_log(p_vend->p_log, OSM_LOG_ERROR,
			"__osm_transaction_mgr_callback : ERROR 1000: "
			"Failed to create retry_madw_p_list\n");
	}

	current_time = cl_get_time_stamp();
	cl_spinlock_acquire(&(trans_mgr_p->transaction_mgr_lock));
	p_list_item = cl_qlist_head(trans_mgr_p->madw_reqs_list_p);
	if (p_list_item == cl_qlist_end(trans_mgr_p->madw_reqs_list_p)) {
		/*  the list is empty - nothing to do */
		cl_spinlock_release(&trans_mgr_p->transaction_mgr_lock);
		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
			"__osm_transaction_mgr_callback : Nothing to do\n");
		goto Exit;
	}

	/*  non empty list: */

	/*  get the osm_madw_req_p  */
	osm_madw_req_p = PARENT_STRUCT(p_list_item, osm_madw_req_t, list_item);

	while (osm_madw_req_p->waking_time <= current_time) {
		/*  this object was supposed to have gotten a response */
		/*  we need to decide if we need to retry or done with it. */
		if (osm_madw_req_p->retry_cnt > 0) {
			/*  add to the list of the retrys : */
			cl_list_insert_tail(&retry_madw_p_list, osm_madw_req_p);

			/*  update wakeup time and retry count */
			osm_madw_req_p->waking_time =
			    p_vend->timeout * 1000 + cl_get_time_stamp();
			osm_madw_req_p->retry_cnt--;

			/*  make sure we will get some timer call if not earlier */
			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
				"__osm_transaction_mgr_callback : Timer restart:%u\n",
				p_vend->timeout);

			cl_status =
			    cl_timer_start(&trans_mgr_p->madw_list_timer,
					   p_vend->timeout);

			/*  go to the next object and check if it also needs to be removed - didn't receive response */
			/*  we need to do it before we move current item to the end of the list */
			p_list_next_item = cl_qlist_next(p_list_item);

			/*  remove from the head */
			cl_qlist_remove_item(trans_mgr_p->madw_reqs_list_p,
					     &(osm_madw_req_p->list_item));

			/*  insert the object to the qlist and the qmap */
			cl_qlist_insert_tail(trans_mgr_p->madw_reqs_list_p,
					     &(osm_madw_req_p->list_item));

		} else {
			/*  go to the next object and check if it also needs to be removed - didn't receive response */
			p_list_next_item = cl_qlist_next(p_list_item);

			/*  remove from the head */
			cl_qlist_remove_item(trans_mgr_p->madw_reqs_list_p,
					     &(osm_madw_req_p->list_item));

			/*  add it to the tmp_madw_p_list to be removed */
			cl_list_insert_tail(&tmp_madw_p_list,
					    osm_madw_req_p->p_madw);
			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
				"__osm_transaction_mgr_callback : Found failed transaction madw: %p\n",
				osm_madw_req_p->p_madw);
		}

		/*  Advance */
		p_list_item = p_list_next_item;
		if (p_list_item == cl_qlist_end(trans_mgr_p->madw_reqs_list_p)) {
			/*  the list is empty - nothing to do */
			break;
		}

		/*  get the osm_madw_req_p  */
		osm_madw_req_p =
		    PARENT_STRUCT(p_list_item, osm_madw_req_t, list_item);
	}

	/*  look at the current p_list_item. If it is not the end item - then we need to  */
	/*  re-start the timer */
	if (p_list_item != cl_qlist_end(trans_mgr_p->madw_reqs_list_p)) {
		/*  get the osm_madw_req_p  */
		osm_madw_req_p =
		    PARENT_STRUCT(p_list_item, osm_madw_req_t, list_item);

		/*  we have the object that still didn't get response - re-start the timer */
		/*  start the timer to the timeout (in miliseconds) */
		new_timeout =
		    (osm_madw_req_p->waking_time - cl_get_time_stamp()) / 1000 +
		    1;
		cl_status =
		    cl_timer_start(&trans_mgr_p->madw_list_timer, new_timeout);
		osm_log(p_vend->p_log, OSM_LOG_DEBUG,
			"__osm_transaction_mgr_callback : Timer restart:%u\n",
			new_timeout);

		if (cl_status != CL_SUCCESS) {
			osm_log(p_vend->p_log, OSM_LOG_ERROR,
				"__osm_transaction_mgr_callback : ERROR 1000: "
				"Failed to start timer\n");
		}
	}
	/* if not empty - retry on retry list: */
	if (!cl_is_list_empty(&retry_madw_p_list)) {

		/*  remove all elements that were retried: */
		osm_madw_req_p =
		    (osm_madw_req_t
		     *) (cl_list_remove_head(&retry_madw_p_list));
		while (osm_madw_req_p != NULL) {

			/*  resend: */
			osm_log(p_vend->p_log, OSM_LOG_DEBUG,
				"__osm_transaction_mgr_callback : "
				"Retry %d of madw %p\n",
				OSM_DEFAULT_RETRY_COUNT -
				osm_madw_req_p->retry_cnt,
				osm_madw_req_p->p_madw);

			/*  actually send it */
#ifdef OSM_VENDOR_INTF_MTL
			osm_mtl_send_mad((osm_mtl_bind_info_t *)
					 osm_madw_req_p->p_bind,
					 osm_madw_req_p->p_madw);
#else
			ib_api_status_t
			    osm_ts_send_mad(osm_ts_bind_info_t * p_bind,
					    osm_madw_t * const p_madw);
			osm_ts_send_mad((osm_ts_bind_info_t *) osm_madw_req_p->
					p_bind, osm_madw_req_p->p_madw);
#endif
			/*  next one */
			osm_madw_req_p =
			    (osm_madw_req_t
			     *) (cl_list_remove_head(&retry_madw_p_list));
		}
	}

	/*  if the tmp_madw_p_list has elements - need to call the send_err_callback */
	madw_p = (osm_madw_t *) (cl_list_remove_head(&tmp_madw_p_list));
	while (madw_p != NULL) {
		/*  need to remove it from pool */

		/* obtain the madw_p stored as the wrid in the send call */
		p_mad = osm_madw_get_mad_ptr(madw_p);
		p_bind = madw_p->h_bind;
		/*
		   Return any wrappers to the pool that may have been
		   pre-emptively allocated to handle a receive.
		 */
		if (madw_p->vend_wrap.p_resp_madw) {
#ifdef OSM_VENDOR_INTF_MTL
			osm_mad_pool_put(p_bind->p_osm_pool,
					 madw_p->vend_wrap.p_resp_madw);
#else
			osm_mad_pool_put(p_bind->p_osm_pool,
					 madw_p->vend_wrap.p_resp_madw);
#endif
			madw_p->vend_wrap.p_resp_madw = NULL;
		}

		/* invoke the CB */
		(*(osm_vend_mad_send_err_callback_t)
		 (p_bind->send_err_callback)) (p_bind->client_context, madw_p);
		madw_p = (osm_madw_t *) (cl_list_remove_head(&tmp_madw_p_list));
	}

Exit:
	OSM_LOG_EXIT(p_vend->p_log);

}
Esempio n. 8
0
/*        rank is a SWITCH for BFS purpose */
static int updn_subn_rank(IN updn_t * p_updn)
{
	osm_switch_t *p_sw;
	osm_physp_t *p_physp, *p_remote_physp;
	cl_qlist_t list;
	cl_map_item_t *item;
	struct updn_node *u, *remote_u;
	uint8_t num_ports, port_num;
	osm_log_t *p_log = &p_updn->p_osm->log;
	unsigned max_rank = 0;

	OSM_LOG_ENTER(p_log);
	cl_qlist_init(&list);

	/* add all roots to the list */
	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
	     item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
	     item = cl_qmap_next(item)) {
		p_sw = (osm_switch_t *)item;
		u = p_sw->priv;
		if (!u->rank)
			cl_qlist_insert_tail(&list, &u->list);
	}

	/* BFS the list till it's empty */
	while (!cl_is_qlist_empty(&list)) {
		u = (struct updn_node *)cl_qlist_remove_head(&list);
		/* Go over all remote nodes and rank them (if not already visited) */
		p_sw = u->sw;
		num_ports = p_sw->num_ports;
		OSM_LOG(p_log, OSM_LOG_DEBUG,
			"Handling switch GUID 0x%" PRIx64 "\n",
			cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
		for (port_num = 1; port_num < num_ports; port_num++) {
			ib_net64_t port_guid;

			/* Current port fetched in order to get remote side */
			p_physp =
			    osm_node_get_physp_ptr(p_sw->p_node, port_num);

			if (!p_physp)
				continue;

			p_remote_physp = p_physp->p_remote_physp;

			/*
			   make sure that all the following occur on p_remote_physp:
			   1. The port isn't NULL
			   2. It is a switch
			 */
			if (p_remote_physp && p_remote_physp->p_node->sw) {
				remote_u = p_remote_physp->p_node->sw->priv;
				port_guid = p_remote_physp->port_guid;

				if (remote_u->rank > u->rank + 1) {
					remote_u->rank = u->rank + 1;
					max_rank = remote_u->rank;
					cl_qlist_insert_tail(&list,
							     &remote_u->list);
					OSM_LOG(p_log, OSM_LOG_DEBUG,
						"Rank of port GUID 0x%" PRIx64
						" = %u\n", cl_ntoh64(port_guid),
						remote_u->rank);
				}
			}
		}
	}

	/* Print Summary of ranking */
	OSM_LOG(p_log, OSM_LOG_VERBOSE,
		"Subnet ranking completed. Max Node Rank = %d\n", max_rank);
	OSM_LOG_EXIT(p_log);
	return 0;
}
Esempio n. 9
0
/**********************************************************************
 * This function does the bfs of min hop table calculation by guid index
 * as a starting point.
 **********************************************************************/
static int updn_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn,
			    IN osm_switch_t * p_sw)
{
	uint8_t pn, pn_rem;
	cl_qlist_t list;
	uint16_t lid;
	struct updn_node *u;
	updn_switch_dir_t next_dir, current_dir;

	OSM_LOG_ENTER(p_log);

	lid = osm_node_get_base_lid(p_sw->p_node, 0);
	lid = cl_ntoh16(lid);
	osm_switch_set_hops(p_sw, lid, 0, 0);

	OSM_LOG(p_log, OSM_LOG_DEBUG,
		"Starting from switch - port GUID 0x%" PRIx64 " lid %u\n",
		cl_ntoh64(p_sw->p_node->node_info.port_guid), lid);

	u = p_sw->priv;
	u->dir = UP;

	/* Update list with the new element */
	cl_qlist_init(&list);
	cl_qlist_insert_tail(&list, &u->list);

	/* BFS the list till no next element */
	while (!cl_is_qlist_empty(&list)) {
		u = (struct updn_node *)cl_qlist_remove_head(&list);
		u->visited = 0;	/* cleanup */
		current_dir = u->dir;
		/* Go over all ports of the switch and find unvisited remote nodes */
		for (pn = 1; pn < u->sw->num_ports; pn++) {
			osm_node_t *p_remote_node;
			struct updn_node *rem_u;
			uint8_t current_min_hop, remote_min_hop,
			    set_hop_return_value;
			osm_switch_t *p_remote_sw;

			p_remote_node =
			    osm_node_get_remote_node(u->sw->p_node, pn,
						     &pn_rem);
			/* If no remote node OR remote node is not a SWITCH
			   continue to next pn */
			if (!p_remote_node || !p_remote_node->sw)
				continue;
			/* Fetch remote guid only after validation of remote node */
			p_remote_sw = p_remote_node->sw;
			rem_u = p_remote_sw->priv;
			/* Decide which direction to mark it (UP/DOWN) */
			next_dir = updn_get_dir(u->rank, rem_u->rank,
						u->id, rem_u->id);

			/* Check if this is a legal step : the only illegal step is going
			   from DOWN to UP */
			if ((current_dir == DOWN) && (next_dir == UP)) {
				OSM_LOG(p_log, OSM_LOG_DEBUG,
					"Avoiding move from 0x%016" PRIx64
					" to 0x%016" PRIx64 "\n",
					cl_ntoh64(osm_node_get_node_guid(u->sw->p_node)),
					cl_ntoh64(osm_node_get_node_guid(p_remote_node)));
				/* Illegal step */
				continue;
			}
			/* Set MinHop value for the current lid */
			current_min_hop = osm_switch_get_least_hops(u->sw, lid);
			/* Check hop count if better insert into list && update
			   the remote node Min Hop Table */
			remote_min_hop =
			    osm_switch_get_hop_count(p_remote_sw, lid, pn_rem);
			if (current_min_hop + 1 < remote_min_hop) {
				set_hop_return_value =
				    osm_switch_set_hops(p_remote_sw, lid,
							pn_rem,
							current_min_hop + 1);
				if (set_hop_return_value) {
					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AA01: "
						"Invalid value returned from set min hop is: %d\n",
						set_hop_return_value);
				}
				/* Check if remote port has already been visited */
				if (!rem_u->visited) {
					/* Insert updn_switch item into the list */
					rem_u->dir = next_dir;
					rem_u->visited = 1;
					cl_qlist_insert_tail(&list,
							     &rem_u->list);
				}
			}
		}
	}

	OSM_LOG_EXIT(p_log);
	return 0;
}
Esempio n. 10
0
int osm_qos_setup(osm_opensm_t * p_osm)
{
	struct qos_config ca_config, sw0_config, swe_config, rtr_config;
	struct qos_config *cfg;
	cl_qmap_t *p_tbl;
	cl_map_item_t *p_next;
	osm_port_t *p_port;
	osm_node_t *p_node;
	int ret = 0;
	int vlarb_only;
	qos_mad_list_t *p_list, *p_list_next;
	qos_mad_item_t *p_port_mad;
	cl_qlist_t qos_mad_list;

	if (!p_osm->subn.opt.qos)
		return 0;

	OSM_LOG_ENTER(&p_osm->log);

	qos_build_config(&ca_config, &p_osm->subn.opt.qos_ca_options,
			 &p_osm->subn.opt.qos_options);
	qos_build_config(&sw0_config, &p_osm->subn.opt.qos_sw0_options,
			 &p_osm->subn.opt.qos_options);
	qos_build_config(&swe_config, &p_osm->subn.opt.qos_swe_options,
			 &p_osm->subn.opt.qos_options);
	qos_build_config(&rtr_config, &p_osm->subn.opt.qos_rtr_options,
			 &p_osm->subn.opt.qos_options);

	cl_qlist_init(&qos_mad_list);

	cl_plock_excl_acquire(&p_osm->lock);

	/* read QoS policy config file */
	osm_qos_parse_policy_file(&p_osm->subn);
	p_tbl = &p_osm->subn.port_guid_tbl;
	p_next = cl_qmap_head(p_tbl);
	while (p_next != cl_qmap_end(p_tbl)) {
		vlarb_only = 0;
		p_port = (osm_port_t *) p_next;
		p_next = cl_qmap_next(p_next);

		p_list = (qos_mad_list_t *) malloc(sizeof(*p_list));
		if (!p_list)
			return -1;

		memset(p_list, 0, sizeof(*p_list));

		cl_qlist_init(&p_list->port_mad_list);

		p_node = p_port->p_node;
		if (p_node->sw) {
			if (qos_extports_setup(&p_osm->sm, p_node, &swe_config,
					       &p_list->port_mad_list))
				ret = -1;

			/* skip base port 0 */
			if (!ib_switch_info_is_enhanced_port0
			    (&p_node->sw->switch_info))
				goto Continue;

			if (ib_switch_info_get_opt_sl2vlmapping(&p_node->sw->switch_info) &&
			    p_osm->sm.p_subn->opt.use_optimized_slvl &&
			    !memcmp(&swe_config.sl2vl, &sw0_config.sl2vl,
				    sizeof(swe_config.sl2vl)))
				vlarb_only = 1;

			cfg = &sw0_config;
		} else if (osm_node_get_type(p_node) == IB_NODE_TYPE_ROUTER)
			cfg = &rtr_config;
		else
			cfg = &ca_config;

		if (qos_endport_setup(&p_osm->sm, p_port->p_physp, cfg,
				      vlarb_only, &p_list->port_mad_list))

			ret = -1;
Continue:
		/* if MAD list is not empty, add it to the global MAD list */
		if (cl_qlist_count(&p_list->port_mad_list)) {
			cl_qlist_insert_tail(&qos_mad_list, &p_list->list_item);
		} else {
			free(p_list);
		}
	}
	while (cl_qlist_count(&qos_mad_list)) {
		p_list_next = (qos_mad_list_t *) cl_qlist_head(&qos_mad_list);
		while (p_list_next !=
			(qos_mad_list_t *) cl_qlist_end(&qos_mad_list)) {
			p_list = p_list_next;
			p_list_next = (qos_mad_list_t *)
				      cl_qlist_next(&p_list->list_item);
			/* next MAD to send*/
			p_port_mad = (qos_mad_item_t *)
				     cl_qlist_remove_head(&p_list->port_mad_list);
			osm_send_req_mad(&p_osm->sm, p_port_mad->p_madw);
			osm_qos_mad_delete(&p_port_mad);
			/* remove the QoS MAD from global MAD list */
			if (cl_qlist_count(&p_list->port_mad_list) == 0) {
				cl_qlist_remove_item(&qos_mad_list, &p_list->list_item);
				free(p_list);
			}
		}
	}

	cl_plock_release(&p_osm->lock);
	OSM_LOG_EXIT(&p_osm->log);

	return ret;
}