xref: /onnv-gate/usr/src/uts/common/io/ib/mgt/ibmf/ibmf_trans.c (revision 12787:45ed97ad3d9f)
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
5*12787SLida.Horn@Oracle.COM  * Common Development and Distribution License (the "License").
6*12787SLida.Horn@Oracle.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*12787SLida.Horn@Oracle.COM 
220Sstevel@tonic-gate /*
23*12787SLida.Horn@Oracle.COM  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * This file implements the transaction processing logic common to send
280Sstevel@tonic-gate  * and receive transactions in IBMF.
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <sys/ib/mgt/ibmf/ibmf_impl.h>
320Sstevel@tonic-gate 
330Sstevel@tonic-gate extern int ibmf_trace_level;
340Sstevel@tonic-gate 
350Sstevel@tonic-gate /*
360Sstevel@tonic-gate  * ibmf_i_terminate_transaction():
370Sstevel@tonic-gate  *	Do transaction termination processing.
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate void
ibmf_i_terminate_transaction(ibmf_client_t * clientp,ibmf_msg_impl_t * msgimplp,uint32_t status)400Sstevel@tonic-gate ibmf_i_terminate_transaction(ibmf_client_t *clientp, ibmf_msg_impl_t *msgimplp,
410Sstevel@tonic-gate     uint32_t status)
420Sstevel@tonic-gate {
430Sstevel@tonic-gate 
440Sstevel@tonic-gate 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4,
450Sstevel@tonic-gate 	    ibmf_i_terminate_transaction_start, IBMF_TNF_TRACE, "",
460Sstevel@tonic-gate 	    "ibmf_i_terminate_transaction(): clientp = 0x%p, msgp = 0x%p, "
470Sstevel@tonic-gate 	    "status = 0x%x\n", tnf_opaque, clientp, clientp,
480Sstevel@tonic-gate 	    tnf_opaque, msg, msgimplp, tnf_uint, status, status);
490Sstevel@tonic-gate 
500Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
510Sstevel@tonic-gate 
520Sstevel@tonic-gate 	msgimplp->im_msg_status = status;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate 	/*
550Sstevel@tonic-gate 	 * Cancel the transaction timer. timer is probably only active if status
560Sstevel@tonic-gate 	 * was not success and this is a recv operation, but unset_timer() will
570Sstevel@tonic-gate 	 * check.
580Sstevel@tonic-gate 	 */
590Sstevel@tonic-gate 	ibmf_i_unset_timer(msgimplp, IBMF_TRANS_TIMER);
600Sstevel@tonic-gate 
610Sstevel@tonic-gate 	/*
620Sstevel@tonic-gate 	 * For unsolicited messages, do not notify the client
630Sstevel@tonic-gate 	 * if an error was encontered in the transfer.
640Sstevel@tonic-gate 	 * For solicited messages, call the transaction callback
650Sstevel@tonic-gate 	 * provided by the client in the message context.
660Sstevel@tonic-gate 	 */
670Sstevel@tonic-gate 	if (msgimplp->im_unsolicited == B_TRUE) {
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 		msgimplp->im_trans_state_flags |= IBMF_TRANS_STATE_FLAG_DONE;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	} else {
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
740Sstevel@tonic-gate 		    ibmf_i_terminate_transaction, IBMF_TNF_TRACE, "",
750Sstevel@tonic-gate 		    "ibmf_i_terminate_transaction(): %s, "
760Sstevel@tonic-gate 		    "trans_state_flags = 0x%x, msg_flags = 0x%x\n",
770Sstevel@tonic-gate 		    tnf_string, msg, "solicted message callback",
780Sstevel@tonic-gate 		    tnf_opaque, trans_state_flags,
790Sstevel@tonic-gate 		    msgimplp->im_trans_state_flags,
800Sstevel@tonic-gate 		    tnf_opaque, flags, msgimplp->im_flags);
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 		/* mark as recv_compl happened */
830Sstevel@tonic-gate 		msgimplp->im_trans_state_flags |=
840Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_RECV_DONE;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 		/*
87268Ssandipb 		 * Check if last send is done before marking as done.
88268Ssandipb 		 * We should get here for sequenced transactions and
89268Ssandipb 		 * non-sequenced send RMPP transaction.
900Sstevel@tonic-gate 		 */
91268Ssandipb 		if (msgimplp->im_trans_state_flags &
92268Ssandipb 		    IBMF_TRANS_STATE_FLAG_SEND_DONE) {
930Sstevel@tonic-gate 			msgimplp->im_trans_state_flags |=
940Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_DONE;
950Sstevel@tonic-gate 		}
960Sstevel@tonic-gate 	}
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
990Sstevel@tonic-gate 	    ibmf_i_terminate_transaction_end, IBMF_TNF_TRACE, "",
1000Sstevel@tonic-gate 	    "ibmf_i_terminate_transaction() exit\n");
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate /*
1040Sstevel@tonic-gate  * ibmf_i_notify_client():
1050Sstevel@tonic-gate  * 	If the transaction is done, call the appropriate callback
1060Sstevel@tonic-gate  */
1070Sstevel@tonic-gate void
ibmf_i_notify_client(ibmf_msg_impl_t * msgimplp)1080Sstevel@tonic-gate ibmf_i_notify_client(ibmf_msg_impl_t *msgimplp)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate 	ibmf_client_t	*clientp;
1110Sstevel@tonic-gate 	ibmf_msg_cb_t	async_cb;
1120Sstevel@tonic-gate 	void		*async_cb_arg;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_notify_client_start,
1150Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_notify_client(): msgp = 0x%p\n",
1160Sstevel@tonic-gate 	    tnf_opaque, msgimplp, msgimplp);
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	clientp = msgimplp->im_client;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/*
1210Sstevel@tonic-gate 	 * message is removed so no more threads will find message;
1220Sstevel@tonic-gate 	 * wait for any current clients to finish
1230Sstevel@tonic-gate 	 */
1240Sstevel@tonic-gate 	mutex_enter(&msgimplp->im_mutex);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	ASSERT(msgimplp->im_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE);
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	/*
1290Sstevel@tonic-gate 	 * If the message reference count is not zero, then some duplicate
1300Sstevel@tonic-gate 	 * MAD has arrived for this message. The thread processing the MAD
1310Sstevel@tonic-gate 	 * found the message on the client's list before this thread was able
1320Sstevel@tonic-gate 	 * to remove the message from the list. Since, we should not notify
1330Sstevel@tonic-gate 	 * the client of the transaction completion until all the threads
1340Sstevel@tonic-gate 	 * working on this message have completed (we don't want the client
1350Sstevel@tonic-gate 	 * to free the message while a thread is working on it), we let one
1360Sstevel@tonic-gate 	 * of the other threads notify the client of the completion once
1370Sstevel@tonic-gate 	 * the message reference count is zero.
1380Sstevel@tonic-gate 	 */
1390Sstevel@tonic-gate 	if (msgimplp->im_ref_count != 0) {
1400Sstevel@tonic-gate 		mutex_exit(&msgimplp->im_mutex);
1410Sstevel@tonic-gate 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1420Sstevel@tonic-gate 		    ibmf_i_notify_client_err, IBMF_TNF_TRACE,
1430Sstevel@tonic-gate 		    "", "ibmf_i_notify_client(): %s\n",
1440Sstevel@tonic-gate 		    tnf_string, msg, "message reference count != 0");
1450Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1460Sstevel@tonic-gate 		    ibmf_i_notify_client_end, IBMF_TNF_TRACE, "",
1470Sstevel@tonic-gate 		    "ibmf_i_notify_client() exit\n");
1480Sstevel@tonic-gate 		return;
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	mutex_exit(&msgimplp->im_mutex);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	/*
1540Sstevel@tonic-gate 	 * Free up the UD dest resource so it is not tied down by
1550Sstevel@tonic-gate 	 * the message in case the message is not freed immediately.
1560Sstevel@tonic-gate 	 * Clean up the UD dest list as well so that excess UD dest
1570Sstevel@tonic-gate 	 * resources are returned to the CI.
1580Sstevel@tonic-gate 	 */
1590Sstevel@tonic-gate 	if (msgimplp->im_ibmf_ud_dest != NULL) {
1600Sstevel@tonic-gate 		ibmf_i_free_ud_dest(clientp, msgimplp);
1610Sstevel@tonic-gate 		ibmf_i_clean_ud_dest_list(clientp->ic_myci, B_FALSE);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgimplp))
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	if (msgimplp->im_unsolicited == B_TRUE) {
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 		/*
1690Sstevel@tonic-gate 		 * Do nothing if error status
1700Sstevel@tonic-gate 		 */
1710Sstevel@tonic-gate 		if (msgimplp->im_msg_status != IBMF_SUCCESS) {
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 			if (msgimplp->im_qp_hdl == IBMF_QP_HANDLE_DEFAULT) {
1740Sstevel@tonic-gate 				mutex_enter(&clientp->ic_mutex);
1750Sstevel@tonic-gate 				IBMF_RECV_CB_CLEANUP(clientp);
1760Sstevel@tonic-gate 				mutex_exit(&clientp->ic_mutex);
1770Sstevel@tonic-gate 			} else {
1780Sstevel@tonic-gate 				ibmf_alt_qp_t *qpp =
1790Sstevel@tonic-gate 				    (ibmf_alt_qp_t *)msgimplp->im_qp_hdl;
1800Sstevel@tonic-gate 				mutex_enter(&qpp->isq_mutex);
1810Sstevel@tonic-gate 				IBMF_ALT_RECV_CB_CLEANUP(qpp);
1820Sstevel@tonic-gate 				mutex_exit(&qpp->isq_mutex);
1830Sstevel@tonic-gate 			}
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
1860Sstevel@tonic-gate 			    ibmf_i_notify_client_err, IBMF_TNF_ERROR, "",
1870Sstevel@tonic-gate 			    "ibmf_i_notify_client(): %s, status = %d\n",
1880Sstevel@tonic-gate 			    tnf_string, msg, "message status not success",
1890Sstevel@tonic-gate 			    tnf_opaque, status, msgimplp->im_msg_status);
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 			ibmf_i_free_msg(msgimplp);
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1940Sstevel@tonic-gate 			    ibmf_i_notify_client_end, IBMF_TNF_TRACE, "",
1950Sstevel@tonic-gate 			    "ibmf_i_notify_client() exit\n");
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 			return;
1980Sstevel@tonic-gate 		}
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 		/*
2010Sstevel@tonic-gate 		 * Check to see if
202*12787SLida.Horn@Oracle.COM 		 * a callback has been registered with the client
2030Sstevel@tonic-gate 		 * for this unsolicited message.
2040Sstevel@tonic-gate 		 * If one has been registered, up the recvs active
2050Sstevel@tonic-gate 		 * count to get the teardown routine to wait until
2060Sstevel@tonic-gate 		 * this callback is complete.
2070Sstevel@tonic-gate 		 */
2080Sstevel@tonic-gate 		if (msgimplp->im_qp_hdl == IBMF_QP_HANDLE_DEFAULT) {
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 			mutex_enter(&clientp->ic_mutex);
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 			if ((clientp->ic_recv_cb == NULL) ||
2130Sstevel@tonic-gate 			    (clientp->ic_flags & IBMF_CLIENT_TEAR_DOWN_CB)) {
2140Sstevel@tonic-gate 				IBMF_RECV_CB_CLEANUP(clientp);
2150Sstevel@tonic-gate 				mutex_exit(&clientp->ic_mutex);
2160Sstevel@tonic-gate 				ibmf_i_free_msg(msgimplp);
2170Sstevel@tonic-gate 				IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2180Sstevel@tonic-gate 				    ibmf_i_notify_client_err, IBMF_TNF_ERROR,
2190Sstevel@tonic-gate 				    "", "ibmf_i_notify_client(): %s\n",
2200Sstevel@tonic-gate 				    tnf_string, msg,
2210Sstevel@tonic-gate 				    "ibmf_tear_down_recv_cb already occurred");
2220Sstevel@tonic-gate 				IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2230Sstevel@tonic-gate 				    ibmf_i_notify_client_end,
2240Sstevel@tonic-gate 				    IBMF_TNF_TRACE, "",
2250Sstevel@tonic-gate 				    "ibmf_i_notify_client() exit\n");
2260Sstevel@tonic-gate 				return;
2270Sstevel@tonic-gate 			}
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 			clientp->ic_msgs_alloced++;
2300Sstevel@tonic-gate 			mutex_enter(&clientp->ic_kstat_mutex);
2310Sstevel@tonic-gate 			IBMF_ADD32_KSTATS(clientp, msgs_alloced, 1);
2320Sstevel@tonic-gate 			mutex_exit(&clientp->ic_kstat_mutex);
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 			async_cb = clientp->ic_recv_cb;
2350Sstevel@tonic-gate 			async_cb_arg = clientp->ic_recv_cb_arg;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 			mutex_exit(&clientp->ic_mutex);
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 			async_cb((ibmf_handle_t)clientp, (ibmf_msg_t *)msgimplp,
2400Sstevel@tonic-gate 			    async_cb_arg);
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 			mutex_enter(&clientp->ic_mutex);
2430Sstevel@tonic-gate 			IBMF_RECV_CB_CLEANUP(clientp);
2440Sstevel@tonic-gate 			mutex_exit(&clientp->ic_mutex);
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 		} else {
2470Sstevel@tonic-gate 			ibmf_alt_qp_t *qpp =
2480Sstevel@tonic-gate 			    (ibmf_alt_qp_t *)msgimplp->im_qp_hdl;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 			mutex_enter(&qpp->isq_mutex);
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 			if ((qpp->isq_recv_cb == NULL) ||
2530Sstevel@tonic-gate 			    (qpp->isq_flags & IBMF_CLIENT_TEAR_DOWN_CB)) {
2540Sstevel@tonic-gate 				IBMF_ALT_RECV_CB_CLEANUP(qpp);
2550Sstevel@tonic-gate 				mutex_exit(&qpp->isq_mutex);
2560Sstevel@tonic-gate 				ibmf_i_free_msg(msgimplp);
2570Sstevel@tonic-gate 				IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2580Sstevel@tonic-gate 				    ibmf_i_notify_client_err, IBMF_TNF_ERROR,
2590Sstevel@tonic-gate 				    "", "ibmf_i_notify_client(): %s\n",
2600Sstevel@tonic-gate 				    tnf_string, msg,
2610Sstevel@tonic-gate 				    "ibmf_tear_down_recv_cb already occurred");
2620Sstevel@tonic-gate 				IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2630Sstevel@tonic-gate 				    ibmf_i_notify_client_end,
2640Sstevel@tonic-gate 				    IBMF_TNF_TRACE, "",
2650Sstevel@tonic-gate 				    "ibmf_i_notify_client() exit\n");
2660Sstevel@tonic-gate 				return;
2670Sstevel@tonic-gate 			}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 			async_cb = qpp->isq_recv_cb;
2700Sstevel@tonic-gate 			async_cb_arg = qpp->isq_recv_cb_arg;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 			mutex_exit(&qpp->isq_mutex);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 			mutex_enter(&clientp->ic_mutex);
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 			clientp->ic_msgs_alloced++;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 			mutex_exit(&clientp->ic_mutex);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 			mutex_enter(&clientp->ic_kstat_mutex);
2810Sstevel@tonic-gate 			IBMF_ADD32_KSTATS(clientp, msgs_alloced, 1);
2820Sstevel@tonic-gate 			mutex_exit(&clientp->ic_kstat_mutex);
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 			async_cb((ibmf_handle_t)clientp, (ibmf_msg_t *)msgimplp,
2850Sstevel@tonic-gate 			    async_cb_arg);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 			mutex_enter(&qpp->isq_mutex);
2880Sstevel@tonic-gate 			IBMF_ALT_RECV_CB_CLEANUP(qpp);
2890Sstevel@tonic-gate 			mutex_exit(&qpp->isq_mutex);
2900Sstevel@tonic-gate 		}
2910Sstevel@tonic-gate 	} else {
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 		/* Solicited transaction processing */
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 		if (msgimplp->im_trans_cb == NULL) {
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 			/* Processing for a blocking transaction */
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 			mutex_enter(&msgimplp->im_mutex);
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 			if (msgimplp->im_trans_state_flags &
3020Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_WAIT) {
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 				IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
3050Sstevel@tonic-gate 				    ibmf_i_notify_client, IBMF_TNF_TRACE, "",
3060Sstevel@tonic-gate 				    "ibmf_i_notify_client(): %s, msg = 0x%p\n",
3070Sstevel@tonic-gate 				    tnf_string, msg, "Awaking thread",
3080Sstevel@tonic-gate 				    tnf_opaque, msgimplp, msgimplp);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 				cv_signal(&msgimplp->im_trans_cv);
3110Sstevel@tonic-gate 			} else {
3120Sstevel@tonic-gate 				IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
3130Sstevel@tonic-gate 				    ibmf_i_notify_client, IBMF_TNF_TRACE, "",
3140Sstevel@tonic-gate 				    "ibmf_i_notify_client(): %s, msg = 0x%p\n",
3150Sstevel@tonic-gate 				    tnf_string, msg, "Notify client, no wait",
3160Sstevel@tonic-gate 				    tnf_opaque, msgimplp, msgimplp);
3170Sstevel@tonic-gate 			}
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 			msgimplp->im_trans_state_flags |=
3200Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_SIGNALED;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 			mutex_exit(&msgimplp->im_mutex);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 		} else {
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 			/* Processing for a non-blocking transaction */
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 			mutex_enter(&msgimplp->im_mutex);
3290Sstevel@tonic-gate 			msgimplp->im_flags &= ~IBMF_MSG_FLAGS_BUSY;
3300Sstevel@tonic-gate 			mutex_exit(&msgimplp->im_mutex);
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
3330Sstevel@tonic-gate 			    ibmf_i_notify_client, IBMF_TNF_TRACE, "",
3340Sstevel@tonic-gate 			    "ibmf_i_notify_client(): %s, msg = 0x%p\n",
3350Sstevel@tonic-gate 			    tnf_string, msg, "No thread is blocking",
3360Sstevel@tonic-gate 			    tnf_opaque, msgimplp, msgimplp);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 			if (msgimplp->im_trans_cb != NULL) {
3390Sstevel@tonic-gate 				msgimplp->im_trans_cb(
3400Sstevel@tonic-gate 				    (ibmf_handle_t)clientp,
3410Sstevel@tonic-gate 				    (ibmf_msg_t *)msgimplp,
3420Sstevel@tonic-gate 				    msgimplp->im_trans_cb_arg);
3430Sstevel@tonic-gate 			}
3440Sstevel@tonic-gate 		}
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_notify_client_end,
3480Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_notify_client() exit\n");
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate /*
3520Sstevel@tonic-gate  * ibmf_i_notify_sequence()
3530Sstevel@tonic-gate  *	Checks for the need to create a termination context before
3540Sstevel@tonic-gate  *	notifying the client.
3550Sstevel@tonic-gate  */
3560Sstevel@tonic-gate void
ibmf_i_notify_sequence(ibmf_client_t * clientp,ibmf_msg_impl_t * msgimplp,int msg_flags)3570Sstevel@tonic-gate ibmf_i_notify_sequence(ibmf_client_t *clientp, ibmf_msg_impl_t *msgimplp,
3580Sstevel@tonic-gate     int msg_flags)
3590Sstevel@tonic-gate {
3600Sstevel@tonic-gate 	int status;
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
3630Sstevel@tonic-gate 	    ibmf_i_notify_sequence_start, IBMF_TNF_TRACE, "",
3640Sstevel@tonic-gate 	    "ibmf_i_notify_sequence() enter, clientp = %p, msgimplp = %p\n",
3650Sstevel@tonic-gate 	    tnf_opaque, clientp, clientp, tnf_opaque, msgimplp, msgimplp);
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	if (msg_flags & IBMF_MSG_FLAGS_TERMINATION) {
3680Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_i_notify_sequence,
3690Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_i_notify_sequence(): %s, "
3700Sstevel@tonic-gate 		    "msgimplp = %p\n", tnf_string, msg,
3710Sstevel@tonic-gate 		    "IBMF_MSG_FLAGS_TERMINATION already set",
3720Sstevel@tonic-gate 		    tnf_opaque, msgimplp, msgimplp);
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		return;
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	if (msg_flags & IBMF_MSG_FLAGS_SET_TERMINATION) {
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 		/*
3800Sstevel@tonic-gate 		 * In some cases, we need to check if the termination context
3810Sstevel@tonic-gate 		 * needs to be set up for early termination of non-double-sided
3820Sstevel@tonic-gate 		 * RMPP receiver transactions. In these cases we set up the
3830Sstevel@tonic-gate 		 * termination context, and then notify the client.
3840Sstevel@tonic-gate 		 * If the set up of the termination context fails, attempt to
3850Sstevel@tonic-gate 		 * reverse state to the regular context, and set the response
3860Sstevel@tonic-gate 		 * timer for the termination timeout and exit without notifying
3870Sstevel@tonic-gate 		 * the client in this failure case. If the setting of the
3880Sstevel@tonic-gate 		 * response timer fails, simply notify the client without
3890Sstevel@tonic-gate 		 * going through the process of timing out in the response
3900Sstevel@tonic-gate 		 * timer.
3910Sstevel@tonic-gate 		 */
3920Sstevel@tonic-gate 		status = ibmf_setup_term_ctx(clientp, msgimplp);
3930Sstevel@tonic-gate 		if (status != IBMF_SUCCESS) {
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
3960Sstevel@tonic-gate 			    ibmf_i_notify_sequence, IBMF_TNF_TRACE,
3970Sstevel@tonic-gate 			    "", "ibmf_i_notify_sequence(): %s, "
3980Sstevel@tonic-gate 			    "msgimplp = %p\n", tnf_string, msg,
3990Sstevel@tonic-gate 			    "ibmf_setup_term_ctx() failed,"
4000Sstevel@tonic-gate 			    "reversing to regular termination",
4010Sstevel@tonic-gate 			    tnf_opaque, msgimplp, msgimplp);
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 			mutex_enter(&msgimplp->im_mutex);
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 			ibmf_i_set_timer(ibmf_i_recv_timeout, msgimplp,
4060Sstevel@tonic-gate 			    IBMF_RESP_TIMER);
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 			/*
4090Sstevel@tonic-gate 			 * Set the flags cleared in
4100Sstevel@tonic-gate 			 * ibmf_i_terminate_transaction()
4110Sstevel@tonic-gate 			 */
4120Sstevel@tonic-gate 			msgimplp->im_trans_state_flags &=
4130Sstevel@tonic-gate 			    ~IBMF_TRANS_STATE_FLAG_DONE;
4140Sstevel@tonic-gate 			msgimplp->im_trans_state_flags &=
4150Sstevel@tonic-gate 			    ~IBMF_TRANS_STATE_FLAG_RECV_DONE;
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 			mutex_exit(&msgimplp->im_mutex);
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 			/* Re-add the message to the list */
4200Sstevel@tonic-gate 			ibmf_i_client_add_msg(clientp, msgimplp);
4210Sstevel@tonic-gate 		} else {
4220Sstevel@tonic-gate 			/*
4230Sstevel@tonic-gate 			 * The termination context has been
4240Sstevel@tonic-gate 			 * set up. Notify the client that the
4250Sstevel@tonic-gate 			 * regular message is done.
4260Sstevel@tonic-gate 			 */
4270Sstevel@tonic-gate 			ibmf_i_notify_client(msgimplp);
4280Sstevel@tonic-gate 		}
4290Sstevel@tonic-gate 	} else {
4300Sstevel@tonic-gate 		ibmf_i_notify_client(msgimplp);
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
4340Sstevel@tonic-gate 	    ibmf_i_notify_sequence_end, IBMF_TNF_TRACE, "",
4350Sstevel@tonic-gate 	    "ibmf_i_notify_sequence() exit, msgimplp = %p\n",
4360Sstevel@tonic-gate 	    tnf_opaque, msgimplp, msgimplp);
4370Sstevel@tonic-gate }
438