Blame opensm/osm_vl15intf.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2010 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_vl15_t.
Packit 13e616
 * This object represents the VL15 Interface object.
Packit 13e616
 * This object is part of the opensm family of objects.
Packit 13e616
 */
Packit 13e616
Packit 13e616
#if HAVE_CONFIG_H
Packit 13e616
#  include <config.h>
Packit 13e616
#endif				/* HAVE_CONFIG_H */
Packit 13e616
Packit 13e616
#include <string.h>
Packit 13e616
#include <iba/ib_types.h>
Packit 13e616
#include <complib/cl_thread.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_VL15INTF_C
Packit 13e616
#include <vendor/osm_vendor_api.h>
Packit 13e616
#include <opensm/osm_vl15intf.h>
Packit 13e616
#include <opensm/osm_madw.h>
Packit 13e616
#include <opensm/osm_log.h>
Packit 13e616
#include <opensm/osm_helper.h>
Packit 13e616
Packit 13e616
static void vl15_send_mad(osm_vl15_t * p_vl, osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	ib_api_status_t status;
Packit 13e616
	boolean_t resp_expected = p_madw->resp_expected;
Packit 13e616
	ib_smp_t * p_smp;
Packit 13e616
	ib_net16_t attr_id;
Packit 13e616
	uint8_t method;
Packit 13e616
Packit 13e616
	p_smp = osm_madw_get_smp_ptr(p_madw);
Packit 13e616
	method = p_smp->method;
Packit 13e616
	attr_id = p_smp->attr_id;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Non-response-expected mads are not throttled on the wire
Packit 13e616
	   since we can have no confirmation that they arrived
Packit 13e616
	   at their destination.
Packit 13e616
	 */
Packit 13e616
	if (resp_expected)
Packit 13e616
		/*
Packit 13e616
		   Note that other threads may not see the response MAD
Packit 13e616
		   arrive before send() even returns.
Packit 13e616
		   In that case, the wire count would temporarily go negative.
Packit 13e616
		   To avoid this confusion, preincrement the counts on the
Packit 13e616
		   assumption that send() will succeed.
Packit 13e616
		 */
Packit 13e616
		cl_atomic_inc(&p_vl->p_stats->qp0_mads_outstanding_on_wire);
Packit 13e616
	else
Packit 13e616
		cl_atomic_inc(&p_vl->p_stats->qp0_unicasts_sent);
Packit 13e616
Packit 13e616
	cl_atomic_inc(&p_vl->p_stats->qp0_mads_sent);
Packit 13e616
Packit 13e616
	status = osm_vendor_send(osm_madw_get_bind_handle(p_madw),
Packit 13e616
				 p_madw, p_madw->resp_expected);
Packit 13e616
Packit 13e616
	if (status == IB_SUCCESS) {
Packit 13e616
		OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"%u QP0 MADs on wire, %u outstanding, "
Packit 13e616
			"%u unicasts sent, %u total sent\n",
Packit 13e616
			p_vl->p_stats->qp0_mads_outstanding_on_wire,
Packit 13e616
			p_vl->p_stats->qp0_mads_outstanding,
Packit 13e616
			p_vl->p_stats->qp0_unicasts_sent,
Packit 13e616
			p_vl->p_stats->qp0_mads_sent);
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E03: "
Packit 13e616
		"MAD send failed (%s)\n", ib_get_err_str(status));
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   The MAD was never successfully sent, so
Packit 13e616
	   fix up the pre-incremented count values.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	/* Decrement qp0_mads_sent that were incremented in the code above.
Packit 13e616
	   qp0_mads_outstanding will be decremented by send error callback
Packit 13e616
	   (called by osm_vendor_send() */
Packit 13e616
	cl_atomic_dec(&p_vl->p_stats->qp0_mads_sent);
Packit 13e616
	if (!resp_expected) {
Packit 13e616
		cl_atomic_dec(&p_vl->p_stats->qp0_unicasts_sent);
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* need to cause heavy-sweep if resp_expected MAD sending failed */
Packit 13e616
	OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E04: "
Packit 13e616
		"%s method failed for attribute 0x%X (%s)\n",
Packit 13e616
		method == IB_MAD_METHOD_SET ? "SET" : "GET",
Packit 13e616
		cl_ntoh16(attr_id), ib_get_sm_attr_str(attr_id));
