xref: /onnv-gate/usr/src/uts/common/io/ib/mgt/ibmf/ibmf_send.c (revision 268:ff68965f3743)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * This file implements the MAD send logic in IBMF.
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <sys/ib/mgt/ibmf/ibmf_impl.h>
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #define	IBMF_SEND_WR_ID_TO_ADDR(id, ptr)		\
360Sstevel@tonic-gate 	(ptr) = (void *)(uintptr_t)(id)
370Sstevel@tonic-gate 
380Sstevel@tonic-gate extern int ibmf_trace_level;
390Sstevel@tonic-gate 
400Sstevel@tonic-gate static void ibmf_i_do_send_cb(void *taskq_arg);
410Sstevel@tonic-gate static void ibmf_i_do_send_compl(ibmf_handle_t ibmf_handle,
420Sstevel@tonic-gate     ibmf_msg_impl_t *msgimplp, ibmf_send_wqe_t *send_wqep);
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * ibmf_i_issue_pkt():
460Sstevel@tonic-gate  *	Post an IB packet on the specified QP's send queue
470Sstevel@tonic-gate  */
480Sstevel@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)490Sstevel@tonic-gate ibmf_i_issue_pkt(ibmf_client_t *clientp, ibmf_msg_impl_t *msgimplp,
500Sstevel@tonic-gate     ibmf_qp_handle_t ibmf_qp_handle, ibmf_send_wqe_t *send_wqep)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate 	int			ret;
530Sstevel@tonic-gate 	ibt_status_t		status;
540Sstevel@tonic-gate 	ibt_wr_ds_t		sgl[1];
550Sstevel@tonic-gate 	ibt_qp_hdl_t		ibt_qp_handle;
560Sstevel@tonic-gate 
570Sstevel@tonic-gate 	_NOTE(ASSUMING_PROTECTED(*send_wqep))
580Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*send_wqep))
590Sstevel@tonic-gate 
600Sstevel@tonic-gate 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
610Sstevel@tonic-gate 	    ibmf_i_issue_pkt_start, IBMF_TNF_TRACE, "",
620Sstevel@tonic-gate 	    "ibmf_i_issue_pkt() enter, clientp = %p, msg = %p, "
630Sstevel@tonic-gate 	    "qp_hdl = %p,  swqep = %p\n", tnf_opaque, clientp, clientp,
640Sstevel@tonic-gate 	    tnf_opaque, msg, msgimplp, tnf_opaque, ibmf_qp_handle,
650Sstevel@tonic-gate 	    ibmf_qp_handle, tnf_opaque, send_wqep, send_wqep);
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
680Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&clientp->ic_mutex));
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	/*
710Sstevel@tonic-gate 	 * if the qp handle provided in ibmf_send_pkt()
720Sstevel@tonic-gate 	 * is not the default qp handle for this client,
730Sstevel@tonic-gate 	 * then the wqe must be sent on this qp,
740Sstevel@tonic-gate 	 * else use the default qp handle set up during ibmf_register()
750Sstevel@tonic-gate 	 */
760Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
770Sstevel@tonic-gate 		ibt_qp_handle = clientp->ic_qp->iq_qp_handle;
780Sstevel@tonic-gate 	} else {
790Sstevel@tonic-gate 		ibt_qp_handle =
800Sstevel@tonic-gate 		    ((ibmf_alt_qp_t *)ibmf_qp_handle)->isq_qp_handle;
810Sstevel@tonic-gate 	}
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	/* initialize the send WQE */
840Sstevel@tonic-gate 	ibmf_i_init_send_wqe(clientp, msgimplp, sgl, send_wqep,
850Sstevel@tonic-gate 	    msgimplp->im_ud_dest, ibt_qp_handle, ibmf_qp_handle);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*send_wqep))
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	/*
900Sstevel@tonic-gate 	 * Issue the wqe to the transport.
910Sstevel@tonic-gate 	 * NOTE: ibt_post_send() will not block, so, it is ok
920Sstevel@tonic-gate 	 * to hold the msgimpl mutex across this call.
930Sstevel@tonic-gate 	 */
940Sstevel@tonic-gate 	status = ibt_post_send(send_wqep->send_qp_handle, &send_wqep->send_wr,
950Sstevel@tonic-gate 	    1, NULL);
960Sstevel@tonic-gate 	if (status != IBT_SUCCESS) {
970Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
980Sstevel@tonic-gate 		IBMF_ADD32_KSTATS(clientp, send_pkt_failed, 1);
990Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
1000Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1010Sstevel@tonic-gate 		    ibmf_i_issue_pkt_err, IBMF_TNF_TRACE, "",
1020Sstevel@tonic-gate 		    "ibmf_i_issue_pkt(): %s, status = %d\n",
1030Sstevel@tonic-gate 		    tnf_string, msg, "post send failure",
1040Sstevel@tonic-gate 		    tnf_uint, ibt_status, status);
1050Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_issue_pkt_end,
1060Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_i_issue_pkt(() exit\n");
1070Sstevel@tonic-gate 		return (IBMF_TRANSPORT_FAILURE);
1080Sstevel@tonic-gate 	}
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	ret = IBMF_SUCCESS;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	/* bump the number of active sends */
1130Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1140Sstevel@tonic-gate 		mutex_enter(&clientp->ic_mutex);
1150Sstevel@tonic-gate 		clientp->ic_sends_active++;
1160Sstevel@tonic-gate 		mutex_exit(&clientp->ic_mutex);
1170Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
1180Sstevel@tonic-gate 		IBMF_ADD32_KSTATS(clientp, sends_active, 1);
1190Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
1200Sstevel@tonic-gate 	} else {
1210Sstevel@tonic-gate 		ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
1220Sstevel@tonic-gate 		mutex_enter(&qpp->isq_mutex);
1230Sstevel@tonic-gate 		qpp->isq_sends_active++;
1240Sstevel@tonic-gate 		mutex_exit(&qpp->isq_mutex);
1250Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
1260Sstevel@tonic-gate 		IBMF_ADD32_KSTATS(clientp, sends_active, 1);
1270Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_issue_pkt_end,
1310Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_issue_pkt() exit\n");
1320Sstevel@tonic-gate 	return (ret);
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate /*
1360Sstevel@tonic-gate  * ibmf_i_send_pkt()
1370Sstevel@tonic-gate  *	Send an IB packet after allocating send resources
1380Sstevel@tonic-gate  */
1390Sstevel@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)1400Sstevel@tonic-gate ibmf_i_send_pkt(ibmf_client_t *clientp, ibmf_qp_handle_t ibmf_qp_handle,
1410Sstevel@tonic-gate     ibmf_msg_impl_t *msgimplp, int block)
1420Sstevel@tonic-gate {
1430Sstevel@tonic-gate 	ibmf_send_wqe_t	*send_wqep;
1440Sstevel@tonic-gate 	int		status;
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_pkt_start,
1470Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "",
1480Sstevel@tonic-gate 	    "ibmf_i_send_pkt(): clientp = 0x%p, qp_hdl = 0x%p, "
1490Sstevel@tonic-gate 	    "msgp = 0x%p, block = %d\n", tnf_opaque, clientp, clientp,
1500Sstevel@tonic-gate 	    tnf_opaque, qp_hdl, ibmf_qp_handle, tnf_opaque, msg, msgimplp,
1510Sstevel@tonic-gate 	    tnf_uint, block, block);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*send_wqep))
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	/*
1580Sstevel@tonic-gate 	 * Reset send_done to indicate we have not received the completion
1590Sstevel@tonic-gate 	 * for this send yet.
1600Sstevel@tonic-gate 	 */
1610Sstevel@tonic-gate 	msgimplp->im_trans_state_flags &= ~IBMF_TRANS_STATE_FLAG_SEND_DONE;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	/*
1640Sstevel@tonic-gate 	 * Allocate resources needed to send a UD packet including the
1650Sstevel@tonic-gate 	 * send WQE context
1660Sstevel@tonic-gate 	 */
1670Sstevel@tonic-gate 	status = ibmf_i_alloc_send_resources(clientp->ic_myci,
1680Sstevel@tonic-gate 	    msgimplp, block, &send_wqep);
1690Sstevel@tonic-gate 	if (status != IBMF_SUCCESS) {
1700Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_send_pkt_err,
1710Sstevel@tonic-gate 		    IBMF_TNF_ERROR, "", "ibmf_i_send_pkt(): %s, status = %d\n",
1720Sstevel@tonic-gate 		    tnf_string, msg, "unable to allocate send resources",
1730Sstevel@tonic-gate 		    tnf_uint, status, status);
1740Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_send_pkt_end,
1750Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_i_send_pkt() exit\n");
1760Sstevel@tonic-gate 		return (status);
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	/* Set the segment number in the send WQE context */
1800Sstevel@tonic-gate 	if (msgimplp->im_flags & IBMF_MSG_FLAGS_SEND_RMPP)
1810Sstevel@tonic-gate 		send_wqep->send_rmpp_segment = msgimplp->im_rmpp_ctx.rmpp_ns;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*send_wqep))
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	/*
1860Sstevel@tonic-gate 	 * Increment the count of pending send completions.
1870Sstevel@tonic-gate 	 * Only when this count is zero should the client be notified
1880Sstevel@tonic-gate 	 * of completion of the transaction.
1890Sstevel@tonic-gate 	 */
1900Sstevel@tonic-gate 	msgimplp->im_pending_send_compls += 1;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	/* Send the packet */
1930Sstevel@tonic-gate 	status = ibmf_i_issue_pkt(clientp, msgimplp, ibmf_qp_handle, send_wqep);
1940Sstevel@tonic-gate 	if (status != IBMF_SUCCESS) {
1950Sstevel@tonic-gate 		ibmf_i_free_send_resources(clientp->ic_myci, msgimplp,
1960Sstevel@tonic-gate 		    send_wqep);
1970Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_i_send_pkt_err,
1980Sstevel@tonic-gate 		    IBMF_TNF_ERROR, "", "ibmf_i_send_pkt(): %s, status = %d\n",
1990Sstevel@tonic-gate 		    tnf_string, msg, "unable to issue packet",
2000Sstevel@tonic-gate 		    tnf_uint, status, status);
2010Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_send_pkt_end,
2020Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_i_send_pkt() exit\n");
2030Sstevel@tonic-gate 		return (status);
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_send_pkt_end,
2070Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_send_pkt() exit, status = %d\n",
2080Sstevel@tonic-gate 	    tnf_uint, status, status);
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	return (IBMF_SUCCESS);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate  * ibmf_i_send_single_pkt():
2150Sstevel@tonic-gate  *	Send a single IB packet.  Only used to send non-RMPP packets.
2160Sstevel@tonic-gate  */
2170Sstevel@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)2180Sstevel@tonic-gate ibmf_i_send_single_pkt(ibmf_client_t *clientp, ibmf_qp_handle_t ibmf_qp_handle,
2190Sstevel@tonic-gate     ibmf_msg_impl_t *msgimplp, int block)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	int	status;
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_send_single_pkt_start,
2240Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "",
2250Sstevel@tonic-gate 	    "ibmf_i_send_single_pkt(): clientp = 0x%p, qp_hdl = 0x%p, "
2260Sstevel@tonic-gate 	    "msgp = 0x%p, block = %d\n", tnf_opaque, clientp, clientp,
2270Sstevel@tonic-gate 	    tnf_opaque, qp_hdl, ibmf_qp_handle, tnf_opaque, msg, msgimplp,
2280Sstevel@tonic-gate 	    tnf_uint, block, block);
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	status = ibmf_i_send_pkt(clientp, ibmf_qp_handle, msgimplp, block);
2330Sstevel@tonic-gate 	if (status != IBMF_SUCCESS) {
2340Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2350Sstevel@tonic-gate 		    ibmf_i_send_single_pkt_err, IBMF_TNF_ERROR, "",
2360Sstevel@tonic-gate 		    "ibmf_i_send_single_pkt(): %s, msgp = 0x%p\n",
2370Sstevel@tonic-gate 		    tnf_string, msg, "unable to send packet",
2380Sstevel@tonic-gate 		    tnf_uint, status, status);
2390Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2400Sstevel@tonic-gate 		    ibmf_i_send_single_pkt_end, IBMF_TNF_TRACE, "",
2410Sstevel@tonic-gate 		    "ibmf_i_send_single_pkt() exit\n");
2420Sstevel@tonic-gate 		return (status);
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_send_single_pkt_end,
2460Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_send_single_pkt() exit\n");
2470Sstevel@tonic-gate 	return (IBMF_SUCCESS);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate  * ibmf_i_handle_send_completion():
2520Sstevel@tonic-gate  *	Process the WQE from the SQ identified in the work completion entry.
2530Sstevel@tonic-gate  */
2540Sstevel@tonic-gate /* ARGSUSED */
2550Sstevel@tonic-gate void
ibmf_i_handle_send_completion(ibmf_ci_t * cip,ibt_wc_t * wcp)2560Sstevel@tonic-gate ibmf_i_handle_send_completion(ibmf_ci_t *cip, ibt_wc_t *wcp)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate 	ibmf_client_t		*clientp, *cclientp;
2590Sstevel@tonic-gate 	ibmf_send_wqe_t		*send_wqep;
2600Sstevel@tonic-gate 	ibmf_qp_handle_t	ibmf_qp_handle;
2610Sstevel@tonic-gate 	ibmf_alt_qp_t		*qpp;
2620Sstevel@tonic-gate 	int			ret;
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
2650Sstevel@tonic-gate 	    ibmf_i_handle_send_completion_start, IBMF_TNF_TRACE, "",
2660Sstevel@tonic-gate 	    "ibmf_i_handle_send_completion() enter, cip = %p, wcp = %p\n",
2670Sstevel@tonic-gate 	    tnf_opaque, cip, cip, tnf_opaque, wcp, wcp);
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*send_wqep))
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	ASSERT(wcp->wc_id != NULL);
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	ASSERT(IBMF_IS_SEND_WR_ID(wcp->wc_id));
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	/* get the IBMF send WQE context */
2760Sstevel@tonic-gate 	IBMF_SEND_WR_ID_TO_ADDR(wcp->wc_id, send_wqep);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	ASSERT(send_wqep != NULL);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	/* get the client context */
2810Sstevel@tonic-gate 	cclientp =  clientp = send_wqep->send_client;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	/* Check if this is a completion for a BUSY MAD sent by IBMF */
2840Sstevel@tonic-gate 	if (clientp == NULL) {
2850Sstevel@tonic-gate 		ibmf_msg_impl_t		*msgimplp;
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L3,
2880Sstevel@tonic-gate 		    ibmf_i_handle_send_completion, IBMF_TNF_TRACE, "",
2890Sstevel@tonic-gate 		    "ibmf_i_handle_send_completion(): NULL client\n");
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		msgimplp = send_wqep->send_msg;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 		/*
2940Sstevel@tonic-gate 		 * Deregister registered memory and free it, and
2950Sstevel@tonic-gate 		 * free up the send WQE context
2960Sstevel@tonic-gate 		 */
2970Sstevel@tonic-gate 		(void) ibt_deregister_mr(cip->ci_ci_handle,
2980Sstevel@tonic-gate 		    send_wqep->send_mem_hdl);
2990Sstevel@tonic-gate 		kmem_free(send_wqep->send_mem, IBMF_MEM_PER_WQE);
3000Sstevel@tonic-gate 		kmem_free(send_wqep, sizeof (ibmf_send_wqe_t));
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 		/* Free up the message context */
3030Sstevel@tonic-gate 		ibmf_i_put_ud_dest(cip, msgimplp->im_ibmf_ud_dest);
3040Sstevel@tonic-gate 		ibmf_i_clean_ud_dest_list(cip, B_FALSE);
3050Sstevel@tonic-gate 		kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
3060Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3070Sstevel@tonic-gate 		    ibmf_i_handle_send_completion_end, IBMF_TNF_TRACE, "",
3080Sstevel@tonic-gate 		    "ibmf_i_handle_send_completion() exit\n");
3090Sstevel@tonic-gate 		return;
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	/* get the QP handle */
3130Sstevel@tonic-gate 	ibmf_qp_handle = send_wqep->send_ibmf_qp_handle;
3140Sstevel@tonic-gate 	qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	ASSERT(clientp != NULL);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	/* decrement the number of active sends */
3190Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
3200Sstevel@tonic-gate 		mutex_enter(&clientp->ic_mutex);
3210Sstevel@tonic-gate 		clientp->ic_sends_active--;
3220Sstevel@tonic-gate 		mutex_exit(&clientp->ic_mutex);
3230Sstevel@tonic-gate 	} else {
3240Sstevel@tonic-gate 		mutex_enter(&qpp->isq_mutex);
3250Sstevel@tonic-gate 		qpp->isq_sends_active--;
3260Sstevel@tonic-gate 		mutex_exit(&qpp->isq_mutex);
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	mutex_enter(&clientp->ic_kstat_mutex);
3300Sstevel@tonic-gate 	IBMF_SUB32_KSTATS(clientp, sends_active, 1);
3310Sstevel@tonic-gate 	mutex_exit(&clientp->ic_kstat_mutex);
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	send_wqep->send_status = ibmf_i_ibt_wc_to_ibmf_status(wcp->wc_status);
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	/*
3360Sstevel@tonic-gate 	 * issue the callback using taskq. If no taskq or if the
3370Sstevel@tonic-gate 	 * dispatch fails, we do the send processing in the callback context
3380Sstevel@tonic-gate 	 * which is the interrupt context
3390Sstevel@tonic-gate 	 */
3400Sstevel@tonic-gate 	if (cclientp->ic_send_taskq == NULL) {
3410Sstevel@tonic-gate 		/* Do the processing in callback context */
3420Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
3430Sstevel@tonic-gate 		IBMF_ADD32_KSTATS(clientp, send_cb_active, 1);
3440Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
3450Sstevel@tonic-gate 		ibmf_i_do_send_cb((void *)send_wqep);
3460Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
3470Sstevel@tonic-gate 		IBMF_SUB32_KSTATS(clientp, send_cb_active, 1);
3480Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
3490Sstevel@tonic-gate 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
3500Sstevel@tonic-gate 		    ibmf_i_handle_send_err, IBMF_TNF_ERROR, "",
3510Sstevel@tonic-gate 		    "ibmf_i_handle_send_completion(): %s\n",
3520Sstevel@tonic-gate 		    tnf_string, msg, "ci_send_taskq == NULL");
3530Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3540Sstevel@tonic-gate 		    ibmf_i_handle_send_completion_end, IBMF_TNF_TRACE, "",
3550Sstevel@tonic-gate 		    "ibmf_i_handle_send_completion() exit\n");
3560Sstevel@tonic-gate 		return;
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	mutex_enter(&clientp->ic_kstat_mutex);
3600Sstevel@tonic-gate 	IBMF_ADD32_KSTATS(clientp, send_cb_active, 1);
3610Sstevel@tonic-gate 	mutex_exit(&clientp->ic_kstat_mutex);
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	/* Use taskq for processing if the IBMF_REG_FLAG_NO_OFFLOAD isn't set */
3640Sstevel@tonic-gate 	if ((clientp->ic_reg_flags & IBMF_REG_FLAG_NO_OFFLOAD) == 0) {
3650Sstevel@tonic-gate 		ret = taskq_dispatch(cclientp->ic_send_taskq, ibmf_i_do_send_cb,
3660Sstevel@tonic-gate 		    send_wqep, TQ_NOSLEEP);
3670Sstevel@tonic-gate 		if (ret == 0) {
3680Sstevel@tonic-gate 			IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
3690Sstevel@tonic-gate 			    ibmf_i_handle_send_err, IBMF_TNF_ERROR, "",
3700Sstevel@tonic-gate 			    "ibmf_i_handle_send_completion(): %s\n",
3710Sstevel@tonic-gate 			    tnf_string, msg, "send: dispatch failed");
3720Sstevel@tonic-gate 			ibmf_i_do_send_cb((void *)send_wqep);
3730Sstevel@tonic-gate 		}
3740Sstevel@tonic-gate 	} else {
3750Sstevel@tonic-gate 		ibmf_i_do_send_cb((void *)send_wqep);
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	mutex_enter(&clientp->ic_kstat_mutex);
3790Sstevel@tonic-gate 	IBMF_SUB32_KSTATS(clientp, send_cb_active, 1);
3800Sstevel@tonic-gate 	mutex_exit(&clientp->ic_kstat_mutex);
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*send_wqep))
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3850Sstevel@tonic-gate 	    ibmf_i_handle_send_completion_end, IBMF_TNF_TRACE, "",
3860Sstevel@tonic-gate 	    "ibmf_i_handle_send_completion() exit\n");
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate /*
3900Sstevel@tonic-gate  * ibmf_i_do_send_cb():
3910Sstevel@tonic-gate  *	Do the send completion processing
3920Sstevel@tonic-gate  */
3930Sstevel@tonic-gate static void
ibmf_i_do_send_cb(void * taskq_arg)3940Sstevel@tonic-gate ibmf_i_do_send_cb(void *taskq_arg)
3950Sstevel@tonic-gate {
3960Sstevel@tonic-gate 	ibmf_ci_t		*cip;
3970Sstevel@tonic-gate 	ibmf_msg_impl_t		*msgimplp;
3980Sstevel@tonic-gate 	ibmf_client_t		*clientp;
3990Sstevel@tonic-gate 	ibmf_send_wqe_t		*send_wqep;
4000Sstevel@tonic-gate 	boolean_t		found;
4010Sstevel@tonic-gate 	int			msg_trans_state_flags, msg_flags;
4020Sstevel@tonic-gate 	uint_t			ref_cnt;
4030Sstevel@tonic-gate 	ibmf_qp_handle_t	ibmf_qp_handle;
4040Sstevel@tonic-gate 	struct kmem_cache	*kmem_cachep;
4050Sstevel@tonic-gate 	timeout_id_t		msg_rp_unset_id, msg_tr_unset_id;
4060Sstevel@tonic-gate 	timeout_id_t		msg_rp_set_id, msg_tr_set_id;
4070Sstevel@tonic-gate 	ibmf_alt_qp_t		*altqp;
4080Sstevel@tonic-gate 	boolean_t		inc_refcnt;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	send_wqep = taskq_arg;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
4130Sstevel@tonic-gate 	    ibmf_i_do_send_cb_start, IBMF_TNF_TRACE, "",
4140Sstevel@tonic-gate 	    "ibmf_i_do_send_cb() enter, send_wqep = %p\n",
4150Sstevel@tonic-gate 	    tnf_opaque, send_wqep, send_wqep);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	clientp = send_wqep->send_client;
4180Sstevel@tonic-gate 	cip = clientp->ic_myci;
4190Sstevel@tonic-gate 	msgimplp = send_wqep->send_msg;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	/* get the QP handle */
4220Sstevel@tonic-gate 	ibmf_qp_handle = send_wqep->send_ibmf_qp_handle;
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	/* Get the WQE kmem cache pointer based on the QP type */
4250Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT)
4260Sstevel@tonic-gate 		kmem_cachep = cip->ci_send_wqes_cache;
4270Sstevel@tonic-gate 	else {
4280Sstevel@tonic-gate 		altqp = (ibmf_alt_qp_t *)ibmf_qp_handle;
4290Sstevel@tonic-gate 		kmem_cachep = altqp->isq_send_wqes_cache;
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	/* Look for a message in the client's message list */
4330Sstevel@tonic-gate 	inc_refcnt = B_TRUE;
4340Sstevel@tonic-gate 	found = ibmf_i_find_msg_client(clientp, msgimplp, inc_refcnt);
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	/*
4370Sstevel@tonic-gate 	 * If the message context was not found, then it's likely
4380Sstevel@tonic-gate 	 * been freed up. So, do nothing in this timeout handler
4390Sstevel@tonic-gate 	 */
4400Sstevel@tonic-gate 	if (found == B_FALSE) {
4410Sstevel@tonic-gate 		kmem_cache_free(kmem_cachep, send_wqep);
4420Sstevel@tonic-gate 		mutex_enter(&cip->ci_mutex);
4430Sstevel@tonic-gate 		IBMF_SUB32_PORT_KSTATS(cip, send_wqes_alloced, 1);
4440Sstevel@tonic-gate 		mutex_exit(&cip->ci_mutex);
4450Sstevel@tonic-gate 		if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
4460Sstevel@tonic-gate 			mutex_enter(&cip->ci_mutex);
4470Sstevel@tonic-gate 			cip->ci_wqes_alloced--;
4480Sstevel@tonic-gate 			if (cip->ci_wqes_alloced == 0)
4490Sstevel@tonic-gate 				cv_signal(&cip->ci_wqes_cv);
4500Sstevel@tonic-gate 			mutex_exit(&cip->ci_mutex);
4510Sstevel@tonic-gate 		} else {
4520Sstevel@tonic-gate 			mutex_enter(&altqp->isq_mutex);
4530Sstevel@tonic-gate 			altqp->isq_wqes_alloced--;
4540Sstevel@tonic-gate 			if (altqp->isq_wqes_alloced == 0)
4550Sstevel@tonic-gate 				cv_signal(&altqp->isq_wqes_cv);
4560Sstevel@tonic-gate 			mutex_exit(&altqp->isq_mutex);
4570Sstevel@tonic-gate 		}
4580Sstevel@tonic-gate 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
4590Sstevel@tonic-gate 		    ibmf_i_do_send_cb, IBMF_TNF_TRACE, "",
4600Sstevel@tonic-gate 		    "ibmf_i_do_send_cb(): %s\n", tnf_string, msg,
4610Sstevel@tonic-gate 		    "Message not found, return without processing send cb");
4620Sstevel@tonic-gate 		return;
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	/* Grab the message context lock */
4660Sstevel@tonic-gate 	mutex_enter(&msgimplp->im_mutex);
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	/*
4690Sstevel@tonic-gate 	 * Decrement the count of pending send completions for
4700Sstevel@tonic-gate 	 * this transaction
4710Sstevel@tonic-gate 	 */
4720Sstevel@tonic-gate 	msgimplp->im_pending_send_compls -= 1;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	/*
4750Sstevel@tonic-gate 	 * If the pending send completions is not zero, then we must
4760Sstevel@tonic-gate 	 * not attempt to notify the client of a transaction completion
4770Sstevel@tonic-gate 	 * in this instance of the send completion handler. Notification
4780Sstevel@tonic-gate 	 * of transaction completion should be provided only by the
4790Sstevel@tonic-gate 	 * last send completion so that all send completions are accounted
4800Sstevel@tonic-gate 	 * for before the client is notified and subsequently attempts to
4810Sstevel@tonic-gate 	 * reuse the message for an other transaction.
4820Sstevel@tonic-gate 	 * If this is not done, the message may be reused while the
4830Sstevel@tonic-gate 	 * send WR from the old transaction is still active in the QP's WQ.
4840Sstevel@tonic-gate 	 * This could result in an attempt to modify the address handle with
4850Sstevel@tonic-gate 	 * information for the new transaction which could be potentially
4860Sstevel@tonic-gate 	 * incompatible, such as an incorrect port number. Such an
4870Sstevel@tonic-gate 	 * incompatible modification of the address handle of the old
4880Sstevel@tonic-gate 	 * transaction could result in a QP error.
4890Sstevel@tonic-gate 	 */
4900Sstevel@tonic-gate 	if (msgimplp->im_pending_send_compls != 0) {
4910Sstevel@tonic-gate 		IBMF_MSG_DECR_REFCNT(msgimplp);
4920Sstevel@tonic-gate 		mutex_exit(&msgimplp->im_mutex);
4930Sstevel@tonic-gate 		kmem_cache_free(kmem_cachep, send_wqep);
4940Sstevel@tonic-gate 		mutex_enter(&cip->ci_mutex);
4950Sstevel@tonic-gate 		IBMF_SUB32_PORT_KSTATS(cip, send_wqes_alloced, 1);
4960Sstevel@tonic-gate 		mutex_exit(&cip->ci_mutex);
4970Sstevel@tonic-gate 		if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
4980Sstevel@tonic-gate 			mutex_enter(&cip->ci_mutex);
4990Sstevel@tonic-gate 			cip->ci_wqes_alloced--;
5000Sstevel@tonic-gate 			if (cip->ci_wqes_alloced == 0)
5010Sstevel@tonic-gate 				cv_signal(&cip->ci_wqes_cv);
5020Sstevel@tonic-gate 			mutex_exit(&cip->ci_mutex);
5030Sstevel@tonic-gate 		} else {
5040Sstevel@tonic-gate 			mutex_enter(&altqp->isq_mutex);
5050Sstevel@tonic-gate 			altqp->isq_wqes_alloced--;
5060Sstevel@tonic-gate 			if (altqp->isq_wqes_alloced == 0)
5070Sstevel@tonic-gate 				cv_signal(&altqp->isq_wqes_cv);
5080Sstevel@tonic-gate 			mutex_exit(&altqp->isq_mutex);
5090Sstevel@tonic-gate 		}
5100Sstevel@tonic-gate 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
5110Sstevel@tonic-gate 		    ibmf_i_do_send_cb, IBMF_TNF_TRACE, "",
5120Sstevel@tonic-gate 		    "ibmf_i_do_send_cb(): %s\n", tnf_string, msg,
5130Sstevel@tonic-gate 		    "Message found with pending send completions, "
5140Sstevel@tonic-gate 		    "return without processing send cb");
5150Sstevel@tonic-gate 		return;
5160Sstevel@tonic-gate 	}
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	/*
5190Sstevel@tonic-gate 	 * If the message has been marked unitialized or done
5200Sstevel@tonic-gate 	 * release the message mutex and return
5210Sstevel@tonic-gate 	 */
5220Sstevel@tonic-gate 	if ((msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_UNINIT) ||
5230Sstevel@tonic-gate 	    (msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE)) {
5240Sstevel@tonic-gate 		IBMF_MSG_DECR_REFCNT(msgimplp);
5250Sstevel@tonic-gate 		msg_trans_state_flags = msgimplp->im_trans_state_flags;
5260Sstevel@tonic-gate 		msg_flags = msgimplp->im_flags;
5270Sstevel@tonic-gate 		ref_cnt = msgimplp->im_ref_count;
5280Sstevel@tonic-gate 		mutex_exit(&msgimplp->im_mutex);
5290Sstevel@tonic-gate 		/*
5300Sstevel@tonic-gate 		 * This thread may notify the client only if the
5310Sstevel@tonic-gate 		 * transaction is done, the message has been removed
5320Sstevel@tonic-gate 		 * from the client's message list, and the message
5330Sstevel@tonic-gate 		 * reference count is 0.
5340Sstevel@tonic-gate 		 * If the transaction is done, and the message reference
5350Sstevel@tonic-gate 		 * count = 0, there is still a possibility that a
5360Sstevel@tonic-gate 		 * packet could arrive for the message and its reference
5370Sstevel@tonic-gate 		 * count increased if the message is still on the list.
5380Sstevel@tonic-gate 		 * If the message is still on the list, it will be
5390Sstevel@tonic-gate 		 * removed by a call to ibmf_i_client_rem_msg() at
5400Sstevel@tonic-gate 		 * the completion point of the transaction.
5410Sstevel@tonic-gate 		 * So, the reference count should be checked after the
5420Sstevel@tonic-gate 		 * message has been removed.
5430Sstevel@tonic-gate 		 */
5440Sstevel@tonic-gate 		if ((msg_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE) &&
5450Sstevel@tonic-gate 		    !(msg_flags & IBMF_MSG_FLAGS_ON_LIST) &&
5460Sstevel@tonic-gate 		    (ref_cnt == 0)) {
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 			ibmf_i_notify_sequence(clientp, msgimplp, msg_flags);
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 		}
5510Sstevel@tonic-gate 		kmem_cache_free(kmem_cachep, send_wqep);
5520Sstevel@tonic-gate 		mutex_enter(&cip->ci_mutex);
5530Sstevel@tonic-gate 		IBMF_SUB32_PORT_KSTATS(cip, send_wqes_alloced, 1);
5540Sstevel@tonic-gate 		mutex_exit(&cip->ci_mutex);
5550Sstevel@tonic-gate 		if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
5560Sstevel@tonic-gate 			mutex_enter(&cip->ci_mutex);
5570Sstevel@tonic-gate 			cip->ci_wqes_alloced--;
5580Sstevel@tonic-gate 			if (cip->ci_wqes_alloced == 0)
5590Sstevel@tonic-gate 				cv_signal(&cip->ci_wqes_cv);
5600Sstevel@tonic-gate 			mutex_exit(&cip->ci_mutex);
5610Sstevel@tonic-gate 		} else {
5620Sstevel@tonic-gate 			mutex_enter(&altqp->isq_mutex);
5630Sstevel@tonic-gate 			altqp->isq_wqes_alloced--;
5640Sstevel@tonic-gate 			if (altqp->isq_wqes_alloced == 0)
5650Sstevel@tonic-gate 				cv_signal(&altqp->isq_wqes_cv);
5660Sstevel@tonic-gate 			mutex_exit(&altqp->isq_mutex);
5670Sstevel@tonic-gate 		}
5680Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
5690Sstevel@tonic-gate 		    ibmf_i_do_send_cb, IBMF_TNF_TRACE, "",
5700Sstevel@tonic-gate 		    "ibmf_i_do_send_cb(): %s, msg = %p\n", tnf_string, msg,
5710Sstevel@tonic-gate 		    "Message marked for removal, return without processing "
5720Sstevel@tonic-gate 		    "send cb", tnf_opaque, msgimplp, msgimplp);
5730Sstevel@tonic-gate 		return;
5740Sstevel@tonic-gate 	}
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	/* Perform send completion processing of the message context */
5770Sstevel@tonic-gate 	ibmf_i_do_send_compl((ibmf_handle_t)clientp, msgimplp, send_wqep);
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	msg_rp_unset_id = msg_tr_unset_id = msg_rp_set_id = msg_tr_set_id = 0;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	/* Save the message flags before releasing the mutex */
5820Sstevel@tonic-gate 	msg_trans_state_flags = msgimplp->im_trans_state_flags;
5830Sstevel@tonic-gate 	msg_flags = msgimplp->im_flags;
5840Sstevel@tonic-gate 	msg_rp_unset_id = msgimplp->im_rp_unset_timeout_id;
5850Sstevel@tonic-gate 	msg_tr_unset_id = msgimplp->im_tr_unset_timeout_id;
5860Sstevel@tonic-gate 	msgimplp->im_rp_unset_timeout_id = 0;
5870Sstevel@tonic-gate 	msgimplp->im_tr_unset_timeout_id = 0;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	/*
5900Sstevel@tonic-gate 	 * Decrement the message reference count
5910Sstevel@tonic-gate 	 * This count was inceremented when the message was found on the
5920Sstevel@tonic-gate 	 * client's message list
5930Sstevel@tonic-gate 	 */
5940Sstevel@tonic-gate 	IBMF_MSG_DECR_REFCNT(msgimplp);
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	if (msg_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE) {
5970Sstevel@tonic-gate 		if (msgimplp->im_rp_timeout_id != 0) {
5980Sstevel@tonic-gate 			msg_rp_set_id = msgimplp->im_rp_timeout_id;
5990Sstevel@tonic-gate 			msgimplp->im_rp_timeout_id = 0;
6000Sstevel@tonic-gate 		}
6010Sstevel@tonic-gate 		if (msgimplp->im_tr_timeout_id != 0) {
6020Sstevel@tonic-gate 			msg_tr_set_id = msgimplp->im_tr_timeout_id;
6030Sstevel@tonic-gate 			msgimplp->im_tr_timeout_id = 0;
6040Sstevel@tonic-gate 		}
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	mutex_exit(&msgimplp->im_mutex);
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	if (msg_rp_unset_id != 0) {
6100Sstevel@tonic-gate 		(void) untimeout(msg_rp_unset_id);
6110Sstevel@tonic-gate 	}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	if (msg_tr_unset_id != 0) {
6140Sstevel@tonic-gate 		(void) untimeout(msg_tr_unset_id);
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	if (msg_rp_set_id != 0) {
6180Sstevel@tonic-gate 		(void) untimeout(msg_rp_set_id);
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	if (msg_tr_set_id != 0) {
6220Sstevel@tonic-gate 		(void) untimeout(msg_tr_set_id);
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
6260Sstevel@tonic-gate 	    ibmf_i_do_send_cb, IBMF_TNF_TRACE, "",
6270Sstevel@tonic-gate 	    "ibmf_i_do_send_cb(): %s, msg = %p\n",
6280Sstevel@tonic-gate 	    tnf_string, msg, "Send callback done.  Dec ref count",
6290Sstevel@tonic-gate 	    tnf_opaque, msgimplp, msgimplp);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	/*
6320Sstevel@tonic-gate 	 * If the transaction is done, signal the block thread if the
6330Sstevel@tonic-gate 	 * transaction is blocking, or call the client's transaction done
6340Sstevel@tonic-gate 	 * notification callback
6350Sstevel@tonic-gate 	 */
6360Sstevel@tonic-gate 	if (msg_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE) {
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 		/* Remove the message from the client's message list */
6390Sstevel@tonic-gate 		ibmf_i_client_rem_msg(clientp, msgimplp, &ref_cnt);
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 		/*
6420Sstevel@tonic-gate 		 * Notify the client if the message reference count is zero.
6430Sstevel@tonic-gate 		 * At this point, we know that the transaction is done and
6440Sstevel@tonic-gate 		 * the message has been removed from the client's message list.
6450Sstevel@tonic-gate 		 * So, we only need to make sure the reference count is zero
6460Sstevel@tonic-gate 		 * before notifying the client.
6470Sstevel@tonic-gate 		 */
6480Sstevel@tonic-gate 		if (ref_cnt == 0) {
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 			ibmf_i_notify_sequence(clientp, msgimplp, msg_flags);
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 		}
6530Sstevel@tonic-gate 	}
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	kmem_cache_free(kmem_cachep, send_wqep);
6560Sstevel@tonic-gate 	mutex_enter(&cip->ci_mutex);
6570Sstevel@tonic-gate 	IBMF_SUB32_PORT_KSTATS(cip, send_wqes_alloced, 1);
6580Sstevel@tonic-gate 	mutex_exit(&cip->ci_mutex);
6590Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
6600Sstevel@tonic-gate 		mutex_enter(&cip->ci_mutex);
6610Sstevel@tonic-gate 		cip->ci_wqes_alloced--;
6620Sstevel@tonic-gate 		if (cip->ci_wqes_alloced == 0)
6630Sstevel@tonic-gate 			cv_signal(&cip->ci_wqes_cv);
6640Sstevel@tonic-gate 		mutex_exit(&cip->ci_mutex);
6650Sstevel@tonic-gate 	} else {
6660Sstevel@tonic-gate 		mutex_enter(&altqp->isq_mutex);
6670Sstevel@tonic-gate 		altqp->isq_wqes_alloced--;
6680Sstevel@tonic-gate 		if (altqp->isq_wqes_alloced == 0)
6690Sstevel@tonic-gate 			cv_signal(&altqp->isq_wqes_cv);
6700Sstevel@tonic-gate 		mutex_exit(&altqp->isq_mutex);
6710Sstevel@tonic-gate 	}
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
6740Sstevel@tonic-gate 	    ibmf_i_do_send_cb_end, IBMF_TNF_TRACE, "",
6750Sstevel@tonic-gate 	    "ibmf_i_do_send_cb() exit\n");
6760Sstevel@tonic-gate }
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate /*
6790Sstevel@tonic-gate  * ibmf_i_do_send_compl():
6800Sstevel@tonic-gate  *	Determine if the transaction is complete
6810Sstevel@tonic-gate  */
6820Sstevel@tonic-gate /* ARGSUSED */
6830Sstevel@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)6840Sstevel@tonic-gate ibmf_i_do_send_compl(ibmf_handle_t ibmf_handle, ibmf_msg_impl_t *msgimplp,
6850Sstevel@tonic-gate     ibmf_send_wqe_t *send_wqep)
6860Sstevel@tonic-gate {
6870Sstevel@tonic-gate 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_do_send_compl_start,
6880Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_do_send_compl(): ibmf_hdl = 0x%p "
6890Sstevel@tonic-gate 	    "msgp = %p, send_wqep = 0x%p, msg_flags = 0x%x\n",
6900Sstevel@tonic-gate 	    tnf_opaque, ibmf_hdl, ibmf_handle, tnf_opaque, msgimplp, msgimplp,
6910Sstevel@tonic-gate 	    tnf_opaque, send_wqep, send_wqep,
6920Sstevel@tonic-gate 	    tnf_opaque, msg_flags, msgimplp->im_flags);
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	/*
6970Sstevel@tonic-gate 	 * For RMPP transactions, we only care about the final packet of the
6980Sstevel@tonic-gate 	 * transaction.  For others, the code does not need to wait for the send
6990Sstevel@tonic-gate 	 * completion (although bad things can happen if it never occurs).
7000Sstevel@tonic-gate 	 * The final packets of a transaction are sent when the state is either
7010Sstevel@tonic-gate 	 * ABORT or RECEVR_TERMINATE.
7020Sstevel@tonic-gate 	 * Don't mark the transaction as send_done if there are still more
7030Sstevel@tonic-gate 	 * packets to be sent, including doing the second part of a double-sided
7040Sstevel@tonic-gate 	 * transaction.
7050Sstevel@tonic-gate 	 */
7060Sstevel@tonic-gate 	if ((msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) ||
7070Sstevel@tonic-gate 	    (msgimplp->im_flags & IBMF_MSG_FLAGS_SEND_RMPP)) {
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
7100Sstevel@tonic-gate 		    ibmf_i_do_send_compl, IBMF_TNF_TRACE, "",
7110Sstevel@tonic-gate 		    "ibmf_i_do_send_compl(): %s msgp = %p, rmpp_state = 0x%x\n",
7120Sstevel@tonic-gate 		    tnf_string, msg, "Received send callback for RMPP trans",
7130Sstevel@tonic-gate 		    tnf_opaque, msg, msgimplp,
7140Sstevel@tonic-gate 		    tnf_opaque, rmpp_state, msgimplp->im_rmpp_ctx.rmpp_state);
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 		/*
7170Sstevel@tonic-gate 		 * For ABORT state, we should not return control to
7180Sstevel@tonic-gate 		 * the client from the send completion handler.
7190Sstevel@tonic-gate 		 * Control should be returned in the error timeout handler.
7200Sstevel@tonic-gate 		 *
7210Sstevel@tonic-gate 		 * The exception is when the IBMF_TRANS_STATE_FLAG_RECV_DONE
7220Sstevel@tonic-gate 		 * flag has already been set. This flag is set when
7230Sstevel@tonic-gate 		 * ibmf_i_terminate_transaction is called from one of the
7240Sstevel@tonic-gate 		 * three timeout handlers. In this case return control from
7250Sstevel@tonic-gate 		 * here.
7260Sstevel@tonic-gate 		 */
7270Sstevel@tonic-gate 		if (msgimplp->im_rmpp_ctx.rmpp_state == IBMF_RMPP_STATE_ABORT) {
7280Sstevel@tonic-gate 			msgimplp->im_trans_state_flags |=
7290Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_SEND_DONE;
7300Sstevel@tonic-gate 			if (msgimplp->im_trans_state_flags &
7310Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
7320Sstevel@tonic-gate 				msgimplp->im_trans_state_flags |=
7330Sstevel@tonic-gate 				    IBMF_TRANS_STATE_FLAG_DONE;
7340Sstevel@tonic-gate 			}
7350Sstevel@tonic-gate 		}
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 		if ((msgimplp->im_rmpp_ctx.rmpp_state ==
7380Sstevel@tonic-gate 		    IBMF_RMPP_STATE_RECEVR_TERMINATE) ||
7390Sstevel@tonic-gate 		    (msgimplp->im_rmpp_ctx.rmpp_state ==
7400Sstevel@tonic-gate 		    IBMF_RMPP_STATE_DONE)) {
7410Sstevel@tonic-gate 			msgimplp->im_trans_state_flags |=
7420Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_SEND_DONE;
7430Sstevel@tonic-gate 			if (msgimplp->im_trans_state_flags  &
7440Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
7450Sstevel@tonic-gate 				msgimplp->im_trans_state_flags |=
7460Sstevel@tonic-gate 				    IBMF_TRANS_STATE_FLAG_DONE;
7470Sstevel@tonic-gate 			}
7480Sstevel@tonic-gate 		}
7490Sstevel@tonic-gate 
750*268Ssandipb 		/*
751*268Ssandipb 		 * If the transaction is a send-only RMPP, then
752*268Ssandipb 		 * set the SEND_DONE flag on every send completion
753*268Ssandipb 		 * as long as there are no outstanding ones.
754*268Ssandipb 		 * This is needed so that the transaction can return
755*268Ssandipb 		 * in the receive path, where ibmf_i_terminate_transaction
756*268Ssandipb 		 * is called from ibmf_i_rmpp_sender_active_flow,
757*268Ssandipb 		 * after checking if the SEND_DONE flag is set.
758*268Ssandipb 		 * When a new MAD is sent as part of the RMPP transaction,
759*268Ssandipb 		 * the SEND_DONE flag will get reset.
760*268Ssandipb 		 * The RECV_DONE indicates that the last ACK was received.
761*268Ssandipb 		 */
762*268Ssandipb 		if ((msgimplp->im_flags & IBMF_MSG_FLAGS_SEQUENCED) == 0) {
763*268Ssandipb 			if (msgimplp->im_pending_send_compls == 0) {
764*268Ssandipb 				msgimplp->im_trans_state_flags |=
765*268Ssandipb 				    IBMF_TRANS_STATE_FLAG_SEND_DONE;
766*268Ssandipb 				if (msgimplp->im_trans_state_flags  &
767*268Ssandipb 				    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
768*268Ssandipb 					msgimplp->im_trans_state_flags |=
769*268Ssandipb 					    IBMF_TRANS_STATE_FLAG_DONE;
770*268Ssandipb 				}
771*268Ssandipb 			}
772*268Ssandipb 		}
773*268Ssandipb 
7740Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
7750Sstevel@tonic-gate 		    ibmf_i_do_send_compl_end, IBMF_TNF_TRACE, "",
7760Sstevel@tonic-gate 		    "ibmf_i_do_send_compl() exit\n");
7770Sstevel@tonic-gate 		return;
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	/*
7810Sstevel@tonic-gate 	 * Only non-RMPP send completion gets here.
7820Sstevel@tonic-gate 	 * If the send is a single-packet send that does not use RMPP, and if
7830Sstevel@tonic-gate 	 * the transaction is not a sequenced transaction, call the transaction
7840Sstevel@tonic-gate 	 * callback handler after flagging the transaction as done.  If the
7850Sstevel@tonic-gate 	 * message is sequenced, start a timer to bound the wait for the first
7860Sstevel@tonic-gate 	 * data packet of the response.
7870Sstevel@tonic-gate 	 */
7880Sstevel@tonic-gate 	if (msgimplp->im_flags & IBMF_MSG_FLAGS_SEQUENCED) {
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
7910Sstevel@tonic-gate 		    ibmf_i_do_send_compl, IBMF_TNF_TRACE, "",
7920Sstevel@tonic-gate 		    "ibmf_i_do_send_compl(): %s msgp = %p\n", tnf_string, msg,
7930Sstevel@tonic-gate 		    "Sequenced transaction, setting response timer",
7940Sstevel@tonic-gate 		    tnf_opaque, msg, msgimplp);
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 		/*
7970Sstevel@tonic-gate 		 * Check if the send completion already occured,
7980Sstevel@tonic-gate 		 * which could imply that this is a send completion
7990Sstevel@tonic-gate 		 * for some previous transaction that has come in very late.
8000Sstevel@tonic-gate 		 * In this case exit here.
8010Sstevel@tonic-gate 		 */
8020Sstevel@tonic-gate 		if (msgimplp->im_trans_state_flags  &
8030Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_SEND_DONE) {
8040Sstevel@tonic-gate 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
8050Sstevel@tonic-gate 			    ibmf_i_do_send_compl_end, IBMF_TNF_TRACE, "",
8060Sstevel@tonic-gate 			    "ibmf_i_do_send_compl() exit, "
8070Sstevel@tonic-gate 			    "Duplicate SEND completion\n");
8080Sstevel@tonic-gate 			return;
8090Sstevel@tonic-gate 		}
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 		/* mark as send_compl happened */
8120Sstevel@tonic-gate 		msgimplp->im_trans_state_flags |=
8130Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_SEND_DONE;
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 		if (msgimplp->im_trans_state_flags  &
8160Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_RECV_DONE) {
8170Sstevel@tonic-gate 			msgimplp->im_trans_state_flags |=
8180Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_DONE;
8190Sstevel@tonic-gate 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
8200Sstevel@tonic-gate 			    ibmf_i_do_send_compl_end, IBMF_TNF_TRACE, "",
8210Sstevel@tonic-gate 			    "ibmf_i_do_send_compl() exit, RECV_DONE\n");
8220Sstevel@tonic-gate 			return;
8230Sstevel@tonic-gate 		}
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 		/*
8260Sstevel@tonic-gate 		 * check if response was received before send
8270Sstevel@tonic-gate 		 * completion
8280Sstevel@tonic-gate 		 */
8290Sstevel@tonic-gate 		if (((msgimplp->im_trans_state_flags &
8300Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_DONE) == 0) &&
8310Sstevel@tonic-gate 		    ((msgimplp->im_trans_state_flags &
8320Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_RECV_ACTIVE) == 0)) {
8330Sstevel@tonic-gate 			/* set timer for first packet of response */
8340Sstevel@tonic-gate 			ibmf_i_set_timer(ibmf_i_send_timeout, msgimplp,
8350Sstevel@tonic-gate 			    IBMF_RESP_TIMER);
8360Sstevel@tonic-gate 		}
8370Sstevel@tonic-gate 	} else {
8380Sstevel@tonic-gate 		msgimplp->im_msg_status = IBMF_SUCCESS;
839*268Ssandipb 		msgimplp->im_trans_state_flags |=
840*268Ssandipb 		    IBMF_TRANS_STATE_FLAG_SEND_DONE;
8410Sstevel@tonic-gate 		msgimplp->im_trans_state_flags |= IBMF_TRANS_STATE_FLAG_DONE;
8420Sstevel@tonic-gate 	}
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_do_send_compl_end,
8450Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_do_send_compl() exit\n");
8460Sstevel@tonic-gate }
847