17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * This file implements the MAD send logic in IBMF.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/ib/mgt/ibmf/ibmf_impl.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #define	IBMF_SEND_WR_ID_TO_ADDR(id, ptr)		\
347c478bd9Sstevel@tonic-gate 	(ptr) = (void *)(uintptr_t)(id)
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate extern int ibmf_trace_level;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static void ibmf_i_do_send_cb(void *taskq_arg);
397c478bd9Sstevel@tonic-gate static void ibmf_i_do_send_compl(ibmf_handle_t ibmf_handle,
407c478bd9Sstevel@tonic-gate     ibmf_msg_impl_t *msgimplp, ibmf_send_wqe_t *send_wqep);
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * ibmf_i_issue_pkt():
447c478bd9Sstevel@tonic-gate  *	Post an IB packet on the specified QP's send queue
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate int
ibmf_i_issue_pkt(ibmf_client_t * clientp,ibmf_msg_impl_t * msgimplp,ibmf_qp_handle_t ibmf_qp_handle,ibmf_send_wqe_t * send_wqep)477c478bd9Sstevel@tonic-gate ibmf_i_issue_pkt(ibmf_client_t *clientp, ibmf_msg_impl_t *msgimplp,
487c478bd9Sstevel@tonic-gate     ibmf_qp_handle_t ibmf_qp_handle, ibmf_send_wqe_t *send_wqep)
497c478bd9Sstevel@tonic-gate {
507c478bd9Sstevel@tonic-gate 	int			ret;
517c478bd9Sstevel@tonic-gate 	ibt_status_t		status;
527c478bd9Sstevel@tonic-gate 	ibt_wr_ds_t		sgl[1];
537c478bd9Sstevel@tonic-gate 	ibt_qp_hdl_t		ibt_qp_handle;
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate 	_NOTE(ASSUMING_PROTECTED(*send_wqep))
567c478bd9Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*send_wqep))
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
597c478bd9Sstevel@tonic-gate 	    ibmf_i_issue_pkt_start, IBMF_TNF_TRACE, "",
607c478bd9Sstevel@tonic-gate 	    "ibmf_i_issue_pkt() enter, clientp = %p, msg = %p, "
617c478bd9Sstevel@tonic-gate 	    "qp_hdl = %p,  swqep = %p\n", tnf_opaque, clientp, clientp,
627c478bd9Sstevel@tonic-gate 	    tnf_opaque, msg, msgimplp, tnf_opaque, ibmf_qp_handle,
637c478bd9Sstevel@tonic-gate 	    ibmf_qp_handle, tnf_opaque, send_wqep, send_wqep);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
667c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&clientp->ic_mutex));
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	/*
697c478bd9Sstevel@tonic-gate 	 * if the qp handle provided in ibmf_send_pkt()
707c478bd9Sstevel@tonic-gate 	 * is not the default qp handle for this client,
717c478bd9Sstevel@tonic-gate 	 * then the wqe must be sent on this qp,
727c478bd9Sstevel@tonic-gate 	 * else use the default qp handle set up during ibmf_register()
737c478bd9Sstevel@tonic-gate 	 */
747c478bd9Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
757c478bd9Sstevel@tonic-gate 		ibt_qp_handle = clientp->ic_qp->iq_qp_handle;
767c478bd9Sstevel@tonic-gate 	} else {
777c478bd9Sstevel@tonic-gate 		ibt_qp_handle =
787c478bd9Sstevel@tonic-gate 		    ((ibmf_alt_qp_t *)ibmf_qp_handle)->isq_qp_handle;
797c478bd9Sstevel@tonic-gate 	}
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	/* initialize the send WQE */
827c478bd9Sstevel@tonic-gate 	ibmf_i_init_send_wqe(clientp, msgimplp, sgl, send_wqep,
837c478bd9Sstevel@tonic-gate 	    msgimplp->im_ud_dest, ibt_qp_handle, ibmf_qp_handle);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*send_wqep))
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	/*
887c478bd9Sstevel@tonic-gate 	 * Issue the wqe to the transport.
897c478bd9Sstevel@tonic-gate 	 * NOTE: ibt_post_send() will not block, so, it is ok
907c478bd9Sstevel@tonic-gate 	 * to hold the msgimpl mutex across this call.
917c478bd9Sstevel@tonic-gate 	 */
927c478bd9Sstevel@tonic-gate 	status = ibt_post_send(send_wqep->send_qp_handle, &send_wqep->send_wr,
937c478bd9Sstevel@tonic-gate 	    1, NULL);
947c478bd9Sstevel@tonic-gate 	if (status != IBT_SUCCESS) {
957c478bd9Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
967c478bd9Sstevel@tonic-gate 		IBMF_ADD32_KSTATS(clientp, send_pkt_failed, 1);
977c478bd9Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
987c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
997c478bd9Sstevel@tonic-gate 		    ibmf_i_issue_pkt_err, IBMF_TNF_TRACE, "",
1007c478bd9Sstevel@tonic-gate 		    "ibmf_i_issue_pkt(): %s, status = %d\n",
1017c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "post send failure",
1027c478bd9Sstevel@tonic-gate 		    tnf_uint, ibt_status, status);
1037c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_issue_pkt_end,
1047c478bd9Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_i_issue_pkt(() exit\n");
1057c478bd9Sstevel@tonic-gate 		return (IBMF_TRANSPORT_FAILURE);
1067c478bd9Sstevel@tonic-gate 	}
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	ret = IBMF_SUCCESS;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	/* bump the number of active sends */
1117c478bd9Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1127c478bd9Sstevel@tonic-gate 		mutex_enter(&clientp->ic_mutex);
1137c478bd9Sstevel@tonic-gate 		clientp->ic_sends_active++;
1147c478bd9Sstevel@tonic-gate 		mutex_exit(&clientp->ic_mutex);
1157c478bd9Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
1167c478bd9Sstevel@tonic-gate 		IBMF_ADD32_KSTATS(clientp, sends_active, 1);
1177c478bd9Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
1187c478bd9Sstevel@tonic-gate 	} else {
1197c478bd9Sstevel@tonic-gate 		ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
1207c478bd9Sstevel@tonic-gate 		mutex_enter(&qpp->isq_mutex);
1217c478bd9Sstevel@tonic-gate 		qpp->isq_sends_active++;
1227c478bd9Sstevel@tonic-gate 		mutex_exit(&qpp->isq_mutex);
1237c478bd9Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
1247c478bd9Sstevel@tonic-gate 		IBMF_ADD32_KSTATS(clientp, sends_active, 1);
1257c478bd9Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
1267c478bd9Sstevel@tonic-gate 	}
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_issue_pkt_end,
1297c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_issue_pkt() exit\n");
1307c478bd9Sstevel@tonic-gate 	return (ret);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /*
1347c478bd9Sstevel@tonic-gate  * ibmf_i_send_pkt()
1357c478bd9Sstevel@tonic-gate  *	Send an IB packet after allocating send resources
1367c478bd9Sstevel@tonic-gate  */
1377c478bd9Sstevel@tonic-gate int
ibmf_i_send_pkt(ibmf_client_t * clientp,ibmf_qp_handle_t ibmf_qp_handle,ibmf_msg_impl_t * msgimplp,int block)1387c478bd9Sstevel@tonic-gate ibmf_i_send_pkt(ibmf_client_t *clientp, ibmf_qp_handle_t ibmf_qp_handle,
1397c478bd9Sstevel@tonic-gate     ibmf_msg_impl_t *msgimplp, int block)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	ibmf_send_wqe_t	*send_wqep;
1427c478bd9Sstevel@tonic-gate 	int		status;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_pkt_start,
1457c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "",
1467c478bd9Sstevel@tonic-gate 	    "ibmf_i_send_pkt(): clientp = 0x%p, qp_hdl = 0x%p, "
1477c478bd9Sstevel@tonic-gate 	    "msgp = 0x%p, block = %d\n", tnf_opaque, clientp, clientp,
1487c478bd9Sstevel@tonic-gate 	    tnf_opaque, qp_hdl, ibmf_qp_handle, tnf_opaque, msg, msgimplp,
1497c478bd9Sstevel@tonic-gate 	    tnf_uint, block, block);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*send_wqep))
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	/*
1567c478bd9Sstevel@tonic-gate 	 * Reset send_done to indicate we have not received the completion
1577c478bd9Sstevel@tonic-gate 	 * for this send yet.
1587c478bd9Sstevel@tonic-gate 	 */
1597c478bd9Sstevel@tonic-gate 	msgimplp->im_trans_state_flags &= ~IBMF_TRANS_STATE_FLAG_SEND_DONE;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	/*
1627c478bd9Sstevel@tonic-gate 	 * Allocate resources needed to send a UD packet including the
1637c478bd9Sstevel@tonic-gate 	 * send WQE context
1647c478bd9Sstevel@tonic-gate 	 */
1657c478bd9Sstevel@tonic-gate 	status = ibmf_i_alloc_send_resources(clientp->ic_myci,
1667c478bd9Sstevel@tonic-gate 	    msgimplp, block, &send_wqep);
1677c478bd9Sstevel@tonic-gate 	if (status != IBMF_SUCCESS) {
1687c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_send_pkt_err,
1697c478bd9Sstevel@tonic-gate 		    IBMF_TNF_ERROR, "", "ibmf_i_send_pkt(): %s, status = %d\n",
1707c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "unable to allocate send resources",
1717c478bd9Sstevel@tonic-gate 		    tnf_uint, status, status);
1727c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_send_pkt_end,
1737c478bd9Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_i_send_pkt() exit\n");
1747c478bd9Sstevel@tonic-gate 		return (status);
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	/* Set the segment number in the send WQE context */
1787c478bd9Sstevel@tonic-gate 	if (msgimplp->im_flags & IBMF_MSG_FLAGS_SEND_RMPP)
1797c478bd9Sstevel@tonic-gate 		send_wqep->send_rmpp_segment = msgimplp->im_rmpp_ctx.rmpp_ns;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*send_wqep))
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	/*
1847c478bd9Sstevel@tonic-gate 	 * Increment the count of pending send completions.
1857c478bd9Sstevel@tonic-gate 	 * Only when this count is zero should the client be notified
1867c478bd9Sstevel@tonic-gate 	 * of completion of the transaction.
1877c478bd9Sstevel@tonic-gate 	 */
1887c478bd9Sstevel@tonic-gate 	msgimplp->im_pending_send_compls += 1;
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	/* Send the packet */
1917c478bd9Sstevel@tonic-gate 	status = ibmf_i_issue_pkt(clientp, msgimplp, ibmf_qp_handle, send_wqep);
1927c478bd9Sstevel@tonic-gate 	if (status != IBMF_SUCCESS) {
1937c478bd9Sstevel@tonic-gate 		ibmf_i_free_send_resources(clientp->ic_myci, msgimplp,
1947c478bd9Sstevel@tonic-gate 		    send_wqep);
1957c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_send_pkt_err,
1967c478bd9Sstevel@tonic-gate 		    IBMF_TNF_ERROR, "", "ibmf_i_send_pkt(): %s, status = %d\n",
1977c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "unable to issue packet",
1987c478bd9Sstevel@tonic-gate 		    tnf_uint, status, status);
1997c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_send_pkt_end,
2007c478bd9Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_i_send_pkt() exit\n");
2017c478bd9Sstevel@tonic-gate 		return (status);
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_send_pkt_end,
2057c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_send_pkt() exit, status = %d\n",
2067c478bd9Sstevel@tonic-gate 	    tnf_uint, status, status);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	return (IBMF_SUCCESS);
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate  * ibmf_i_send_single_pkt():
2137c478bd9Sstevel@tonic-gate  *	Send a single IB packet.  Only used to send non-RMPP packets.
2147c478bd9Sstevel@tonic-gate  */
2157c478bd9Sstevel@tonic-gate int
ibmf_i_send_single_pkt(ibmf_client_t * clientp,ibmf_qp_handle_t ibmf_qp_handle,ibmf_msg_impl_t * msgimplp,int block)2167c478bd9Sstevel@tonic-gate ibmf_i_send_single_pkt(ibmf_client_t *clientp, ibmf_qp_handle_t ibmf_qp_handle,
2177c478bd9Sstevel@tonic-gate     ibmf_msg_impl_t *msgimplp, int block)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate 	int	status;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_single_pkt_start,
2227c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "",
2237c478bd9Sstevel@tonic-gate 	    "ibmf_i_send_single_pkt(): clientp = 0x%p, qp_hdl = 0x%p, "
2247c478bd9Sstevel@tonic-gate 	    "msgp = 0x%p, block = %d\n", tnf_opaque, clientp, clientp,
2257c478bd9Sstevel@tonic-gate 	    tnf_opaque, qp_hdl, ibmf_qp_handle, tnf_opaque, msg, msgimplp,
2267c478bd9Sstevel@tonic-gate 	    tnf_uint, block, block);
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	status = ibmf_i_send_pkt(clientp, ibmf_qp_handle, msgimplp, block);
2317c478bd9Sstevel@tonic-gate 	if (status != IBMF_SUCCESS) {
2327c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2337c478bd9Sstevel@tonic-gate 		    ibmf_i_send_single_pkt_err, IBMF_TNF_ERROR, "",
2347c478bd9Sstevel@tonic-gate 		    "ibmf_i_send_single_pkt(): %s, msgp = 0x%p\n",
2357c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "unable to send packet",
2367c478bd9Sstevel@tonic-gate 		    tnf_uint, status, status);
2377c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2387c478bd9Sstevel@tonic-gate 		    ibmf_i_send_single_pkt_end, IBMF_TNF_TRACE, "",
2397c478bd9Sstevel@tonic-gate 		    "ibmf_i_send_single_pkt() exit\n");
2407c478bd9Sstevel@tonic-gate 		return (status);
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_send_single_pkt_end,
2447c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_send_single_pkt() exit\n");
2457c478bd9Sstevel@tonic-gate 	return (IBMF_SUCCESS);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate  * ibmf_i_handle_send_completion():
2507c478bd9Sstevel@tonic-gate  *	Process the WQE from the SQ identified in the work completion entry.
2517c478bd9Sstevel@tonic-gate  */
2527c478bd9Sstevel@tonic-gate /* ARGSUSED */
2537c478bd9Sstevel@tonic-gate void
ibmf_i_handle_send_completion(ibmf_ci_t * cip,ibt_wc_t * wcp)2547c478bd9Sstevel@tonic-gate ibmf_i_handle_send_completion(ibmf_ci_t *cip, ibt_wc_t *wcp)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	ibmf_client_t		*clientp, *cclientp;
2577c478bd9Sstevel@tonic-gate 	ibmf_send_wqe_t		*send_wqep;
2587c478bd9Sstevel@tonic-gate 	ibmf_qp_handle_t	ibmf_qp_handle;
2597c478bd9Sstevel@tonic-gate 	ibmf_alt_qp_t		*qpp;
2607c478bd9Sstevel@tonic-gate 	int			ret;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
2637c478bd9Sstevel@tonic-gate 	    ibmf_i_handle_send_completion_start, IBMF_TNF_TRACE, "",
2647c478bd9Sstevel@tonic-gate 	    "ibmf_i_handle_send_completion() enter, cip = %p, wcp = %p\n",
2657c478bd9Sstevel@tonic-gate 	    tnf_opaque, cip, cip, tnf_opaque, wcp, wcp);
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*send_wqep))
2687c478bd9Sstevel@tonic-gate 
269*525f8227SToomas Soome 	ASSERT(wcp->wc_id != 0);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	ASSERT(IBMF_IS_SEND_WR_ID(wcp->wc_id));
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	/* get the IBMF send WQE context */
2747c478bd9Sstevel@tonic-gate 	IBMF_SEND_WR_ID_TO_ADDR(wcp->wc_id, send_wqep);
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	ASSERT(send_wqep != NULL);
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	/* get the client context */
2797c478bd9Sstevel@tonic-gate 	cclientp =  clientp = send_wqep->send_client;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	/* Check if this is a completion for a BUSY MAD sent by IBMF */
2827c478bd9Sstevel@tonic-gate 	if (clientp == NULL) {
2837c478bd9Sstevel@tonic-gate 		ibmf_msg_impl_t		*msgimplp;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L3,
2867c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_send_completion, IBMF_TNF_TRACE, "",
2877c478bd9Sstevel@tonic-gate 		    "ibmf_i_handle_send_completion(): NULL client\n");
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 		msgimplp = send_wqep->send_msg;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 		/*
2927c478bd9Sstevel@tonic-gate 		 * Deregister registered memory and free it, and
2937c478bd9Sstevel@tonic-gate 		 * free up the send WQE context
2947c478bd9Sstevel@tonic-gate 		 */
2957c478bd9Sstevel@tonic-gate 		(void) ibt_deregister_mr(cip->ci_ci_handle,
2967c478bd9Sstevel@tonic-gate 		    send_wqep->send_mem_hdl);
2977c478bd9Sstevel@tonic-gate 		kmem_free(send_wqep->send_mem, IBMF_MEM_PER_WQE);
2987c478bd9Sstevel@tonic-gate 		kmem_free(send_wqep, sizeof (ibmf_send_wqe_t));
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 		/* Free up the message context */
3017c478bd9Sstevel@tonic-gate 		ibmf_i_put_ud_dest(cip, msgimplp->im_ibmf_ud_dest);
3027c478bd9Sstevel@tonic-gate 		ibmf_i_clean_ud_dest_list(cip, B_FALSE);
3037c478bd9Sstevel@tonic-gate 		kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
3047c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3057c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_send_completion_end, IBMF_TNF_TRACE, "",
3067c478bd9Sstevel@tonic-gate 		    "ibmf_i_handle_send_completion() exit\n");
3077c478bd9Sstevel@tonic-gate 		return;
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/* get the QP handle */
3117c478bd9Sstevel@tonic-gate 	ibmf_qp_handle = send_wqep->send_ibmf_qp_handle;
3127c478bd9Sstevel@tonic-gate 	qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	ASSERT(clientp != NULL);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	/* decrement the number of active sends */
3177c478bd9Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
3187c478bd9Sstevel@tonic-gate 		mutex_enter(&clientp->ic_mutex);
3197c478bd9Sstevel@tonic-gate 		clientp->ic_sends_active--;
3207c478bd9Sstevel@tonic-gate 		mutex_exit(&clientp->ic_mutex);
3217c478bd9Sstevel@tonic-gate 	} else {
3227c478bd9Sstevel@tonic-gate 		mutex_enter(&qpp->isq_mutex);
3237c478bd9Sstevel@tonic-gate 		qpp->isq_sends_active--;
3247c478bd9Sstevel@tonic-gate 		mutex_exit(&qpp->isq_mutex);
3257c478bd9Sstevel@tonic-gate 	}
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	mutex_enter(&clientp->ic_kstat_mutex);
3287c478bd9Sstevel@tonic-gate 	IBMF_SUB32_KSTATS(clientp, sends_active, 1);
3297c478bd9Sstevel@tonic-gate 	mutex_exit(&clientp->ic_kstat_mutex);
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	send_wqep->send_status = ibmf_i_ibt_wc_to_ibmf_status(wcp->wc_status);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	/*
3347c478bd9Sstevel@tonic-gate 	 * issue the callback using taskq. If no taskq or if the
3357c478bd9Sstevel@tonic-gate 	 * dispatch fails, we do the send processing in the callback context
3367c478bd9Sstevel@tonic-gate 	 * which is the interrupt context
3377c478bd9Sstevel@tonic-gate 	 */
3387c478bd9Sstevel@tonic-gate 	if (cclientp->ic_send_taskq == NULL) {
3397c478bd9Sstevel@tonic-gate 		/* Do the processing in callback context */
3407c478bd9Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
3417c478bd9Sstevel@tonic-gate 		IBMF_ADD32_KSTATS(clientp, send_cb_active, 1);
3427c478bd9Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
3437c478bd9Sstevel@tonic-gate 		ibmf_i_do_send_cb((void *)send_wqep);
3447c478bd9Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
3457c478bd9Sstevel@tonic-gate 		IBMF_SUB32_KSTATS(clientp, send_cb_active, 1);
3467c478bd9Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
3477c478bd9Sstevel@tonic-gate 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
3487c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_send_err, IBMF_TNF_ERROR, "",
3497c478bd9Sstevel@tonic-gate 		    "ibmf_i_handle_send_completion(): %s\n",
3507c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "ci_send_taskq == NULL");
3517c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3527c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_send_completion_end, IBMF_TNF_TRACE, "",
3537c478bd9Sstevel@tonic-gate 		    "ibmf_i_handle_send_completion() exit\n");
3547c478bd9Sstevel@tonic-gate 		return;
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	mutex_enter(&clientp->ic_kstat_mutex);
3587c478bd9Sstevel@tonic-gate 	IBMF_ADD32_KSTATS(clientp, send_cb_active, 1);
3597c478bd9Sstevel@tonic-gate 	mutex_exit(&clientp->ic_kstat_mutex);
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	/* Use taskq for processing if the IBMF_REG_FLAG_NO_OFFLOAD isn't set */
3627c478bd9Sstevel@tonic-gate 	if ((clientp->ic_reg_flags & IBMF_REG_FLAG_NO_OFFLOAD) == 0) {
3637c478bd9Sstevel@tonic-gate 		ret = taskq_dispatch(cclientp->ic_send_taskq, ibmf_i_do_send_cb,
3647c478bd9Sstevel@tonic-gate 		    send_wqep, TQ_NOSLEEP);
365fc8ae2ecSToomas Soome 		if (ret == TASKQID_INVALID) {
3667c478bd9Sstevel@tonic-gate 			IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
3677c478bd9Sstevel@tonic-gate 			    ibmf_i_handle_send_err, IBMF_TNF_ERROR, "",
3687c478bd9Sstevel@tonic-gate 			    "ibmf_i_handle_send_completion(): %s\n",
3697c478bd9Sstevel@tonic-gate 			    tnf_string, msg, "send: dispatch failed");
3707c478bd9Sstevel@tonic-gate 			ibmf_i_do_send_cb((void *)send_wqep);
3717c478bd9Sstevel@tonic-gate 		}
3727c478bd9Sstevel@tonic-gate 	} else {
3737c478bd9Sstevel@tonic-gate 		ibmf_i_do_send_cb((void *)send_wqep);
3747c478bd9Sstevel@tonic-gate 	}
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	mutex_enter(&clientp->ic_kstat_mutex);
3777c478bd9Sstevel@tonic-gate 	IBMF_SUB32_KSTATS(clientp, send_cb_active, 1);
3787c478bd9Sstevel@tonic-gate 	mutex_exit(&clientp->ic_kstat_mutex);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*send_wqep))
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3837c478bd9Sstevel@tonic-gate 	    ibmf_i_handle_send_completion_end, IBMF_TNF_TRACE, "",
3847c478bd9Sstevel@tonic-gate 	    "ibmf_i_handle_send_completion() exit\n");
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate /*
3887c478bd9Sstevel@tonic-gate  * ibmf_i_do_send_cb():
3897c478bd9Sstevel@tonic-gate  *	Do the send completion processing
3907c478bd9Sstevel@tonic-gate  */
3917c478bd9Sstevel@tonic-gate static void
ibmf_i_do_send_cb(void * taskq_arg)3927c478bd9Sstevel@tonic-gate ibmf_i_do_send_cb(void *taskq_arg)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	ibmf_ci_t		*cip;
3957c478bd9Sstevel@tonic-gate 	ibmf_msg_impl_t		*msgimplp;
3967c478bd9Sstevel@tonic-gate 	ibmf_client_t		*clientp;
3977c478bd9Sstevel@tonic-gate 	ibmf_send_wqe_t		*send_wqep;
3987c478bd9Sstevel@tonic-gate 	boolean_t		found;
3997c478bd9Sstevel@tonic-gate 	int			msg_trans_state_flags, msg_flags;
4007c478bd9Sstevel@tonic-gate 	uint_t			ref_cnt;
4017c478bd9Sstevel@tonic-gate 	ibmf_qp_handle_t	ibmf_qp_handle;
4027c478bd9Sstevel@tonic-gate 	struct kmem_cache	*kmem_cachep;
4037c478bd9Sstevel@tonic-gate 	timeout_id_t		msg_rp_unset_id, msg_tr_unset_id;
4047c478bd9Sstevel@tonic-gate 	timeout_id_t		msg_rp_set_id, msg_tr_set_id;
4057c478bd9Sstevel@tonic-gate 	ibmf_alt_qp_t		*altqp;
4067c478bd9Sstevel@tonic-gate 	boolean_t		inc_refcnt;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	send_wqep = taskq_arg;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
4117c478bd9Sstevel@tonic-gate 	    ibmf_i_do_send_cb_start, IBMF_TNF_TRACE, "",
4127c478bd9Sstevel@tonic-gate 	    "ibmf_i_do_send_cb() enter, send_wqep = %p\n",
4137c478bd9Sstevel@tonic-gate 	    tnf_opaque, send_wqep, send_wqep);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	clientp = send_wqep->send_client;
4167c478bd9Sstevel@tonic-gate 	cip = clientp->ic_myci;
4177c478bd9Sstevel@tonic-gate 	msgimplp = send_wqep->send_msg;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	/* get the QP handle */
4207c478bd9Sstevel@tonic-gate 	ibmf_qp_handle = send_wqep->send_ibmf_qp_handle;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	/* Get the WQE kmem cache pointer based on the QP type */
4237c478bd9Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT)
4247c478bd9Sstevel@tonic-gate 		kmem_cachep = cip->ci_send_wqes_cache;
4257c478bd9Sstevel@tonic-gate 	else {
4267c478bd9Sstevel@tonic-gate 		altqp = (ibmf_alt_qp_t *)ibmf_qp_handle;
4277c478bd9Sstevel@tonic-gate 		kmem_cachep = altqp->isq_send_wqes_cache;
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	/* Look for a message in the client's message list */
4317c478bd9Sstevel@tonic-gate 	inc_refcnt = B_TRUE;
4327c478bd9Sstevel@tonic-gate 	found = ibmf_i_find_msg_client(clientp, msgimplp, inc_refcnt);
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	/*
4357c478bd9Sstevel@tonic-gate 	 * If the message context was not found, then it's likely
4367c478bd9Sstevel@tonic-gate 	 * been freed up. So, do nothing in this timeout handler
4377c478bd9Sstevel@tonic-gate 	 */
4387c478bd9Sstevel@tonic-gate 	if (found == B_FALSE) {
4397c478bd9Sstevel@tonic-gate 		kmem_cache_free(kmem_cachep, send_wqep);
4407c478bd9Sstevel@tonic-gate 		mutex_enter(&cip->ci_mutex);
4417c478bd9Sstevel@tonic-gate 		IBMF_SUB32_PORT_KSTATS(cip, send_wqes_alloced, 1);
4427c478bd9Sstevel@tonic-gate 		mutex_exit(&cip->ci_mutex);
4437c478bd9Sstevel@tonic-gate 		if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
4447c478bd9Sstevel@tonic-gate 			mutex_enter(&cip->ci_mutex);
4457c478bd9Sstevel@tonic-gate 			cip->ci_wqes_alloced--;
4467c478bd9Sstevel@tonic-gate 			if (cip->ci_wqes_alloced == 0)
4477c478bd9Sstevel@tonic-gate 				cv_signal(&cip->ci_wqes_cv);
4487c478bd9Sstevel@tonic-gate 			mutex_exit(&cip->ci_mutex);
4497c478bd9Sstevel@tonic-gate 		} else {
4507c478bd9Sstevel@tonic-gate 			mutex_enter(&altqp->isq_mutex);
4517c478bd9Sstevel@tonic-gate 			altqp->isq_wqes_alloced--;
4527c478bd9Sstevel@tonic-gate 			if (altqp->isq_wqes_alloced == 0)
4537c478bd9Sstevel@tonic-gate 				cv_signal(&altqp->isq_wqes_cv);
4547c478bd9Sstevel@tonic-gate 			mutex_exit(&altqp->isq_mutex);
4557c478bd9Sstevel@tonic-gate 		}
4567c478bd9Sstevel@tonic-gate 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
4577c478bd9Sstevel@tonic-gate 		    ibmf_i_do_send_cb, IBMF_TNF_TRACE, "",
4587c478bd9Sstevel@tonic-gate 		    "ibmf_i_do_send_cb(): %s\n", tnf_string, msg,
4597c478bd9Sstevel@tonic-gate 		    "Message not found, return without processing send cb");
4607c478bd9Sstevel@tonic-gate 		return;
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	/* Grab the message context lock */
4647c478bd9Sstevel@tonic-gate 	mutex_enter(&msgimplp->im_mutex);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	/*
4677c478bd9Sstevel@tonic-gate 	 * Decrement the count of pending send completions for
4687c478bd9Sstevel@tonic-gate 	 * this transaction
4697c478bd9Sstevel@tonic-gate 	 */
4707c478bd9Sstevel@tonic-gate 	msgimplp->im_pending_send_compls -= 1;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	/*
4737c478bd9Sstevel@tonic-gate 	 * If the pending send completions is not zero, then we must
4747c478bd9Sstevel@tonic-gate 	 * not attempt to notify the client of a transaction completion
4757c478bd9Sstevel@tonic-gate 	 * in this instance of the send completion handler. Notification
4767c478bd9Sstevel@tonic-gate 	 * of transaction completion should be provided only by the
4777c478bd9Sstevel@tonic-gate 	 * last send completion so that all send completions are accounted
4787c478bd9Sstevel@tonic-gate 	 * for before the client is notified and subsequently attempts to
4797c478bd9Sstevel@tonic-gate 	 * reuse the message for an other transaction.
4807c478bd9Sstevel@tonic-gate 	 * If this is not done, the message may be reused while the
4817c478bd9Sstevel@tonic-gate 	 * send WR from the old transaction is still active in the QP's WQ.
4827c478bd9Sstevel@tonic-gate 	 * This could result in an attempt to modify the address handle with
4837c478bd9Sstevel@tonic-gate 	 * information for the new transaction which could be potentially
4847c478bd9Sstevel@tonic-gate 	 * incompatible, such as an incorrect port number. Such an
4857c478bd9Sstevel@tonic-gate 	 * incompatible modification of the address handle of the old
4867c478bd9Sstevel@tonic-gate 	 * transaction could result in a QP error.
4877c478bd9Sstevel@tonic-gate 	 */
4887c478bd9Sstevel@tonic-gate 	if (msgimplp->im_pending_send_compls != 0) {
4897c478bd9Sstevel@tonic-gate 		IBMF_MSG_DECR_REFCNT(msgimplp);
4907c478bd9Sstevel@tonic-gate 		mutex_exit(&msgimplp->im_mutex);
4917c478bd9Sstevel@tonic-gate 		kmem_cache_free(kmem_cachep, send_wqep);
4927c478bd9Sstevel@tonic-gate 		mutex_enter(&cip->ci_mutex);
4937c478bd9Sstevel@tonic-gate 		IBMF_SUB32_PORT_KSTATS(cip, send_wqes_alloced, 1);
4947c478bd9Sstevel@tonic-gate 		mutex_exit(&cip->ci_mutex);
4957c478bd9Sstevel@tonic-gate 		if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
4967c478bd9Sstevel@tonic-gate 			mutex_enter(&cip->ci_mutex);
4977c478bd9Sstevel@tonic-gate 			cip->ci_wqes_alloced--;
4987c478bd9Sstevel@tonic-gate 			if (cip->ci_wqes_alloced == 0)
4997c478bd9Sstevel@tonic-gate 				cv_signal(&cip->ci_wqes_cv);
5007c478bd9Sstevel@tonic-gate 			mutex_exit(&cip->ci_mutex);
5017c478bd9Sstevel@tonic-gate 		} else {
5027c478bd9Sstevel@tonic-gate 			mutex_enter(&altqp->isq_mutex);
5037c478bd9Sstevel@tonic-gate 			altqp->isq_wqes_alloced--;
5047c478bd9Sstevel@tonic-gate 			if (altqp->isq_wqes_alloced == 0)
5057c478bd9Sstevel@tonic-gate 				cv_signal(&altqp->isq_wqes_cv);
5067c478bd9Sstevel@tonic-gate 			mutex_exit(&altqp->isq_mutex);
5077c478bd9Sstevel@tonic-gate 		}
5087c478bd9Sstevel@tonic-gate 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
5097c478bd9Sstevel@tonic-gate 		    ibmf_i_do_send_cb, IBMF_TNF_TRACE, "",
5107c478bd9Sstevel@tonic-gate 		    "ibmf_i_do_send_cb(): %s\n", tnf_string, msg,
5117c478bd9Sstevel@tonic-gate 		    "Message found with pending send completions, "
5127c478bd9Sstevel@tonic-gate 		    "return without processing send cb");
5137c478bd9Sstevel@tonic-gate 		return;
5147c478bd9Sstevel@tonic-gate 	}
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	/*
5177c478bd9Sstevel@tonic-gate 	 * If the message has been marked unitialized or done
5187c478bd9Sstevel@tonic-gate 	 * release the message mutex and return
5197c478bd9Sstevel@tonic-gate 	 */
5207c478bd9Sstevel@tonic-gate 	if ((msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_UNINIT) ||
5217c478bd9Sstevel@tonic-gate 	    (msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE)) {
5227c478bd9Sstevel@tonic-gate 		IBMF_MSG_DECR_REFCNT(msgimplp);
5237c478bd9Sstevel@tonic-gate 		msg_trans_state_flags = msgimplp->im_trans_state_flags;
5247c478bd9Sstevel@tonic-gate 		msg_flags = msgimplp->im_flags;
5257c478bd9Sstevel@tonic-gate 		ref_cnt = msgimplp->im_ref_count;
5267c478bd9Sstevel@tonic-gate 		mutex_exit(&msgimplp->im_mutex);
5277c478bd9Sstevel@tonic-gate 		/*
5287c478bd9Sstevel@tonic-gate 		 * This thread may notify the client only if the
5297c478bd9Sstevel@tonic-gate 		 * transaction is done, the message has been removed
5307c478bd9Sstevel@tonic-gate 		 * from the client's message list, and the message
5317c478bd9Sstevel@tonic-gate 		 * reference count is 0.
5327c478bd9Sstevel@tonic-gate 		 * If the transaction is done, and the message reference
5337c478bd9Sstevel@tonic-gate 		 * count = 0, there is still a possibility that a
5347c478bd9Sstevel@tonic-gate 		 * packet could arrive for the message and its reference
5357c478bd9Sstevel@tonic-gate 		 * count increased if the message is still on the list.
5367c478bd9Sstevel@tonic-gate 		 * If the message is still on the list, it will be
5377c478bd9Sstevel@tonic-gate 		 * removed by a call to ibmf_i_client_rem_msg() at
5387c478bd9Sstevel@tonic-gate 		 * the completion point of the transaction.
5397c478bd9Sstevel@tonic-gate 		 * So, the reference count should be checked after the
5407c478bd9Sstevel@tonic-gate 		 * message has been removed.
5417c478bd9Sstevel@tonic-gate 		 */
5427c478bd9Sstevel@tonic-gate 		if ((msg_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE) &&
5437c478bd9Sstevel@tonic-gate 		    !(msg_flags & IBMF_MSG_FLAGS_ON_LIST) &&
5447c478bd9Sstevel@tonic-gate 		    (ref_cnt == 0)) {
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 			ibmf_i_notify_sequence(clientp, msgimplp, msg_flags);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 		}
5497c478bd9Sstevel@tonic-gate 		kmem_cache_free(kmem_cachep, send_wqep);
5507c478bd9Sstevel@tonic-gate 		mutex_enter(&cip->ci_mutex);
5517c478bd9Sstevel@tonic-gate 		IBMF_SUB32_PORT_KSTATS(cip, send_wqes_alloced, 1);
5527c478bd9Sstevel@tonic-gate 		mutex_exit(&cip->ci_mutex);
5537c478bd9Sstevel@tonic-gate 		if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
5547c478bd9Sstevel@tonic-gate 			mutex_enter(&cip->ci_mutex);
5557c478bd9Sstevel@tonic-gate 			cip->ci_wqes_alloced--;
5567c478bd9Sstevel@tonic-gate 			if (cip->ci_wqes_alloced == 0)
5577c478bd9Sstevel@tonic-gate 				cv_signal(&cip->ci_wqes_cv);
5587c478bd9Sstevel@tonic-gate 			mutex_exit(&cip->ci_mutex);
5597c478bd9Sstevel@tonic-gate 		} else {
5607c478bd9Sstevel@tonic-gate 			mutex_enter(&altqp->isq_mutex);
5617c478bd9Sstevel@tonic-gate 			altqp->isq_wqes_alloced--;
5627c478bd9Sstevel@tonic-gate 			if (altqp->isq_wqes_alloced == 0)
5637c478bd9Sstevel@tonic-gate 				cv_signal(&altqp->isq_wqes_cv);
5647c478bd9Sstevel@tonic-gate 			mutex_exit(&altqp->isq_mutex);
5657c478bd9Sstevel@tonic-gate 		}
5667c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
5677c478bd9Sstevel@tonic-gate 		    ibmf_i_do_send_cb, IBMF_TNF_TRACE, "",
5687c478bd9Sstevel@tonic-gate 		    "ibmf_i_do_send_cb(): %s, msg = %p\n", tnf_string, msg,
5697c478bd9Sstevel@tonic-gate 		    "Message marked for removal, return without processing "
5707c478bd9Sstevel@tonic-gate 		    "send cb", tnf_opaque, msgimplp, msgimplp);
5717c478bd9Sstevel@tonic-gate 		return;
5727c478bd9Sstevel@tonic-gate 	}
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	/* Perform send completion processing of the message context */
5757c478bd9Sstevel@tonic-gate 	ibmf_i_do_send_compl((ibmf_handle_t)clientp, msgimplp, send_wqep);
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	msg_rp_unset_id = msg_tr_unset_id = msg_rp_set_id = msg_tr_set_id = 0;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	/* Save the message flags before releasing the mutex */
5807c478bd9Sstevel@tonic-gate 	msg_trans_state_flags = msgimplp->im_trans_state_flags;
5817c478bd9Sstevel@tonic-gate 	msg_flags = msgimplp->im_flags;
5827c478bd9Sstevel@tonic-gate 	msg_rp_unset_id = msgimplp->im_rp_unset_timeout_id;
5837c478bd9Sstevel@tonic-gate 	msg_tr_unset_id = msgimplp->im_tr_unset_timeout_id;
5847c478bd9Sstevel@tonic-gate 	msgimplp->im_rp_unset_timeout_id = 0;
5857c478bd9Sstevel@tonic-gate 	msgimplp->im_tr_unset_timeout_id = 0;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	/*
5887c478bd9Sstevel@tonic-gate 	 * Decrement the message reference count
5897c478bd9Sstevel@tonic-gate 	 * This count was inceremented when the message was found on the
5907c478bd9Sstevel@tonic-gate 	 * client's message list
5917c478bd9Sstevel@tonic-gate 	 */
5927c478bd9Sstevel@tonic-gate 	IBMF_MSG_DECR_REFCNT(msgimplp);
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	if (msg_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE) {
5957c478bd9Sstevel@tonic-gate 		if (msgimplp->im_rp_timeout_id != 0) {
5967c478bd9Sstevel@tonic-gate 			msg_rp_set_id = msgimplp->im_rp_timeout_id;
5977c478bd9Sstevel@tonic-gate 			msgimplp->im_rp_timeout_id = 0;
5987c478bd9Sstevel@tonic-gate 		}
5997c478bd9Sstevel@tonic-gate 		if (msgimplp->im_tr_timeout_id != 0) {
6007c478bd9Sstevel@tonic-gate 			msg_tr_set_id = msgimplp->im_tr_timeout_id;
6017c478bd9Sstevel@tonic-gate 			msgimplp->im_tr_timeout_id = 0;
6027c478bd9Sstevel@tonic-gate 		}
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	mutex_exit(&msgimplp->im_mutex);
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	if (msg_rp_unset_id != 0) {
6087c478bd9Sstevel@tonic-gate 		(void) untimeout(msg_rp_unset_id);
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	if (msg_tr_unset_id != 0) {
6127c478bd9Sstevel@tonic-gate 		(void) untimeout(msg_tr_unset_id);
6137c478bd9Sstevel@tonic-gate 	}
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	if (msg_rp_set_id != 0) {
6167c478bd9Sstevel@tonic-gate 		(void) untimeout(msg_rp_set_id);
6177c478bd9Sstevel@tonic-gate 	}
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	if (msg_tr_set_id != 0) {
6207c478bd9Sstevel@tonic-gate 		(void) untimeout(msg_tr_set_id);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
6247c478bd9Sstevel@tonic-gate 	    ibmf_i_do_send_cb, IBMF_TNF_TRACE, "",
6257c478bd9Sstevel@tonic-gate 	    "ibmf_i_do_send_cb(): %s, msg = %p\n",
6267c478bd9Sstevel@tonic-gate 	    tnf_string, msg, "Send callback done.  Dec ref count",
6277c478bd9Sstevel@tonic-gate 	    tnf_opaque, msgimplp, msgimplp);
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	/*
6307c478bd9Sstevel@tonic-gate 	 * If the transaction is done, signal the block thread if the
6317c478bd9Sstevel@tonic-gate 	 * transaction is blocking, or call the client's transaction done
6327c478bd9Sstevel@tonic-gate 	 * notification callback
6337c478bd9Sstevel@tonic-gate 	 */
6347c478bd9Sstevel@tonic-gate 	if (msg_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE) {
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 		/* Remove the message from the client's message list */
6377c478bd9Sstevel@tonic-gate 		ibmf_i_client_rem_msg(clientp, msgimplp, &ref_cnt);
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 		/*
6407c478bd9Sstevel@tonic-gate 		 * Notify the client if the message reference count is zero.
6417c478bd9Sstevel@tonic-gate 		 * At this point, we know that the transaction is done and
6427c478bd9Sstevel@tonic-gate 		 * the message has been removed from the client's message list.
6437c478bd9Sstevel@tonic-gate 		 * So, we only need to make sure the reference count is zero
6447c478bd9Sstevel@tonic-gate 		 * before notifying the client.
6457c478bd9Sstevel@tonic-gate 		 */
6467c478bd9Sstevel@tonic-gate 		if (ref_cnt == 0) {
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 			ibmf_i_notify_sequence(clientp, msgimplp, msg_flags);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		}
6517c478bd9Sstevel@tonic-gate 	}
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	kmem_cache_free(kmem_cachep, send_wqep);
6547c478bd9Sstevel@tonic-gate 	mutex_enter(&cip->ci_mutex);
6557c478bd9Sstevel@tonic-gate 	IBMF_SUB32_PORT_KSTATS(cip, send_wqes_alloced, 1);
6567c478bd9Sstevel@tonic-gate 	mutex_exit(&cip->ci_mutex);
6577c478bd9Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
6587c478bd9Sstevel@tonic-gate 		mutex_enter(&cip->ci_mutex);
6597c478bd9Sstevel@tonic-gate 		cip->ci_wqes_alloced--;
6607c478bd9Sstevel@tonic-gate 		if (cip->ci_wqes_alloced == 0)
6617c478bd9Sstevel@tonic-gate 			cv_signal(&cip->ci_wqes_cv);
6627c478bd9Sstevel@tonic-gate 		mutex_exit(&cip->ci_mutex);
6637c478bd9Sstevel@tonic-gate 	} else {
6647c478bd9Sstevel@tonic-gate 		mutex_enter(&altqp->isq_mutex);
6657c478bd9Sstevel@tonic-gate 		altqp->isq_wqes_alloced--;
6667c478bd9Sstevel@tonic-gate 		if (altqp->isq_wqes_alloced == 0)
6677c478bd9Sstevel@tonic-gate 			cv_signal(&altqp->isq_wqes_cv);
6687c478bd9Sstevel@tonic-gate 		mutex_exit(&altqp->isq_mutex);
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
6727c478bd9Sstevel@tonic-gate 	    ibmf_i_do_send_cb_end, IBMF_TNF_TRACE, "",
6737c478bd9Sstevel@tonic-gate 	    "ibmf_i_do_send_cb() exit\n");
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate /*
6777c478bd9Sstevel@tonic-gate  * ibmf_i_do_send_compl():
6787c478bd9Sstevel@tonic-gate  *	Determine if the transaction is complete
6797c478bd9Sstevel@tonic-gate  */
6807c478bd9Sstevel@tonic-gate /* ARGSUSED */
6817c478bd9Sstevel@tonic-gate static void
ibmf_i_do_send_compl(ibmf_handle_t ibmf_handle,ibmf_msg_impl_t * msgimplp,ibmf_send_wqe_t * send_wqep)6827c478bd9Sstevel@tonic-gate ibmf_i_do_send_compl(ibmf_handle_t ibmf_handle, ibmf_msg_impl_t *msgimplp,
6837c478bd9Sstevel@tonic-gate     ibmf_send_wqe_t *send_wqep)
6847c478bd9Sstevel@tonic-gate {
6857c478bd9Sstevel@tonic-gate 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_do_send_compl_start,
6867c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_do_send_compl(): ibmf_hdl = 0x%p "
6877c478bd9Sstevel@tonic-gate 	    "msgp = %p, send_wqep = 0x%p, msg_flags = 0x%x\n",
6887c478bd9Sstevel@tonic-gate 	    tnf_opaque, ibmf_hdl, ibmf_handle, tnf_opaque, msgimplp, msgimplp,
6897c478bd9Sstevel@tonic-gate 	    tnf_opaque, send_wqep, send_wqep,
6907c478bd9Sstevel@tonic-gate 	    tnf_opaque, msg_flags, msgimplp->im_flags);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	/*
6957c478bd9Sstevel@tonic-gate 	 * For RMPP transactions, we only care about the final packet of the
6967c478bd9Sstevel@tonic-gate 	 * transaction.  For others, the code does not need to wait for the send
6977c478bd9Sstevel@tonic-gate 	 * completion (although bad things can happen if it never occurs).
6987c478bd9Sstevel@tonic-gate 	 * The final packets of a transaction are sent when the state is either
6997c478bd9Sstevel@tonic-gate 	 * ABORT or RECEVR_TERMINATE.
7007c478bd9Sstevel@tonic-gate 	 * Don't mark the transaction as send_done if there are still more
7017c478bd9Sstevel@tonic-gate 	 * packets to be sent, including doing the second part of a double-sided
7027c478bd9Sstevel@tonic-gate 	 * transaction.
7037c478bd9Sstevel@tonic-gate 	 */
7047c478bd9Sstevel@tonic-gate 	if ((msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) ||
7057c478bd9Sstevel@tonic-gate 	    (msgimplp->im_flags & IBMF_MSG_FLAGS_SEND_RMPP)) {
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
7087c478bd9Sstevel@tonic-gate 		    ibmf_i_do_send_compl, IBMF_TNF_TRACE, "",
7097c478bd9Sstevel@tonic-gate 		    "ibmf_i_do_send_compl(): %s msgp = %p, rmpp_state = 0x%x\n",
7107c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Received send callback for RMPP trans",
7117c478bd9Sstevel@tonic-gate 		    tnf_opaque, msg, msgimplp,
7127c478bd9Sstevel@tonic-gate 		    tnf_opaque, rmpp_state, msgimplp->im_rmpp_ctx.rmpp_state);
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 		/*
7157c478bd9Sstevel@tonic-gate 		 * For ABORT state, we should not return control to
7167c478bd9Sstevel@tonic-gate 		 * the client from the send completion handler.
7177c478bd9Sstevel@tonic-gate 		 * Control should be returned in the error timeout handler.
7187c478bd9Sstevel@tonic-gate 		 *
7197c478bd9Sstevel@tonic-gate 		 * The exception is when the IBMF_TRANS_STATE_FLAG_RECV_DONE
7207c478bd9Sstevel@tonic-gate 		 * flag has already been set. This flag is set when
7217c478bd9Sstevel@tonic-gate 		 * ibmf_i_terminate_transaction is called from one of the
7227c478bd9Sstevel@tonic-gate 		 * three timeout handlers. In this case return control from
7237c478bd9Sstevel@tonic-gate 		 * here.
7247c478bd9Sstevel@tonic-gate 		 */
7257c478bd9Sstevel@tonic-gate 		if (msgimplp->im_rmpp_ctx.rmpp_state == IBMF_RMPP_STATE_ABORT) {
7267c478bd9Sstevel@tonic-gate 			msgimplp->im_trans_state_flags |=
7277c478bd9Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_SEND_DONE;
7287c478bd9Sstevel@tonic-gate 			if (msgimplp->im_trans_state_flags &
7297c478bd9Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
7307c478bd9Sstevel@tonic-gate 				msgimplp->im_trans_state_flags |=
7317c478bd9Sstevel@tonic-gate 				    IBMF_TRANS_STATE_FLAG_DONE;
7327c478bd9Sstevel@tonic-gate 			}
7337c478bd9Sstevel@tonic-gate 		}
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 		if ((msgimplp->im_rmpp_ctx.rmpp_state ==
7367c478bd9Sstevel@tonic-gate 		    IBMF_RMPP_STATE_RECEVR_TERMINATE) ||
7377c478bd9Sstevel@tonic-gate 		    (msgimplp->im_rmpp_ctx.rmpp_state ==
7387c478bd9Sstevel@tonic-gate 		    IBMF_RMPP_STATE_DONE)) {
7397c478bd9Sstevel@tonic-gate 			msgimplp->im_trans_state_flags |=
7407c478bd9Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_SEND_DONE;
7417c478bd9Sstevel@tonic-gate 			if (msgimplp->im_trans_state_flags  &
7427c478bd9Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
7437c478bd9Sstevel@tonic-gate 				msgimplp->im_trans_state_flags |=
7447c478bd9Sstevel@tonic-gate 				    IBMF_TRANS_STATE_FLAG_DONE;
7457c478bd9Sstevel@tonic-gate 			}
7467c478bd9Sstevel@tonic-gate 		}
7477c478bd9Sstevel@tonic-gate 
748d0141297Ssandipb 		/*
749d0141297Ssandipb 		 * If the transaction is a send-only RMPP, then
750d0141297Ssandipb 		 * set the SEND_DONE flag on every send completion
751d0141297Ssandipb 		 * as long as there are no outstanding ones.
752d0141297Ssandipb 		 * This is needed so that the transaction can return
753d0141297Ssandipb 		 * in the receive path, where ibmf_i_terminate_transaction
754d0141297Ssandipb 		 * is called from ibmf_i_rmpp_sender_active_flow,
755d0141297Ssandipb 		 * after checking if the SEND_DONE flag is set.
756d0141297Ssandipb 		 * When a new MAD is sent as part of the RMPP transaction,
757d0141297Ssandipb 		 * the SEND_DONE flag will get reset.
758d0141297Ssandipb 		 * The RECV_DONE indicates that the last ACK was received.
759d0141297Ssandipb 		 */
760d0141297Ssandipb 		if ((msgimplp->im_flags & IBMF_MSG_FLAGS_SEQUENCED) == 0) {
761d0141297Ssandipb 			if (msgimplp->im_pending_send_compls == 0) {
762d0141297Ssandipb 				msgimplp->im_trans_state_flags |=
763d0141297Ssandipb 				    IBMF_TRANS_STATE_FLAG_SEND_DONE;
764d0141297Ssandipb 				if (msgimplp->im_trans_state_flags  &
765d0141297Ssandipb 				    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
766d0141297Ssandipb 					msgimplp->im_trans_state_flags |=
767d0141297Ssandipb 					    IBMF_TRANS_STATE_FLAG_DONE;
768d0141297Ssandipb 				}
769d0141297Ssandipb 			}
770d0141297Ssandipb 		}
771d0141297Ssandipb 
7727c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
7737c478bd9Sstevel@tonic-gate 		    ibmf_i_do_send_compl_end, IBMF_TNF_TRACE, "",
7747c478bd9Sstevel@tonic-gate 		    "ibmf_i_do_send_compl() exit\n");
7757c478bd9Sstevel@tonic-gate 		return;
7767c478bd9Sstevel@tonic-gate 	}
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	/*
7797c478bd9Sstevel@tonic-gate 	 * Only non-RMPP send completion gets here.
7807c478bd9Sstevel@tonic-gate 	 * If the send is a single-packet send that does not use RMPP, and if
7817c478bd9Sstevel@tonic-gate 	 * the transaction is not a sequenced transaction, call the transaction
7827c478bd9Sstevel@tonic-gate 	 * callback handler after flagging the transaction as done.  If the
7837c478bd9Sstevel@tonic-gate 	 * message is sequenced, start a timer to bound the wait for the first
7847c478bd9Sstevel@tonic-gate 	 * data packet of the response.
7857c478bd9Sstevel@tonic-gate 	 */
7867c478bd9Sstevel@tonic-gate 	if (msgimplp->im_flags & IBMF_MSG_FLAGS_SEQUENCED) {
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
7897c478bd9Sstevel@tonic-gate 		    ibmf_i_do_send_compl, IBMF_TNF_TRACE, "",
7907c478bd9Sstevel@tonic-gate 		    "ibmf_i_do_send_compl(): %s msgp = %p\n", tnf_string, msg,
7917c478bd9Sstevel@tonic-gate 		    "Sequenced transaction, setting response timer",
7927c478bd9Sstevel@tonic-gate 		    tnf_opaque, msg, msgimplp);
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 		/*
7957c478bd9Sstevel@tonic-gate 		 * Check if the send completion already occured,
7967c478bd9Sstevel@tonic-gate 		 * which could imply that this is a send completion
7977c478bd9Sstevel@tonic-gate 		 * for some previous transaction that has come in very late.
7987c478bd9Sstevel@tonic-gate 		 * In this case exit here.
7997c478bd9Sstevel@tonic-gate 		 */
8007c478bd9Sstevel@tonic-gate 		if (msgimplp->im_trans_state_flags  &
8017c478bd9Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_SEND_DONE) {
8027c478bd9Sstevel@tonic-gate 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
8037c478bd9Sstevel@tonic-gate 			    ibmf_i_do_send_compl_end, IBMF_TNF_TRACE, "",
8047c478bd9Sstevel@tonic-gate 			    "ibmf_i_do_send_compl() exit, "
8057c478bd9Sstevel@tonic-gate 			    "Duplicate SEND completion\n");
8067c478bd9Sstevel@tonic-gate 			return;
8077c478bd9Sstevel@tonic-gate 		}
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 		/* mark as send_compl happened */
8107c478bd9Sstevel@tonic-gate 		msgimplp->im_trans_state_flags |=
8117c478bd9Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_SEND_DONE;
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 		if (msgimplp->im_trans_state_flags  &
8147c478bd9Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
8157c478bd9Sstevel@tonic-gate 			msgimplp->im_trans_state_flags |=
8167c478bd9Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_DONE;
8177c478bd9Sstevel@tonic-gate 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
8187c478bd9Sstevel@tonic-gate 			    ibmf_i_do_send_compl_end, IBMF_TNF_TRACE, "",
8197c478bd9Sstevel@tonic-gate 			    "ibmf_i_do_send_compl() exit, RECV_DONE\n");
8207c478bd9Sstevel@tonic-gate 			return;
8217c478bd9Sstevel@tonic-gate 		}
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 		/*
8247c478bd9Sstevel@tonic-gate 		 * check if response was received before send
8257c478bd9Sstevel@tonic-gate 		 * completion
8267c478bd9Sstevel@tonic-gate 		 */
8277c478bd9Sstevel@tonic-gate 		if (((msgimplp->im_trans_state_flags &
8287c478bd9Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_DONE) == 0) &&
8297c478bd9Sstevel@tonic-gate 		    ((msgimplp->im_trans_state_flags &
8307c478bd9Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_RECV_ACTIVE) == 0)) {
8317c478bd9Sstevel@tonic-gate 			/* set timer for first packet of response */
8327c478bd9Sstevel@tonic-gate 			ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp,
8337c478bd9Sstevel@tonic-gate 			    IBMF_RESP_TIMER);
8347c478bd9Sstevel@tonic-gate 		}
8357c478bd9Sstevel@tonic-gate 	} else {
8367c478bd9Sstevel@tonic-gate 		msgimplp->im_msg_status = IBMF_SUCCESS;
837d0141297Ssandipb 		msgimplp->im_trans_state_flags |=
838d0141297Ssandipb 		    IBMF_TRANS_STATE_FLAG_SEND_DONE;
8397c478bd9Sstevel@tonic-gate 		msgimplp->im_trans_state_flags |= IBMF_TRANS_STATE_FLAG_DONE;
8407c478bd9Sstevel@tonic-gate 	}
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_do_send_compl_end,
8437c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_do_send_compl() exit\n");
8447c478bd9Sstevel@tonic-gate }
845