Exemplo n.º 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");
}
Exemplo n.º 2
0
/*
 * ibmf_i_terminate_transaction():
 *	Do transaction termination processing.
 */
void
ibmf_i_terminate_transaction(ibmf_client_t *clientp, ibmf_msg_impl_t *msgimplp,
    uint32_t status)
{

	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4,
	    ibmf_i_terminate_transaction_start, IBMF_TNF_TRACE, "",
	    "ibmf_i_terminate_transaction(): clientp = 0x%p, msgp = 0x%p, "
	    "status = 0x%x\n", tnf_opaque, clientp, clientp,
	    tnf_opaque, msg, msgimplp, tnf_uint, status, status);

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

	msgimplp->im_msg_status = status;

	/*
	 * Cancel the transaction timer. timer is probably only active if status
	 * was not success and this is a recv operation, but unset_timer() will
	 * check.
	 */
	ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);

	/*
	 * For unsolicited messages, do not notify the client
	 * if an error was encontered in the transfer.
	 * For solicited messages, call the transaction callback
	 * provided by the client in the message context.
	 */
	if (msgimplp->im_unsolicited == B_TRUE) {

		msgimplp->im_trans_state_flags |= IBMF_TRANS_STATE_FLAG_DONE;

	} else {

		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
		    ibmf_i_terminate_transaction, IBMF_TNF_TRACE, "",
		    "ibmf_i_terminate_transaction(): %s, "
		    "trans_state_flags = 0x%x, msg_flags = 0x%x\n",
		    tnf_string, msg, "solicted message callback",
		    tnf_opaque, trans_state_flags,
		    msgimplp->im_trans_state_flags,
		    tnf_opaque, flags, msgimplp->im_flags);

		/* mark as recv_compl happened */
		msgimplp->im_trans_state_flags |=
		    IBMF_TRANS_STATE_FLAG_RECV_DONE;

		/*
		 * Check if last send is done before marking as done.
		 * We should get here for sequenced transactions and
		 * non-sequenced send RMPP transaction.
		 */
		if (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_terminate_transaction_end, IBMF_TNF_TRACE, "",
	    "ibmf_i_terminate_transaction() exit\n");
}