/* 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"); }
/* * 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"); }