static void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind)
{
	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
	osm_log_t *p_log = p_bo->p_vendor->p_log;

	OSM_LOG_ENTER(p_log);

	/* "notifying" all that from now on no new sends can be done */
	p_bo->txn_mgr.p_event_wheel->closing = TRUE;

	osmv_txn_lock(p_bo);

	/*
	   the is_closing is set under lock we we know we only need to
	   check for it after obtaining the lock
	 */
	p_bo->is_closing = TRUE;

	/* notifying all sleeping rmpp sends to exit */
	osmv_txn_abort_rmpp_txns(h_bind);

	/* unlock the bo to allow for any residual mads to be dispatched */
	osmv_txn_unlock(p_bo);
	osm_log(p_log, OSM_LOG_DEBUG,
		"__osm_vendor_internal_unbind: destroying transport mgr.. \n");
	/* wait for the receiver thread to exit */
	osmv_transport_done(h_bind);

	/* lock to avoid any collissions while we cleanup the structs */
	osmv_txn_lock(p_bo);
	osm_log(p_log, OSM_LOG_DEBUG,
		"__osm_vendor_internal_unbind: destroying txn mgr.. \n");
	osmv_txnmgr_done(h_bind);
	osm_log(p_log, OSM_LOG_DEBUG,
		"__osm_vendor_internal_unbind: destroying bind lock.. \n");
	osmv_txn_unlock(p_bo);

	/*
	   we intentionally let the p_bo and its lock leak -
	   as we did not implement a way to track active bind handles provided to
	   the client - and the client might use them

	   cl_spinlock_destroy(&p_bo->lock);
	   free(p_bo);
	 */

	OSM_LOG_EXIT(p_log);
}
Example #2
0
ib_api_status_t
osmv_rmpp_send_madw(IN osm_bind_handle_t h_bind,
		    IN osm_madw_t * const p_madw,
		    IN osmv_txn_ctx_t * p_txn, IN boolean_t is_rmpp_ds)
{
	ib_api_status_t ret = IB_SUCCESS;
	uint32_t i, total_segs;

	osmv_rmpp_send_ctx_t *p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn);
	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;

	OSM_LOG_ENTER(p_bo->p_vendor->p_log);

	total_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx);
	CL_ASSERT(total_segs >= 1);

	/* In the double-sided transfer, wait for ACK 0 */

	for (;;) {

		if (p_send_ctx->window_first > total_segs) {

			/* Every segment is acknowledged */
			break;
		}

		/* Send the next burst. */
		for (i = p_send_ctx->window_first; i <= p_send_ctx->window_last;
		     i++) {

			/* Send a segment and setup a timeout timer */
			ret = __osmv_rmpp_send_segment(h_bind, p_txn, i);
			if (IB_SUCCESS != ret) {
				goto send_done;
			}
		}

		/* Set the Response Timeout for the ACK on the last DATA segment */
		ret = osmv_txn_set_timeout_ev(h_bind, osmv_txn_get_key(p_txn),
					      p_bo->p_vendor->resp_timeout);
		if (IB_SUCCESS != ret) {
			goto send_done;
		}

		/* Going to sleep. Let the others access the transaction DB */
		osmv_txn_unlock(p_bo);

		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
			"RMPP Sender thread (madw=%p) going to sleep ...\n",
			p_madw);

		/* Await the next event to happen */
		cl_event_wait_on(&p_send_ctx->event,
				 EVENT_NO_TIMEOUT, TRUE /* interruptible */ );

		/* Got a signal from the MAD dispatcher/timeout handler */
		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
			"RMPP Sender thread (madw=%p) waking up on a signal ...\n",
			p_madw);

		/* Let's see what changed... Make this atomic - re-acquire the lock. */
		osmv_txn_lock(p_bo);

		if (TRUE == p_bo->is_closing) {
			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
				"osmv_rmpp_send_madw: ERR 6601: "
				"The bind handle %p is being closed. "
				"Stopping the RMPP Send of MADW %p\n",
				h_bind, p_madw);

			ret = IB_TIMEOUT;
			return IB_INTERRUPTED;
		}

		/* STOP? ABORT? TIMEOUT? */
		if (IB_SUCCESS != p_send_ctx->status) {
			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
				"osmv_rmpp_send_madw: ERR 6602: "
				"An error (%s) happened during the RMPP send of %p. Bailing out.\n",
				ib_get_err_str(p_send_ctx->status), p_madw);
			ret = p_send_ctx->status;
			goto send_done;
		}
	}

	if (TRUE == is_rmpp_ds) {
		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
			"Double-sided RMPP - switching to be the receiver.\n");

		ret = osmv_txn_init_rmpp_receiver(h_bind, p_txn, FALSE
						  /*Send was initiated by me */
						  );

		if (IB_SUCCESS == ret) {
			/* Send ACK on the 0 segment */
			ret = __osmv_rmpp_send_segment(h_bind, p_txn, 0);
		}
	}