Packit 13e616
Packit 13e616
	p_vl->p_subn->subnet_initialization_error = TRUE;
Packit 13e616
Packit 13e616
}
Packit 13e616
Packit 13e616
static void vl15_poller(IN void *p_ptr)
Packit 13e616
{
Packit 13e616
	ib_api_status_t status;
Packit 13e616
	osm_madw_t *p_madw;
Packit 13e616
	osm_vl15_t *p_vl = p_ptr;
Packit 13e616
	cl_qlist_t *p_fifo;
Packit 13e616
	int32_t max_smps = p_vl->max_wire_smps;
Packit 13e616
	int32_t max_smps2 = p_vl->max_wire_smps2;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_vl->p_log);
Packit 13e616
Packit 13e616
	if (p_vl->thread_state == OSM_THREAD_STATE_NONE)
Packit 13e616
		p_vl->thread_state = OSM_THREAD_STATE_RUN;
Packit 13e616
Packit 13e616
	while (p_vl->thread_state == OSM_THREAD_STATE_RUN) {
Packit 13e616
		/*
Packit 13e616
		   Start servicing the FIFOs by pulling off MAD wrappers
Packit 13e616
		   and passing them to the transport interface.
Packit 13e616
		   There are lots of corner cases here so tread carefully.
Packit 13e616
Packit 13e616
		   The unicast FIFO has priority, since somebody is waiting
Packit 13e616
		   for a timely response.
Packit 13e616
		 */
Packit 13e616
		cl_spinlock_acquire(&p_vl->lock);
Packit 13e616
Packit 13e616
		if (cl_qlist_count(&p_vl->ufifo) != 0)
Packit 13e616
			p_fifo = &p_vl->ufifo;
Packit 13e616
		else
Packit 13e616
			p_fifo = &p_vl->rfifo;
Packit 13e616
Packit 13e616
		p_madw = (osm_madw_t *) cl_qlist_remove_head(p_fifo);
Packit 13e616
Packit 13e616
		cl_spinlock_release(&p_vl->lock);
Packit 13e616
Packit 13e616
		if (p_madw != (osm_madw_t *) cl_qlist_end(p_fifo)) {
Packit 13e616
			OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Servicing p_madw = %p\n", p_madw);
Packit 13e616
			if (OSM_LOG_IS_ACTIVE_V2(p_vl->p_log, OSM_LOG_FRAMES))
Packit 13e616
				osm_dump_dr_smp_v2(p_vl->p_log,
Packit 13e616
						   osm_madw_get_smp_ptr(p_madw),
Packit 13e616
						   FILE_ID, OSM_LOG_FRAMES);
Packit 13e616
Packit 13e616
			vl15_send_mad(p_vl, p_madw);
Packit 13e616
		} else
Packit 13e616
			/*
Packit 13e616
			   The VL15 FIFO is empty, so we have nothing left to do.
Packit 13e616
			 */
Packit 13e616
			status = cl_event_wait_on(&p_vl->signal,
Packit 13e616
						  EVENT_NO_TIMEOUT, TRUE);
Packit 13e616
Packit 13e616
		while (p_vl->p_stats->qp0_mads_outstanding_on_wire >= max_smps &&
Packit 13e616
		       p_vl->thread_state == OSM_THREAD_STATE_RUN) {
Packit 13e616
			status = cl_event_wait_on(&p_vl->signal,
Packit 13e616
						  p_vl->max_smps_timeout,
Packit 13e616
						  TRUE);
Packit 13e616
			if (status == CL_TIMEOUT) {
Packit 13e616
				if (max_smps < max_smps2)
Packit 13e616
					max_smps++;
Packit 13e616
				break;
Packit 13e616
			} else if (status != CL_SUCCESS) {
Packit 13e616
				OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E02: "
Packit 13e616
					"Event wait failed (%s)\n",
Packit 13e616
					CL_STATUS_MSG(status));
Packit 13e616
				break;
Packit 13e616
			}
Packit 13e616
			max_smps = p_vl->max_wire_smps;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   since we abort immediately when the state != OSM_THREAD_STATE_RUN
Packit 13e616
	   we might have some mads on the queues. After the thread exits
Packit 13e616
	   the vl15 destroy routine should put these mads back...
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_vl->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_vl15_construct(IN osm_vl15_t * p_vl)
Packit 13e616
{
Packit 13e616
	memset(p_vl, 0, sizeof(*p_vl));
Packit 13e616
	p_vl->state = OSM_VL15_STATE_INIT;
Packit 13e616
	p_vl->thread_state = OSM_THREAD_STATE_NONE;
Packit 13e616
	cl_event_construct(&p_vl->signal);
Packit 13e616
	cl_spinlock_construct(&p_vl->lock);
Packit 13e616
	cl_qlist_init(&p_vl->rfifo);
Packit 13e616
	cl_qlist_init(&p_vl->ufifo);
Packit 13e616
	cl_thread_construct(&p_vl->poller);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_vl15_destroy(IN osm_vl15_t * p_vl, IN struct osm_mad_pool *p_pool)
Packit 13e616
{
Packit 13e616
	osm_madw_t *p_madw;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_vl->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Signal our threads that we're leaving.
Packit 13e616
	 */
Packit 13e616
	p_vl->thread_state = OSM_THREAD_STATE_EXIT;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Don't trigger unless event has been initialized.
Packit 13e616
	   Destroy the thread before we tear down the other objects.
Packit 13e616
	 */
Packit 13e616
	if (p_vl->state != OSM_VL15_STATE_INIT)
Packit 13e616
		cl_event_signal(&p_vl->signal);
Packit 13e616
Packit 13e616
	cl_thread_destroy(&p_vl->poller);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Return the outstanding messages to the pool
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	cl_spinlock_acquire(&p_vl->lock);
Packit 13e616
Packit 13e616
	while (!cl_is_qlist_empty(&p_vl->rfifo)) {
Packit 13e616
		p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
Packit 13e616
		osm_mad_pool_put(p_pool, p_madw);
Packit 13e616
	}
Packit 13e616
	while (!cl_is_qlist_empty(&p_vl->ufifo)) {
Packit 13e616
		p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
Packit 13e616
		osm_mad_pool_put(p_pool, p_madw);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	cl_spinlock_release(&p_vl->lock);
Packit 13e616
Packit 13e616
	cl_event_destroy(&p_vl->signal);
Packit 13e616
	p_vl->state = OSM_VL15_STATE_INIT;
Packit 13e616
	cl_spinlock_destroy(&p_vl->lock);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_vl->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
ib_api_status_t osm_vl15_init(IN osm_vl15_t * p_vl, IN osm_vendor_t * p_vend,
Packit 13e616
			      IN osm_log_t * p_log, IN osm_stats_t * p_stats,
Packit 13e616
			      IN osm_subn_t * p_subn,
Packit 13e616
			      IN int32_t max_wire_smps,
Packit 13e616
			      IN int32_t max_wire_smps2,
Packit 13e616
			      IN uint32_t max_smps_timeout)
Packit 13e616
{
Packit 13e616
	ib_api_status_t status = IB_SUCCESS;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_log);
Packit 13e616
Packit 13e616
	p_vl->p_vend = p_vend;
Packit 13e616
	p_vl->p_log = p_log;
Packit 13e616
	p_vl->p_stats = p_stats;
Packit 13e616
	p_vl->p_subn = p_subn;
Packit 13e616
	p_vl->max_wire_smps = max_wire_smps;
Packit 13e616
	p_vl->max_wire_smps2 = max_wire_smps2;
Packit 13e616
	p_vl->max_smps_timeout = max_wire_smps < max_wire_smps2 ?
Packit 13e616
				 max_smps_timeout : EVENT_NO_TIMEOUT;
Packit 13e616
Packit 13e616
	status = cl_event_init(&p_vl->signal, FALSE);
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	p_vl->state = OSM_VL15_STATE_READY;
Packit 13e616
Packit 13e616
	status = cl_spinlock_init(&p_vl->lock);
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Initialize the thread after all other dependent objects
Packit 13e616
	   have been initialized.
Packit 13e616
	 */
Packit 13e616
	status = cl_thread_init(&p_vl->poller, vl15_poller, p_vl,
Packit 13e616
				"opensm poller");
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(p_log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_vl15_poll(IN osm_vl15_t * p_vl)
Packit 13e616
{
Packit 13e616
	OSM_LOG_ENTER(p_vl->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   If we have room for more VL15 MADs on the wire,
Packit 13e616
	   then signal the poller thread.
Packit 13e616
Packit 13e616
	   This is not an airtight check, since the poller thread
Packit 13e616
	   could be just about to send another MAD as we signal
Packit 13e616
	   the event here.  To cover this rare case, the poller
Packit 13e616
	   thread checks for a spurious wake-up.
Packit 13e616
	 */
Packit 13e616
	if (p_vl->p_stats->qp0_mads_outstanding_on_wire <
Packit 13e616
	    (int32_t) p_vl->max_wire_smps) {
Packit 13e616
		OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Signalling poller thread\n");
Packit 13e616
		cl_event_signal(&p_vl->signal);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_vl->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_vl15_post(IN osm_vl15_t * p_vl, IN osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	OSM_LOG_ENTER(p_vl->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
Packit 13e616
Packit 13e616
	OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, "Posting p_madw = %p\n", p_madw);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Determine in which fifo to place the pending madw.
Packit 13e616
	 */
Packit 13e616
	cl_spinlock_acquire(&p_vl->lock);
Packit 13e616
	if (p_madw->resp_expected == TRUE) {
Packit 13e616
		cl_qlist_insert_tail(&p_vl->rfifo, &p_madw->list_item);
Packit 13e616
		osm_stats_inc_qp0_outstanding(p_vl->p_stats);
Packit 13e616
	} else
Packit 13e616
		cl_qlist_insert_tail(&p_vl->ufifo, &p_madw->list_item);
Packit 13e616
	cl_spinlock_release(&p_vl->lock);
Packit 13e616
Packit 13e616
	OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"%u QP0 MADs on wire, %u QP0 MADs outstanding\n",
Packit 13e616
		p_vl->p_stats->qp0_mads_outstanding_on_wire,
Packit 13e616
		p_vl->p_stats->qp0_mads_outstanding);
Packit 13e616
Packit 13e616
	osm_vl15_poll(p_vl);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_vl->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_vl15_shutdown(IN osm_vl15_t * p_vl, IN osm_mad_pool_t * p_mad_pool)
Packit 13e616
{
Packit 13e616
	osm_madw_t *p_madw;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_vl->p_log);
Packit 13e616
Packit 13e616
	/* we only should get here after the VL15 interface was initialized */
Packit 13e616
	CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
Packit 13e616
Packit 13e616
	/* grab a lock on the object */
Packit 13e616
	cl_spinlock_acquire(&p_vl->lock);
Packit 13e616
Packit 13e616
	/* go over all outstanding MADs and retire their transactions */
Packit 13e616
Packit 13e616
	/* first we handle the list of response MADs */
Packit 13e616
	p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
Packit 13e616
	while (p_madw != (osm_madw_t *) cl_qlist_end(&p_vl->ufifo)) {
Packit 13e616
		OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Releasing Response p_madw = %p\n", p_madw);
Packit 13e616
Packit 13e616
		osm_mad_pool_put(p_mad_pool, p_madw);
Packit 13e616
Packit 13e616
		p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Request MADs we send out */
Packit 13e616
	p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
Packit 13e616
	while (p_madw != (osm_madw_t *) cl_qlist_end(&p_vl->rfifo)) {
Packit 13e616
		OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Releasing Request p_madw = %p\n", p_madw);
Packit 13e616
Packit 13e616
		osm_mad_pool_put(p_mad_pool, p_madw);
Packit 13e616
		osm_stats_dec_qp0_outstanding(p_vl->p_stats);
Packit 13e616
Packit 13e616
		p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* free the lock */
Packit 13e616
	cl_spinlock_release(&p_vl->lock);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_vl->p_log);
Packit 13e616
}