static osmv_disp_route_t
__osmv_dispatch_route(IN osm_bind_handle_t h_bind,
		      IN const ib_mad_t * p_mad, OUT osmv_txn_ctx_t ** pp_txn)
{
	ib_api_status_t ret;
	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
	boolean_t is_resp = ib_mad_is_response(p_mad);
	boolean_t is_txn;
	uint64_t key = cl_ntoh64(p_mad->trans_id);

	CL_ASSERT(NULL != pp_txn);

	ret = osmv_txn_lookup(h_bind, key, pp_txn);
	is_txn = (IB_SUCCESS == ret);

	if (FALSE == is_txn && TRUE == is_resp) {
		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
			"Received a response to a non-started/aged-out transaction (tid=0x%" PRIx64 "). "
			"Dropping the MAD.\n", key);
		return OSMV_ROUTE_DROP;
	}

	if (TRUE == osmv_mad_is_rmpp(p_mad)) {
		/* An RMPP transaction. The filtering is more delicate there */
		return OSMV_ROUTE_RMPP;
	}

	if (TRUE == is_txn && FALSE == is_resp) {
		/* Does this MAD try to start a transaction with duplicate tid? */
		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
			"Duplicate TID 0x%" PRIx64 " received (not a response). "
			"Dropping the MAD.\n", key);

		return OSMV_ROUTE_DROP;
	}

	return OSMV_ROUTE_SIMPLE;
}
Пример #2
0
static uint64_t
__osmv_txn_timeout_cb(IN uint64_t key,
		      IN uint32_t num_regs, IN void *cb_context)
{
	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) cb_context;
	uint64_t ret = 0;
	osmv_txn_ctx_t *p_txn;
	osmv_rmpp_send_ctx_t *p_send_ctx;
	osm_madw_t *p_madw = NULL;
	ib_mad_t *p_mad;
	osm_mad_addr_t *p_mad_addr;
	boolean_t invoke_err_cb = FALSE;

	OSM_LOG_ENTER(p_bo->p_vendor->p_log);

	/* Don't try to acquire a lock on the Bind Object -
	 * it's taken by the mechanism that drives the timeout based events!
	 * (Recall the special constructor that the Event Wheel is applied with)
	 */
	if (p_bo->is_closing) {
		goto txn_done;
	}

	ret = osmv_txn_lookup(p_bo, key, &p_txn);
	if (IB_NOT_FOUND == ret) {
		/* Prevent a race - the transaction is already destroyed */
		goto txn_done;
	}

	p_madw = p_txn->p_madw;

	switch (osmv_txn_get_rmpp_state(p_txn)) {

	case OSMV_TXN_RMPP_NONE:
		if (num_regs <= OSMV_MAX_RETRANSMIT) {
			/* We still did not exceed the limit of retransmissions.
			 * Set the next timeout's value.
			 */
			osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
				"__osmv_txn_timeout_cb: "
				"The transaction request (tid=0x%llX) timed out %d times. "
				"Retrying the send.\n",
				osmv_txn_get_tid(p_txn), num_regs);

			/* resend this mad */
			ret = osmv_simple_send_madw((osm_bind_handle_t *) p_bo,
						    p_madw, p_txn, TRUE);
			if (ret != IB_SUCCESS) {
				osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
					"__osmv_txn_timeout_cb: "
					"Fail to send retry for transaction request (tid=0x%llX).\n",
					osmv_txn_get_tid(p_txn));

				osmv_txn_done((osm_bind_handle_t) p_bo, key,
					      TRUE /*in timeout callback */ );

				/* This is a requester. Always apply the callback */
				invoke_err_cb = TRUE;
			} else {
				uint64_t next_timeout_ms;
				next_timeout_ms =
				    p_bo->p_vendor->resp_timeout * (num_regs +
								    1) *
				    (num_regs + 1);
				/* when do we need to timeout again */
				ret =
				    cl_get_time_stamp() +
				    (uint64_t) (1000 * next_timeout_ms);

				osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
					"__osmv_txn_timeout_cb: "
					"Retry request timout in : %lu [msec].\n",
					next_timeout_ms);
			}
		} else {
			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
				"__osmv_txn_timeout_cb: ERR 6702: "
				"The transaction request (tid=0x%llX) timed out (after %d retries). "
				"Invoking the error callback.\n",
				osmv_txn_get_tid(p_txn), num_regs);

			osmv_txn_done((osm_bind_handle_t) p_bo, key,
				      TRUE /*in timeout callback */ );

			/* This is a requester. Always apply the callback */
			invoke_err_cb = TRUE;
		}
		break;

	case OSMV_TXN_RMPP_SENDER:
		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
			"RMPP sender (tid=0x%llX) did not receive ACK "
			"on every segment in the current send window.\n",
			osmv_txn_get_tid(p_txn));

		p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn);
		if (num_regs <= OSMV_MAX_RETRANSMIT) {
			/* We still did not exceed the limit of retransmissions.
			 * Set the next timeout's value.
			 */
			ret =
			    cl_get_time_stamp() +
			    1000 * p_bo->p_vendor->resp_timeout;
		} else {
			p_send_ctx->status = IB_TIMEOUT;

			p_mad = osm_madw_get_mad_ptr(p_madw);
			p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw);

			/* Send an ABORT to the other side */
			osmv_rmpp_send_nak((osm_bind_handle_t) p_bo, p_mad,
					   p_mad_addr, IB_RMPP_TYPE_ABORT,
					   IB_RMPP_STATUS_T2L);
		}

		/* Wake the RMPP sender thread up */
		cl_event_signal(&p_send_ctx->event);
		break;

	case OSMV_TXN_RMPP_RECEIVER:
		osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG,
			"Transaction timeout on an RMPP receiver (tid=0x%llX). "
			"Dropping the transaction.\n", osmv_txn_get_tid(p_txn));

		osmv_txn_done((osm_bind_handle_t) p_bo, key,
			      TRUE /*in timeout callback */ );

		if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)) {
			/* This is a requester, still waiting for the reply. Apply the callback */
			invoke_err_cb = TRUE;
		}

		break;

	default:
		CL_ASSERT(FALSE);
	}

	if (TRUE == invoke_err_cb) {
		CL_ASSERT(NULL != p_madw);
		/* update the status in the p_madw */
		p_madw->status = IB_TIMEOUT;
		p_bo->send_err_cb(p_bo->cb_context, p_madw);
		/* no re-registration */
		ret = 0;
	}

