예제 #1
0
/* ARGSUSED */
static void
ibmf_i_do_send_compl(ibmf_handle_t ibmf_handle, ibmf_msg_impl_t *msgimplp,
    ibmf_send_wqe_t *send_wqep)
{
	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_do_send_compl_start,
	    IBMF_TNF_TRACE, "", "ibmf_i_do_send_compl(): ibmf_hdl = 0x%p "
	    "msgp = %p, send_wqep = 0x%p, msg_flags = 0x%x\n",
	    tnf_opaque, ibmf_hdl, ibmf_handle, tnf_opaque, msgimplp, msgimplp,
	    tnf_opaque, send_wqep, send_wqep,
	    tnf_opaque, msg_flags, msgimplp->im_flags);

	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));

	/*
	 * For RMPP transactions, we only care about the final packet of the
	 * transaction.  For others, the code does not need to wait for the send
	 * completion (although bad things can happen if it never occurs).
	 * The final packets of a transaction are sent when the state is either
	 * ABORT or RECEVR_TERMINATE.
	 * Don't mark the transaction as send_done if there are still more
	 * packets to be sent, including doing the second part of a double-sided
	 * transaction.
	 */
	if ((msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) ||
	    (msgimplp->im_flags & IBMF_MSG_FLAGS_SEND_RMPP)) {

		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
		    ibmf_i_do_send_compl, IBMF_TNF_TRACE, "",
		    "ibmf_i_do_send_compl(): %s msgp = %p, rmpp_state = 0x%x\n",
		    tnf_string, msg, "Received send callback for RMPP trans",
		    tnf_opaque, msg, msgimplp,
		    tnf_opaque, rmpp_state, msgimplp->im_rmpp_ctx.rmpp_state);

		/*
		 * For ABORT state, we should not return control to
		 * the client from the send completion handler.
		 * Control should be returned in the error timeout handler.
		 *
		 * The exception is when the IBMF_TRANS_STATE_FLAG_RECV_DONE
		 * flag has already been set. This flag is set when
		 * ibmf_i_terminate_transaction is called from one of the
		 * three timeout handlers. In this case return control from
		 * here.
		 */
		if (msgimplp->im_rmpp_ctx.rmpp_state == IBMF_RMPP_STATE_ABORT) {
			msgimplp->im_trans_state_flags |=
			    IBMF_TRANS_STATE_FLAG_SEND_DONE;
			if (msgimplp->im_trans_state_flags &
			    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
				msgimplp->im_trans_state_flags |=
				    IBMF_TRANS_STATE_FLAG_DONE;
			}
		}

		if ((msgimplp->im_rmpp_ctx.rmpp_state ==
		    IBMF_RMPP_STATE_RECEVR_TERMINATE) ||
		    (msgimplp->im_rmpp_ctx.rmpp_state ==
		    IBMF_RMPP_STATE_DONE)) {
			msgimplp->im_trans_state_flags |=
			    IBMF_TRANS_STATE_FLAG_SEND_DONE;
			if (msgimplp->im_trans_state_flags  &
			    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
				msgimplp->im_trans_state_flags |=
				    IBMF_TRANS_STATE_FLAG_DONE;
			}
		}

		/*
		 * If the transaction is a send-only RMPP, then
		 * set the SEND_DONE flag on every send completion
		 * as long as there are no outstanding ones.
		 * This is needed so that the transaction can return
		 * in the receive path, where ibmf_i_terminate_transaction
		 * is called from ibmf_i_rmpp_sender_active_flow,
		 * after checking if the SEND_DONE flag is set.
		 * When a new MAD is sent as part of the RMPP transaction,
		 * the SEND_DONE flag will get reset.
		 * The RECV_DONE indicates that the last ACK was received.
		 */
		if ((msgimplp->im_flags & IBMF_MSG_FLAGS_SEQUENCED) == 0) {
			if (msgimplp->im_pending_send_compls == 0) {
				msgimplp->im_trans_state_flags |=
				    IBMF_TRANS_STATE_FLAG_SEND_DONE;
				if (msgimplp->im_trans_state_flags  &
				    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
					msgimplp->im_trans_state_flags |=
					    IBMF_TRANS_STATE_FLAG_DONE;
				}
			}
		}

		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
		    ibmf_i_do_send_compl_end, IBMF_TNF_TRACE, "",
		    "ibmf_i_do_send_compl() exit\n");
		return;
	}

	/*
	 * Only non-RMPP send completion gets here.
	 * If the send is a single-packet send that does not use RMPP, and if
	 * the transaction is not a sequenced transaction, call the transaction
	 * callback handler after flagging the transaction as done.  If the
	 * message is sequenced, start a timer to bound the wait for the first
	 * data packet of the response.
	 */
	if (msgimplp->im_flags & IBMF_MSG_FLAGS_SEQUENCED) {

		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
		    ibmf_i_do_send_compl, IBMF_TNF_TRACE, "",
		    "ibmf_i_do_send_compl(): %s msgp = %p\n", tnf_string, msg,
		    "Sequenced transaction, setting response timer",
		    tnf_opaque, msg, msgimplp);

		/*
		 * Check if the send completion already occured,
		 * which could imply that this is a send completion
		 * for some previous transaction that has come in very late.
		 * In this case exit here.
		 */
		if (msgimplp->im_trans_state_flags  &
		    IBMF_TRANS_STATE_FLAG_SEND_DONE) {
			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
			    ibmf_i_do_send_compl_end, IBMF_TNF_TRACE, "",
			    "ibmf_i_do_send_compl() exit, "
			    "Duplicate SEND completion\n");
			return;
		}

		/* mark as send_compl happened */
		msgimplp->im_trans_state_flags |=
		    IBMF_TRANS_STATE_FLAG_SEND_DONE;

		if (msgimplp->im_trans_state_flags  &
		    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
			msgimplp->im_trans_state_flags |=
			    IBMF_TRANS_STATE_FLAG_DONE;
			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
			    ibmf_i_do_send_compl_end, IBMF_TNF_TRACE, "",
			    "ibmf_i_do_send_compl() exit, RECV_DONE\n");
			return;
		}

		/*
		 * check if response was received before send
		 * completion
		 */
		if (((msgimplp->im_trans_state_flags &
		    IBMF_TRANS_STATE_FLAG_DONE) == 0) &&
		    ((msgimplp->im_trans_state_flags &
		    IBMF_TRANS_STATE_FLAG_RECV_ACTIVE) == 0)) {
			/* set timer for first packet of response */
			ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp,
			    IBMF_RESP_TIMER);
		}
	} else {
		msgimplp->im_msg_status = IBMF_SUCCESS;
		msgimplp->im_trans_state_flags |=
		    IBMF_TRANS_STATE_FLAG_SEND_DONE;
		msgimplp->im_trans_state_flags |= IBMF_TRANS_STATE_FLAG_DONE;
	}

	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_do_send_compl_end,
	    IBMF_TNF_TRACE, "", "ibmf_i_do_send_compl() exit\n");
}
예제 #2
0
/*
 * ibmf_i_notify_sequence()
 *	Checks for the need to create a termination context before
 *	notifying the client.
 */