send_done:
	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
	return ret;
}
ib_api_status_t
osm_vendor_send(IN osm_bind_handle_t h_bind,
		IN osm_madw_t * const p_madw, IN boolean_t const resp_expected)
{
	ib_api_status_t ret = IB_SUCCESS;
	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
	boolean_t is_rmpp = FALSE, is_rmpp_ds = FALSE;
	osmv_txn_ctx_t *p_txn = NULL;
	ib_mad_t *p_mad;
	osm_log_t *p_log = p_bo->p_vendor->p_log;
	osm_mad_pool_t *p_mad_pool = p_bo->p_osm_pool;
	OSM_LOG_ENTER(p_log);

	if (NULL == h_bind || NULL == p_madw ||
	    NULL == (p_mad = osm_madw_get_mad_ptr(p_madw)) ||
	    NULL == osm_madw_get_mad_addr_ptr(p_madw)) {

		return IB_INVALID_PARAMETER;
	}

	is_rmpp = (p_madw->mad_size > MAD_BLOCK_SIZE
		   || osmv_mad_is_rmpp(p_mad));
	/* is this rmpp double sided? This means we expect a response that can be
	   an rmpp or not */
	is_rmpp_ds = (TRUE == is_rmpp && TRUE == resp_expected);

	/* Make our operations with the send context atomic */
	osmv_txn_lock(p_bo);

	if (TRUE == p_bo->is_closing) {

		osm_log(p_log, OSM_LOG_ERROR,
			"osm_vendor_send: ERR 7310: "
			"The handle %p is being unbound, cannot send.\n",
			h_bind);
		ret = IB_INTERRUPTED;
		/* When closing p_bo could be detroyed or is going to , thus could not refer to it */
		goto send_done;
	}

	if (TRUE == resp_expected || TRUE == is_rmpp) {

		/* We must run under a transaction framework.
		 * Get the transaction object (old or new) */
		ret = __osmv_get_send_txn(h_bind, p_madw, is_rmpp,
					  resp_expected, &p_txn);
		if (IB_SUCCESS != ret) {
			goto send_done;
		}
	}

	if (TRUE == is_rmpp) {
		/* Do the job - RMPP!
		 * The call returns as all the packets are ACK'ed/upon error
		 * The txn lock will be released each time the function sleeps
		 * and re-acquired when it wakes up
		 */
		ret = osmv_rmpp_send_madw(h_bind, p_madw, p_txn, is_rmpp_ds);
	} else {

		/* Do the job - single MAD!
		 * The call returns as soon as the MAD is put on the wire
		 */
		ret = osmv_simple_send_madw(h_bind, p_madw, p_txn, FALSE);
	}

	if (IB_SUCCESS == ret) {

		if ((TRUE == is_rmpp) && (FALSE == is_rmpp_ds)) {
			/* For double-sided sends, the txn continues to live */
			osmv_txn_done(h_bind, osmv_txn_get_key(p_txn),
				      FALSE /*not in callback */ );
		}

		if (FALSE == resp_expected) {
			osm_mad_pool_put(p_mad_pool, p_madw);
		}
	} else if (IB_INTERRUPTED != ret) {
		if (NULL != p_txn) {
			osmv_txn_done(h_bind, osmv_txn_get_key(p_txn),
				      FALSE /*not in callback */ );
		}

		osm_log(p_log, OSM_LOG_ERROR,
			"osm_vendor_send: ERR 7311: failed to send MADW %p\n",
			p_madw);

		if (TRUE == resp_expected) {
			/* Change the status on the p_madw */
			p_madw->status = ret;
			/* Only the requester expects the error callback */
			p_bo->send_err_cb(p_bo->cb_context, p_madw);
		} else {
			/* put back the mad - it is useless ... */
			osm_mad_pool_put(p_mad_pool, p_madw);
		}
	} else {		/* the transaction was aborted due to p_bo exit */

		osm_mad_pool_put(p_mad_pool, p_madw);
		goto aborted;
	}
send_done:

	osmv_txn_unlock(p_bo);
aborted:
	OSM_LOG_EXIT(p_log);
	return ret;
}
ib_api_status_t
osmv_dispatch_mad(IN osm_bind_handle_t h_bind,
		  IN const void *p_mad_buf,
		  IN const osm_mad_addr_t * p_mad_addr)
{
	ib_api_status_t ret = IB_SUCCESS;
	const ib_mad_t *p_mad = (ib_mad_t *) p_mad_buf;
	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
	osmv_txn_ctx_t *p_txn = NULL;
	osm_log_t *p_log = p_bo->p_vendor->p_log;

	OSM_LOG_ENTER(p_bo->p_vendor->p_log);

	CL_ASSERT(NULL != h_bind && NULL != p_mad && NULL != p_mad_addr);

	osmv_txn_lock(p_bo);

	if (TRUE == p_bo->is_closing) {

		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
			"The bind handle %p is being closed. "
			"The MAD will not be dispatched.\n", p_bo);

		ret = IB_INTERRUPTED;
		goto dispatch_mad_done;
	}

	/*
	   Add call for packet drop randomizer.
	   This is a testing feature. If run_randomizer flag is set to TRUE,
	   the randomizer will be called, and randomally will drop
	   a packet. This is used for simulating unstable fabric.
	 */
	if (p_bo->p_vendor->run_randomizer == TRUE) {
		/* Try the randomizer */
		if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log,
						p_bo->p_vendor->
						p_pkt_randomizer,
						p_mad) == TRUE) {
			osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
				"The MAD will not be dispatched.\n");
			goto dispatch_mad_done;
		}
	}

	switch (__osmv_dispatch_route(h_bind, p_mad, &p_txn)) {

	case OSMV_ROUTE_DROP:
		break;		/* Do nothing */

	case OSMV_ROUTE_SIMPLE:
		__osmv_dispatch_simple_mad(h_bind, p_mad, p_txn, p_mad_addr);
		break;

	case OSMV_ROUTE_RMPP:
		__osmv_dispatch_rmpp_mad(h_bind, p_mad, p_txn, p_mad_addr);
		break;

	default:
		CL_ASSERT(FALSE);
	}

dispatch_mad_done:
	osmv_txn_unlock(p_bo);

	OSM_LOG_EXIT(p_log);
	return ret;
}