txn_done:
	OSM_LOG_EXIT(p_bo->p_vendor->p_log);
	return ret;
}
Пример #3
0
static ib_api_status_t
__osmv_get_send_txn(IN osm_bind_handle_t h_bind,
		    IN osm_madw_t * const p_madw,
		    IN boolean_t is_rmpp,
		    IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn)
{
	ib_api_status_t ret;
	uint64_t tid, key;
	osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind;
	ib_mad_t *p_mad = osm_madw_get_mad_ptr(p_madw);

	OSM_LOG_ENTER(p_bo->p_vendor->p_log);
	CL_ASSERT(NULL != pp_txn);

	key = tid = cl_ntoh64(p_mad->trans_id);
	if (TRUE == resp_expected) {
		/* Create a unique identifier at the requester side */
		key = osmv_txn_uniq_key(tid);
	}

	/* We must run under a transaction framework */
	ret = osmv_txn_lookup(h_bind, key, pp_txn);
	if (IB_NOT_FOUND == ret) {
		/* Generally, we start a new transaction */
		ret = osmv_txn_init(h_bind, tid, key, pp_txn);
		if (IB_SUCCESS != ret) {
			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
				"__osmv_get_send_txn: ERR 7313: "
				"The transaction id=0x%" PRIx64 " failed to init.\n",
				tid);
			goto get_send_txn_done;
		}
	} else {
		CL_ASSERT(NULL != *pp_txn);
		/* The transaction context exists.
		 * This is legal only if I am going to return an
		 * (RMPP?) reply to an RMPP request sent by the other part
		 * (double-sided RMPP transfer)
		 */
		if (FALSE == is_rmpp
		    || FALSE == osmv_txn_is_rmpp_init_by_peer(*pp_txn)) {
			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
				"__osmv_get_send_txn: ERR 7314: "
				"The transaction id=0x%" PRIx64 " is not unique. Send failed.\n",
				tid);

			ret = IB_INVALID_SETTING;
			goto get_send_txn_done;
		}

		if (TRUE == resp_expected) {
			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
				"__osmv_get_send_txn: ERR 7315: "
				"The transaction id=0x%" PRIx64 " can't expect a response. Send failed.\n",
				tid);

			ret = IB_INVALID_PARAMETER;
			goto get_send_txn_done;
		}
	}

	if (TRUE == is_rmpp) {
		ret = osmv_txn_init_rmpp_sender(h_bind, *pp_txn, p_madw);
		if (IB_SUCCESS != ret) {
			osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR,
				"__osmv_get_send_txn: ERR 7316: "
				"The transaction id=0x%" PRIx64 " failed to init the rmpp mad. Send failed.\n",
				tid);
			osmv_txn_done(h_bind, tid, FALSE);
			goto get_send_txn_done;
		}
	}

	/* Save a reference to the MAD in the txn context
	 * We'll need to match it in two cases:
	 *  (1) When the response is returned, if I am the requester
	 *  (2) In RMPP retransmissions
	 */
	osmv_txn_set_madw(*pp_txn, p_madw);

get_send_txn_done:
	OSM_LOG_EXIT(p_bo->p_vendor->p_log);

	return ret;
}