void
ibmf_i_notify_sequence(ibmf_client_t *clientp, ibmf_msg_impl_t *msgimplp,
    int msg_flags)
{
	int status;

	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
	    ibmf_i_notify_sequence_start, IBMF_TNF_TRACE, "",
	    "ibmf_i_notify_sequence() enter, clientp = %p, msgimplp = %p\n",
	    tnf_opaque, clientp, clientp, tnf_opaque, msgimplp, msgimplp);

	if (msg_flags & IBMF_MSG_FLAGS_TERMINATION) {
		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_notify_sequence,
		    IBMF_TNF_TRACE, "", "ibmf_i_notify_sequence(): %s, "
		    "msgimplp = %p\n", tnf_string, msg,
		    "IBMF_MSG_FLAGS_TERMINATION already set",
		    tnf_opaque, msgimplp, msgimplp);

		return;
	}

	if (msg_flags & IBMF_MSG_FLAGS_SET_TERMINATION) {

		/*
		 * In some cases, we need to check if the termination context
		 * needs to be set up for early termination of non-double-sided
		 * RMPP receiver transactions. In these cases we set up the
		 * termination context, and then notify the client.
		 * If the set up of the termination context fails, attempt to
		 * reverse state to the regular context, and set the response
		 * timer for the termination timeout and exit without notifying
		 * the client in this failure case. If the setting of the
		 * response timer fails, simply notify the client without
		 * going through the process of timing out in the response
		 * timer.
		 */
		status = ibmf_setup_term_ctx(clientp, msgimplp);
		if (status != IBMF_SUCCESS) {

			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
			    ibmf_i_notify_sequence, IBMF_TNF_TRACE,
			    "", "ibmf_i_notify_sequence(): %s, "
			    "msgimplp = %p\n", tnf_string, msg,
			    "ibmf_setup_term_ctx() failed,"
			    "reversing to regular termination",
			    tnf_opaque, msgimplp, msgimplp);

			mutex_enter(&msgimplp->im_mutex);

			ibmf_i_set_timer(ibmf_i_recv_timeout, msgimplp,
			    IBMF_RESP_TIMER);

			/*
			 * Set the flags cleared in
			 * ibmf_i_terminate_transaction()
			 */
			msgimplp->im_trans_state_flags &=
			    ~IBMF_TRANS_STATE_FLAG_DONE;
			msgimplp->im_trans_state_flags &=
			    ~IBMF_TRANS_STATE_FLAG_RECV_DONE;

			mutex_exit(&msgimplp->im_mutex);

			/* Re-add the message to the list */
			ibmf_i_client_add_msg(clientp, msgimplp);
		} else {
			/*
			 * The termination context has been
			 * set up. Notify the client that the
			 * regular message is done.
			 */
			ibmf_i_notify_client(msgimplp);
		}
	} else {
		ibmf_i_notify_client(msgimplp);
	}

	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
	    ibmf_i_notify_sequence_end, IBMF_TNF_TRACE, "",
	    "ibmf_i_notify_sequence() exit, msgimplp = %p\n",
	    tnf_opaque, msgimplp, msgimplp);
}