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
5651fc39cSLida.Horn  * Common Development and Distribution License (the "License").
6651fc39cSLida.Horn  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227133abc2SLida.Horn  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * This file implements the MAD receive logic in IBMF.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/ib/mgt/ibmf/ibmf_impl.h>
327c478bd9Sstevel@tonic-gate #include <sys/ib/mgt/ibmf/ibmf_saa_impl.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate extern ibmf_state_t *ibmf_statep;
357c478bd9Sstevel@tonic-gate extern int ibmf_recv_wqes_per_port;
367c478bd9Sstevel@tonic-gate extern int ibmf_send_wqes_posted_per_qp;
377c478bd9Sstevel@tonic-gate extern int ibmf_recv_wqes_posted_per_qp;
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #define	IBMF_RECV_WR_ID_TO_ADDR(id, ptr)		 \
407c478bd9Sstevel@tonic-gate 	(ptr) = (void *)(uintptr_t)((uint64_t)(id) & ~IBMF_RCV_CQE)
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #define	IBMF_QP0_NUM			0
437c478bd9Sstevel@tonic-gate #define	IBMF_QP1_NUM			1
447c478bd9Sstevel@tonic-gate #define	IBMF_BM_MAD_ATTR_MOD_REQRESP_BIT	0x00000001
457c478bd9Sstevel@tonic-gate #define	IBMF_BM_MAD_ATTR_MOD_RESP		0x1
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate  * Structure defintion of entries in the module names table
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate typedef struct _ibmf_mod_names_t {
517c478bd9Sstevel@tonic-gate 	char			mod_name[8];
527c478bd9Sstevel@tonic-gate 	ibmf_client_type_t	mgt_class;
537c478bd9Sstevel@tonic-gate } ibmf_mod_names_t;
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate typedef struct _ibmf_mod_load_args_t {
567c478bd9Sstevel@tonic-gate 	ibmf_ci_t		*cip;
577c478bd9Sstevel@tonic-gate 	ibmf_recv_wqe_t		*recv_wqep;
587c478bd9Sstevel@tonic-gate 	char			*modname;
597c478bd9Sstevel@tonic-gate 	ibmf_client_type_t	ibmf_class;
607c478bd9Sstevel@tonic-gate } ibmf_mod_load_args_t;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate extern int ibmf_trace_level;
637c478bd9Sstevel@tonic-gate extern int ibmf_send_wqes_posted_per_qp;
647c478bd9Sstevel@tonic-gate extern int ibmf_recv_wqes_posted_per_qp;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static void ibmf_i_do_recv_cb(void *taskq_arg);
677c478bd9Sstevel@tonic-gate static int ibmf_i_repost_recv_buffer(ibmf_ci_t *cip,
687c478bd9Sstevel@tonic-gate     ibmf_recv_wqe_t *recv_wqep);
697c478bd9Sstevel@tonic-gate static int ibmf_i_get_class(ib_mad_hdr_t *madhdrp,
707c478bd9Sstevel@tonic-gate     ibmf_qp_handle_t dest_ibmf_qp_handle, ib_lid_t slid,
717c478bd9Sstevel@tonic-gate     ibmf_client_type_t *dest_classp);
727c478bd9Sstevel@tonic-gate static void ibmf_i_handle_non_rmpp(ibmf_client_t *clientp,
737c478bd9Sstevel@tonic-gate     ibmf_msg_impl_t *msgimplp, uchar_t *mad);
747c478bd9Sstevel@tonic-gate static void ibmf_get_mod_name(uint8_t mad_class, ibmf_client_type_t class,
757c478bd9Sstevel@tonic-gate     char *modname);
767c478bd9Sstevel@tonic-gate static void ibmf_module_load(void *taskq_arg);
777c478bd9Sstevel@tonic-gate static void ibmf_send_busy(ibmf_mod_load_args_t *modlargsp);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate #define	AGENT_CLASS(class)					\
807c478bd9Sstevel@tonic-gate 	(((class & 0x000F0000) == IBMF_AGENT_ID))
817c478bd9Sstevel@tonic-gate #define	MANAGER_CLASS(class)				\
827c478bd9Sstevel@tonic-gate 	(((class & 0x000F0000) == IBMF_MANAGER_ID))
837c478bd9Sstevel@tonic-gate #define	AGENT_MANAGER_CLASS(class)				\
847c478bd9Sstevel@tonic-gate 	(((class & 0x000F0000) == IBMF_AGENT_MANAGER_ID))
857c478bd9Sstevel@tonic-gate #define	IS_MANDATORY_CLASS(class)			\
867c478bd9Sstevel@tonic-gate 	((class == PERF_AGENT) || (class == BM_AGENT))
877c478bd9Sstevel@tonic-gate 
88*525f8227SToomas Soome char	ibmf_client_modname[16];
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * ibmf_i_handle_recv_completion():
927c478bd9Sstevel@tonic-gate  *	Process the WQE from the RQ, obtain the management class of the
937c478bd9Sstevel@tonic-gate  *	packet and retrieve the corresponding client context
947c478bd9Sstevel@tonic-gate  */
957c478bd9Sstevel@tonic-gate void
ibmf_i_handle_recv_completion(ibmf_ci_t * cip,ibt_wc_t * wcp)967c478bd9Sstevel@tonic-gate ibmf_i_handle_recv_completion(ibmf_ci_t *cip, ibt_wc_t *wcp)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	int			ret;
997c478bd9Sstevel@tonic-gate 	ibmf_client_type_t	class;
1007c478bd9Sstevel@tonic-gate 	ibmf_client_t		*clientp;
1017c478bd9Sstevel@tonic-gate 	ib_mad_hdr_t		*madhdrp;
1027c478bd9Sstevel@tonic-gate 	ibmf_recv_wqe_t		*recv_wqep;
1037c478bd9Sstevel@tonic-gate 	ibt_recv_wr_t		*rwrp;
1047c478bd9Sstevel@tonic-gate 	ibmf_qp_handle_t	ibmf_qp_handle;
1057c478bd9Sstevel@tonic-gate 	struct kmem_cache	*kmem_cachep;
1067c478bd9Sstevel@tonic-gate 	ibmf_alt_qp_t		*altqp;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
1097c478bd9Sstevel@tonic-gate 	    ibmf_i_handle_recv_completion_start, IBMF_TNF_TRACE, "",
1107c478bd9Sstevel@tonic-gate 	    "ibmf_i_handle_recv_completion() enter, cip = %p, wcp = %p\n",
1117c478bd9Sstevel@tonic-gate 	    tnf_opaque, cip, cip, tnf_opaque, wcp, wcp);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	mutex_enter(&cip->ci_ud_dest_list_mutex);
1147c478bd9Sstevel@tonic-gate 	if (cip->ci_ud_dest_list_count < IBMF_UD_DEST_LO_WATER_MARK) {
1157c478bd9Sstevel@tonic-gate 		ret = ibmf_ud_dest_tq_disp(cip);
1167c478bd9Sstevel@tonic-gate 		if (ret == 0) {
1177c478bd9Sstevel@tonic-gate 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L3,
1187c478bd9Sstevel@tonic-gate 			    ibmf_i_handle_recv_completion_err, IBMF_TNF_ERROR,
1197c478bd9Sstevel@tonic-gate 			    "", "ibmf_i_handle_recv_completion(): %s\n",
1207c478bd9Sstevel@tonic-gate 			    tnf_string, msg, "taskq dispatch of ud_dest "
1217c478bd9Sstevel@tonic-gate 			    "population thread failed");
1227c478bd9Sstevel@tonic-gate 		}
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 	mutex_exit(&cip->ci_ud_dest_list_mutex);
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	ASSERT(IBMF_IS_RECV_WR_ID(wcp->wc_id));
1277c478bd9Sstevel@tonic-gate 	IBMF_RECV_WR_ID_TO_ADDR(wcp->wc_id, recv_wqep);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	rwrp = &recv_wqep->recv_wr;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	/* Retrieve the QP handle from the receive WQE context */
1327c478bd9Sstevel@tonic-gate 	ibmf_qp_handle = recv_wqep->recv_ibmf_qp_handle;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	/* Get the WQE kmem cache pointer based on the QP type */
1357c478bd9Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1367c478bd9Sstevel@tonic-gate 		kmem_cachep = cip->ci_recv_wqes_cache;
1377c478bd9Sstevel@tonic-gate 	} else {
1387c478bd9Sstevel@tonic-gate 		altqp = (ibmf_alt_qp_t *)ibmf_qp_handle;
1397c478bd9Sstevel@tonic-gate 		kmem_cachep = altqp->isq_recv_wqes_cache;
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	/*
1437c478bd9Sstevel@tonic-gate 	 * if the wqe is being flushed due to shutting down of the qp, free
1447c478bd9Sstevel@tonic-gate 	 * the wqe and return.
1457c478bd9Sstevel@tonic-gate 	 */
1467c478bd9Sstevel@tonic-gate 	if (wcp->wc_status == IBT_WC_WR_FLUSHED_ERR) {
1477c478bd9Sstevel@tonic-gate 		kmem_free(rwrp->wr_sgl, IBMF_MAX_RQ_WR_SGL_ELEMENTS *
1487c478bd9Sstevel@tonic-gate 		    sizeof (ibt_wr_ds_t));
1497c478bd9Sstevel@tonic-gate 		kmem_cache_free(kmem_cachep, recv_wqep);
1507c478bd9Sstevel@tonic-gate 		mutex_enter(&cip->ci_mutex);
1517c478bd9Sstevel@tonic-gate 		IBMF_SUB32_PORT_KSTATS(cip, recv_wqes_alloced, 1);
1527c478bd9Sstevel@tonic-gate 		mutex_exit(&cip->ci_mutex);
1537c478bd9Sstevel@tonic-gate 		if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1547c478bd9Sstevel@tonic-gate 			mutex_enter(&cip->ci_mutex);
1557c478bd9Sstevel@tonic-gate 			cip->ci_wqes_alloced--;
1567c478bd9Sstevel@tonic-gate 			if (cip->ci_wqes_alloced == 0)
1577c478bd9Sstevel@tonic-gate 				cv_signal(&cip->ci_wqes_cv);
1587c478bd9Sstevel@tonic-gate 			mutex_exit(&cip->ci_mutex);
1597c478bd9Sstevel@tonic-gate 		} else {
1607c478bd9Sstevel@tonic-gate 			mutex_enter(&altqp->isq_mutex);
1617c478bd9Sstevel@tonic-gate 			altqp->isq_wqes_alloced--;
1627c478bd9Sstevel@tonic-gate 			if (altqp->isq_wqes_alloced == 0)
1637c478bd9Sstevel@tonic-gate 				cv_signal(&altqp->isq_wqes_cv);
1647c478bd9Sstevel@tonic-gate 			mutex_exit(&altqp->isq_mutex);
1657c478bd9Sstevel@tonic-gate 		}
1667c478bd9Sstevel@tonic-gate 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3,
1677c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_recv_completion, IBMF_TNF_TRACE,
1687c478bd9Sstevel@tonic-gate 		    "", "ibmf_i_handle_recv_completion(): %s\n",
1697c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "recv wqe flushed");
1707c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
1717c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_recv_completion_end, IBMF_TNF_TRACE,
1727c478bd9Sstevel@tonic-gate 		    "", "ibmf_i_handle_recv_completion() exit\n");
1737c478bd9Sstevel@tonic-gate 		return;
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/*
1777c478bd9Sstevel@tonic-gate 	 * Dynamic Posting of WQEs to the Receive Queue (RQ) of the QP:
1787c478bd9Sstevel@tonic-gate 	 * If the number of RQ WQEs posted to the QP drops below half
1797c478bd9Sstevel@tonic-gate 	 * the initial number of RQ WQEs posted to the QP, then, one additional
1807c478bd9Sstevel@tonic-gate 	 * WQE is posted to the RQ of the QP while processing this CQE.
1817c478bd9Sstevel@tonic-gate 	 */
1827c478bd9Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
1837c478bd9Sstevel@tonic-gate 		ibmf_qp_t *qpp = recv_wqep->recv_qpp;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 		mutex_enter(&qpp->iq_mutex);
1867c478bd9Sstevel@tonic-gate 		qpp->iq_rwqes_posted--;
1877c478bd9Sstevel@tonic-gate 		if (qpp->iq_rwqes_posted <= (ibmf_recv_wqes_per_port >> 1)) {
1887c478bd9Sstevel@tonic-gate 			mutex_exit(&qpp->iq_mutex);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
1917c478bd9Sstevel@tonic-gate 			    ibmf_i_handle_recv_compl, IBMF_TNF_TRACE, "",
1927c478bd9Sstevel@tonic-gate 			    "ibmf_i_handle_recv_compl(): %s, "
1937c478bd9Sstevel@tonic-gate 			    "QP# = %d\n", tnf_string, msg,
1947c478bd9Sstevel@tonic-gate 			    "Posting more RQ WQEs",
1957c478bd9Sstevel@tonic-gate 			    tnf_int, qpnum, qpp->iq_qp_num);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 			/* Post an additional WQE to the RQ */
1987c478bd9Sstevel@tonic-gate 			ret = ibmf_i_post_recv_buffer(cip, qpp,
1997c478bd9Sstevel@tonic-gate 			    B_FALSE, ibmf_qp_handle);
2007c478bd9Sstevel@tonic-gate 			if (ret != IBMF_SUCCESS) {
201651fc39cSLida.Horn 				IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
202651fc39cSLida.Horn 				    ibmf_i_handle_recv_compl, IBMF_TNF_TRACE,
203651fc39cSLida.Horn 				    "", "ibmf_i_handle_recv_compl(): %s, "
204651fc39cSLida.Horn 				    "status = %d\n", tnf_string, msg,
205651fc39cSLida.Horn 				    "ibmf_i_post_recv_buffer() failed",
206651fc39cSLida.Horn 				    tnf_int, status, ret);
2077c478bd9Sstevel@tonic-gate 			}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 			mutex_enter(&qpp->iq_mutex);
2107c478bd9Sstevel@tonic-gate 		}
2117c478bd9Sstevel@tonic-gate 		mutex_exit(&qpp->iq_mutex);
2127c478bd9Sstevel@tonic-gate 	} else {
2137c478bd9Sstevel@tonic-gate 		mutex_enter(&altqp->isq_mutex);
2147c478bd9Sstevel@tonic-gate 		altqp->isq_rwqes_posted--;
2157c478bd9Sstevel@tonic-gate 		if (altqp->isq_rwqes_posted <= (ibmf_recv_wqes_per_port >> 1)) {
2167c478bd9Sstevel@tonic-gate 			mutex_exit(&altqp->isq_mutex);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
2197c478bd9Sstevel@tonic-gate 			    ibmf_i_handle_recv_compl, IBMF_TNF_TRACE, "",
2207c478bd9Sstevel@tonic-gate 			    "ibmf_i_handle_recv_compl(): %s, "
2217c478bd9Sstevel@tonic-gate 			    "QP# = %d\n", tnf_string, msg,
2227c478bd9Sstevel@tonic-gate 			    "Posting more RQ WQEs",
2237c478bd9Sstevel@tonic-gate 			    tnf_int, qpnum, altqp->isq_qpn);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 			/* Post an additional WQE to the RQ */
2267c478bd9Sstevel@tonic-gate 			ret = ibmf_i_post_recv_buffer(cip, NULL,
2277c478bd9Sstevel@tonic-gate 			    B_FALSE, ibmf_qp_handle);
2287c478bd9Sstevel@tonic-gate 			if (ret != IBMF_SUCCESS) {
229651fc39cSLida.Horn 				IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
230651fc39cSLida.Horn 				    ibmf_i_handle_recv_compl, IBMF_TNF_TRACE,
231651fc39cSLida.Horn 				    "", "ibmf_i_handle_recv_compl(): %s, "
232651fc39cSLida.Horn 				    "status = %d\n", tnf_string, msg,
233651fc39cSLida.Horn 				    "ibmf_i_post_recv_buffer() failed",
234651fc39cSLida.Horn 				    tnf_int, status, ret);
2357c478bd9Sstevel@tonic-gate 			}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 			mutex_enter(&altqp->isq_mutex);
2387c478bd9Sstevel@tonic-gate 		}
2397c478bd9Sstevel@tonic-gate 		mutex_exit(&altqp->isq_mutex);
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	/*
2437c478bd9Sstevel@tonic-gate 	 * for all other completion errors, repost the wqe, and if that
2447c478bd9Sstevel@tonic-gate 	 * fails, free the wqe and return.
2457c478bd9Sstevel@tonic-gate 	 */
2467c478bd9Sstevel@tonic-gate 	if (wcp->wc_status != IBT_WC_SUCCESS) {
2477c478bd9Sstevel@tonic-gate 		(void) ibmf_i_repost_recv_buffer(cip, recv_wqep);
2487c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
2497c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_recv_completion_err, IBMF_TNF_ERROR,
2507c478bd9Sstevel@tonic-gate 		    "", "ibmf_i_handle_recv_completion(): %s, wc_status = %d\n",
2517c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "bad completion status received",
2527c478bd9Sstevel@tonic-gate 		    tnf_uint, wc_status, wcp->wc_status);
2537c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2547c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_recv_completion_end, IBMF_TNF_TRACE,
2557c478bd9Sstevel@tonic-gate 		    "", "ibmf_i_handle_recv_completion() exit\n");
2567c478bd9Sstevel@tonic-gate 		return;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	/* find the client corresponding to this recv cqe */
2607c478bd9Sstevel@tonic-gate 	madhdrp = (ib_mad_hdr_t *)((uintptr_t)recv_wqep->recv_mem +
2617c478bd9Sstevel@tonic-gate 	    sizeof (ib_grh_t));
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	/* drop packet if MAD Base Version is not as expected */
2647c478bd9Sstevel@tonic-gate 	if (madhdrp->BaseVersion != MAD_CLASS_BASE_VERS_1) {
2657c478bd9Sstevel@tonic-gate 		(void) ibmf_i_repost_recv_buffer(cip, recv_wqep);
2667c478bd9Sstevel@tonic-gate 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2677c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_recv_completion_err, IBMF_TNF_ERROR,
2687c478bd9Sstevel@tonic-gate 		    "", "ibmf_i_handle_recv_completion(): %s\n",
2697c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "bad MAD version");
2707c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2717c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_recv_completion_end, IBMF_TNF_TRACE,
2727c478bd9Sstevel@tonic-gate 		    "", "ibmf_i_handle_recv_completion() exit\n");
2737c478bd9Sstevel@tonic-gate 		return;
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	if (ibmf_i_get_class(madhdrp, recv_wqep->recv_ibmf_qp_handle,
2777c478bd9Sstevel@tonic-gate 	    wcp->wc_slid, &class) != IBMF_SUCCESS) {
2787c478bd9Sstevel@tonic-gate 		/* bad class & type? */
2797c478bd9Sstevel@tonic-gate #ifdef DEBUG
2807c478bd9Sstevel@tonic-gate 		ibmf_i_dump_wcp(cip, wcp, recv_wqep);
2817c478bd9Sstevel@tonic-gate #endif
2827c478bd9Sstevel@tonic-gate 		(void) ibmf_i_repost_recv_buffer(cip, recv_wqep);
2837c478bd9Sstevel@tonic-gate 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
2847c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_recv_completion_err, IBMF_TNF_ERROR,
2857c478bd9Sstevel@tonic-gate 		    "", "ibmf_i_handle_recv_completion(): %s\n",
2867c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "bad class/type");
2877c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
2887c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_recv_completion_end, IBMF_TNF_TRACE,
2897c478bd9Sstevel@tonic-gate 		    "", "ibmf_i_handle_recv_completion() exit\n");
2907c478bd9Sstevel@tonic-gate 		return;
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	ret = ibmf_i_lookup_client_by_mgmt_class(cip, recv_wqep->recv_port_num,
2947c478bd9Sstevel@tonic-gate 	    class, &clientp);
2957c478bd9Sstevel@tonic-gate 	if (ret == IBMF_SUCCESS) {
2967c478bd9Sstevel@tonic-gate 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*recv_wqep))
2977c478bd9Sstevel@tonic-gate 		recv_wqep->recv_client = clientp;
2987c478bd9Sstevel@tonic-gate 		recv_wqep->recv_wc = *wcp; /* struct copy */
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 		/*
3017c478bd9Sstevel@tonic-gate 		 * Increment the kstats for the number of active receiver side
3027c478bd9Sstevel@tonic-gate 		 * callbacks
3037c478bd9Sstevel@tonic-gate 		 */
3047c478bd9Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
3057c478bd9Sstevel@tonic-gate 		IBMF_ADD32_KSTATS(clientp, recv_cb_active, 1);
3067c478bd9Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 		if ((clientp->ic_reg_flags & IBMF_REG_FLAG_NO_OFFLOAD) == 0) {
3097c478bd9Sstevel@tonic-gate 			/* Dispatch the taskq thread to do further processing */
3107c478bd9Sstevel@tonic-gate 			ret = taskq_dispatch(clientp->ic_recv_taskq,
3117c478bd9Sstevel@tonic-gate 			    ibmf_i_do_recv_cb, recv_wqep, TQ_NOSLEEP);
312fc8ae2ecSToomas Soome 			if (ret == TASKQID_INVALID) {
3137c478bd9Sstevel@tonic-gate 				mutex_enter(&clientp->ic_kstat_mutex);
3147c478bd9Sstevel@tonic-gate 				IBMF_SUB32_KSTATS(clientp, recv_cb_active, 1);
3157c478bd9Sstevel@tonic-gate 				mutex_exit(&clientp->ic_kstat_mutex);
3167c478bd9Sstevel@tonic-gate 				IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
3177c478bd9Sstevel@tonic-gate 				    ibmf_i_handle_recv_completion_err,
3187c478bd9Sstevel@tonic-gate 				    IBMF_TNF_ERROR, "",
3197c478bd9Sstevel@tonic-gate 				    "ibmf_i_handle_recv_completion(): %s\n",
3207c478bd9Sstevel@tonic-gate 				    tnf_string, msg, "dispatch failed");
3217c478bd9Sstevel@tonic-gate 				(void) ibmf_i_repost_recv_buffer(cip,
3227c478bd9Sstevel@tonic-gate 				    recv_wqep);
3237c478bd9Sstevel@tonic-gate 				IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3247c478bd9Sstevel@tonic-gate 				    ibmf_i_handle_recv_completion_end,
3257c478bd9Sstevel@tonic-gate 				    IBMF_TNF_TRACE, "",
3267c478bd9Sstevel@tonic-gate 				    "ibmf_i_handle_recv_completion() exit\n");
3277c478bd9Sstevel@tonic-gate 				return;
3287c478bd9Sstevel@tonic-gate 			}
3297c478bd9Sstevel@tonic-gate 		} else {
3307c478bd9Sstevel@tonic-gate 			ibmf_i_do_recv_cb((void *)recv_wqep);
3317c478bd9Sstevel@tonic-gate 		}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 		/*
3347c478bd9Sstevel@tonic-gate 		 * Decrement the kstats for the number of active receiver side
3357c478bd9Sstevel@tonic-gate 		 * callbacks
3367c478bd9Sstevel@tonic-gate 		 */
3377c478bd9Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
3387c478bd9Sstevel@tonic-gate 		IBMF_SUB32_KSTATS(clientp, recv_cb_active, 1);
3397c478bd9Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	} else {
3427c478bd9Sstevel@tonic-gate 		/*
3437c478bd9Sstevel@tonic-gate 		 * A client has not registered to receive MADs of this
3447c478bd9Sstevel@tonic-gate 		 * management class. IBMF must attempt to load the
3457c478bd9Sstevel@tonic-gate 		 * client and request a resend of the request MAD.
3467c478bd9Sstevel@tonic-gate 		 * The name of the client MAD is derived using a
3477c478bd9Sstevel@tonic-gate 		 * convention described in PSARC case 2003/753.
3487c478bd9Sstevel@tonic-gate 		 */
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 		ibmf_mod_load_args_t	*modlargsp;
3517c478bd9Sstevel@tonic-gate 
352d1a5c838SRamaswamy Tummala 		/*
353d1a5c838SRamaswamy Tummala 		 * HCA driver handles the Performance management
354d1a5c838SRamaswamy Tummala 		 * class MAD's. It registers with the IBMF during early
355d1a5c838SRamaswamy Tummala 		 * boot and unregisters during detach and during
356d1a5c838SRamaswamy Tummala 		 * HCA unconfigure operation. We come here
357d1a5c838SRamaswamy Tummala 		 * 1. Before HCA registers with IBMF
358*525f8227SToomas Soome 		 *	Drop the MAD. Since this is a UD MAD,
359d1a5c838SRamaswamy Tummala 		 *	sender will resend the request
360d1a5c838SRamaswamy Tummala 		 * 2. After HCA unregistered with IBMF during DR operation.
361d1a5c838SRamaswamy Tummala 		 *	Since HCA is going away, we can safely drop the PMA
362d1a5c838SRamaswamy Tummala 		 *	MAD's here.
363d1a5c838SRamaswamy Tummala 		 * Solaris does not support BM_AGENT and so drop the BM MAD's
364d1a5c838SRamaswamy Tummala 		 */
365d1a5c838SRamaswamy Tummala 		if ((class == PERF_AGENT) || (class == BM_AGENT)) {
366d1a5c838SRamaswamy Tummala 			(void) ibmf_i_repost_recv_buffer(cip, recv_wqep);
367d1a5c838SRamaswamy Tummala 			return;
368d1a5c838SRamaswamy Tummala 		}
369d1a5c838SRamaswamy Tummala 
3707c478bd9Sstevel@tonic-gate 		recv_wqep->recv_wc = *wcp; /* struct copy */
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 		IBMF_TRACE_3(IBMF_TNF_NODEBUG, DPRINT_L4,
3737c478bd9Sstevel@tonic-gate 		    ibmf_i_handle_recv_completion_err, IBMF_TNF_ERROR, "",
3747c478bd9Sstevel@tonic-gate 		    "ibmf_i_handle_recv_completion(): %s, port = %d, "
3757c478bd9Sstevel@tonic-gate 		    "class = 0x%x\n",
3767c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "no client registered", tnf_uint, port,
3777c478bd9Sstevel@tonic-gate 		    recv_wqep->recv_port_num, tnf_opaque, class, class);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 		/* Construct the IBMF client module name */
3807c478bd9Sstevel@tonic-gate 		ibmf_get_mod_name(madhdrp->MgmtClass, class,
3817c478bd9Sstevel@tonic-gate 		    ibmf_client_modname);
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 		/* Load the module using a taskq thread */
3847c478bd9Sstevel@tonic-gate 		modlargsp = (ibmf_mod_load_args_t *)kmem_zalloc(
3857c478bd9Sstevel@tonic-gate 		    sizeof (ibmf_mod_load_args_t), KM_NOSLEEP);
3867c478bd9Sstevel@tonic-gate 		if (modlargsp != NULL) {
3877c478bd9Sstevel@tonic-gate 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*modlargsp))
3887c478bd9Sstevel@tonic-gate 			modlargsp->cip		= cip;
3897c478bd9Sstevel@tonic-gate 			modlargsp->recv_wqep	= recv_wqep;
3907c478bd9Sstevel@tonic-gate 			modlargsp->modname	= ibmf_client_modname;
3917c478bd9Sstevel@tonic-gate 			modlargsp->ibmf_class	= class;
3927c478bd9Sstevel@tonic-gate 			ret = taskq_dispatch(ibmf_statep->ibmf_taskq,
3937c478bd9Sstevel@tonic-gate 			    ibmf_module_load, modlargsp, TQ_NOSLEEP);
394fc8ae2ecSToomas Soome 			if (ret == TASKQID_INVALID) {
3957c478bd9Sstevel@tonic-gate 				kmem_free(modlargsp,
3967c478bd9Sstevel@tonic-gate 				    sizeof (ibmf_mod_load_args_t));
3977c478bd9Sstevel@tonic-gate 				IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
3987c478bd9Sstevel@tonic-gate 				    ibmf_i_handle_recv_completion_error,
3997c478bd9Sstevel@tonic-gate 				    IBMF_TNF_TRACE, "",
4007c478bd9Sstevel@tonic-gate 				    "ibmf_i_handle_recv_completion(): Failed "
4017c478bd9Sstevel@tonic-gate 				    "to dispatch ibmf_module_load taskq\n");
4027c478bd9Sstevel@tonic-gate 				(void) ibmf_i_repost_recv_buffer(cip,
4037c478bd9Sstevel@tonic-gate 				    recv_wqep);
4047c478bd9Sstevel@tonic-gate 			}
4057c478bd9Sstevel@tonic-gate 		} else {
4067c478bd9Sstevel@tonic-gate 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
4077c478bd9Sstevel@tonic-gate 			    ibmf_i_handle_recv_completion_end, IBMF_TNF_TRACE,
4087c478bd9Sstevel@tonic-gate 			    "", "ibmf_i_handle_recv_completion(): "
4097c478bd9Sstevel@tonic-gate 			    "Failed to allocate memory for modlargs\n");
4107c478bd9Sstevel@tonic-gate 			(void) ibmf_i_repost_recv_buffer(cip, recv_wqep);
4117c478bd9Sstevel@tonic-gate 		}
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
4157c478bd9Sstevel@tonic-gate 	    ibmf_i_handle_recv_completion_end, IBMF_TNF_TRACE, "",
4167c478bd9Sstevel@tonic-gate 	    "ibmf_i_handle_recv_completion() exit\n");
4177c478bd9Sstevel@tonic-gate }
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate  * ibmf_i_do_recv_cb():
4217c478bd9Sstevel@tonic-gate  *	This routine does the following:
4227c478bd9Sstevel@tonic-gate  *	o looks for a message in the client's message list
4237c478bd9Sstevel@tonic-gate  *	o creates a new message if one does not exist for unsolicited data
4247c478bd9Sstevel@tonic-gate  *	o invoke routines to do specific handling for rmpp and non-rmpp cases
4257c478bd9Sstevel@tonic-gate  *	o on a failure, the receive WQE is reposted to the RQ
4267c478bd9Sstevel@tonic-gate  */
4277c478bd9Sstevel@tonic-gate static void
ibmf_i_do_recv_cb(void * taskq_arg)4287c478bd9Sstevel@tonic-gate ibmf_i_do_recv_cb(void *taskq_arg)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	ibt_wc_t		*wcp;
4317c478bd9Sstevel@tonic-gate 	ibmf_msg_impl_t		*msgimplp;
4327c478bd9Sstevel@tonic-gate 	ibmf_client_t		*clientp;
4337c478bd9Sstevel@tonic-gate 	ibmf_addr_info_t	addrinfo;
4347c478bd9Sstevel@tonic-gate 	ibmf_recv_wqe_t		*recv_wqep;
4357c478bd9Sstevel@tonic-gate 	ib_grh_t		*ib_grh;
4367c478bd9Sstevel@tonic-gate 	boolean_t		grhpresent;
4377c478bd9Sstevel@tonic-gate 	ibmf_qp_handle_t	ibmf_qp_handle;
4387c478bd9Sstevel@tonic-gate 	ib_mad_hdr_t		*mad_hdr;
4397c478bd9Sstevel@tonic-gate 	ibmf_rmpp_hdr_t		*rmpp_hdr;
4407c478bd9Sstevel@tonic-gate 	ibmf_alt_qp_t		*qpp;
4417c478bd9Sstevel@tonic-gate 	ib_gid_t		gid;
4427c478bd9Sstevel@tonic-gate 	ib_lid_t		lid;
4437c478bd9Sstevel@tonic-gate 	int			msg_trans_state_flags, msg_flags;
4447c478bd9Sstevel@tonic-gate 	uint_t			ref_cnt;
4457c478bd9Sstevel@tonic-gate 	timeout_id_t		msg_rp_unset_id, msg_tr_unset_id;
4467c478bd9Sstevel@tonic-gate 	timeout_id_t		msg_rp_set_id, msg_tr_set_id;
4477c478bd9Sstevel@tonic-gate 	int			status;
4487c478bd9Sstevel@tonic-gate 	saa_port_t		*saa_portp;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*recv_wqep))
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	/* The taskq_arg argument is a pointer to the receive WQE context */
4537c478bd9Sstevel@tonic-gate 	recv_wqep = taskq_arg;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	/* Retrieve the QP handle from the receive WQE context */
4567c478bd9Sstevel@tonic-gate 	ibmf_qp_handle = recv_wqep->recv_ibmf_qp_handle;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
4597c478bd9Sstevel@tonic-gate 	    ibmf_i_do_recv_cb_start, IBMF_TNF_TRACE, "",
4607c478bd9Sstevel@tonic-gate 	    "ibmf_i_do_recv_cb() enter, recv_wqep = %p\n",
4617c478bd9Sstevel@tonic-gate 	    tnf_opaque, recv_wqep, recv_wqep);
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	/* Retrieve the client context pointer from the receive WQE context */
4647c478bd9Sstevel@tonic-gate 	clientp = recv_wqep->recv_client;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	/* Get a pointer to the IBT work completion structure */
4677c478bd9Sstevel@tonic-gate 	wcp = &recv_wqep->recv_wc;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wcp))
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	/*
4727c478bd9Sstevel@tonic-gate 	 * Identify the port by the  LID or GID depending on whether the
4737c478bd9Sstevel@tonic-gate 	 * Global Route Header is valid or not
4747c478bd9Sstevel@tonic-gate 	 */
4757c478bd9Sstevel@tonic-gate 	if (wcp->wc_flags & IBT_WC_GRH_PRESENT) {
4767c478bd9Sstevel@tonic-gate 		grhpresent = B_TRUE;
4777c478bd9Sstevel@tonic-gate 		ib_grh = (ib_grh_t *)recv_wqep->recv_mem;
4787c478bd9Sstevel@tonic-gate 		gid.gid_prefix	= b2h64(ib_grh->SGID.gid_prefix);
479*525f8227SToomas Soome 		gid.gid_guid	= b2h64(ib_grh->SGID.gid_guid);
4807c478bd9Sstevel@tonic-gate 	} else {
4817c478bd9Sstevel@tonic-gate 		grhpresent = B_FALSE;
4827c478bd9Sstevel@tonic-gate 		lid = wcp->wc_slid;
4837c478bd9Sstevel@tonic-gate 	}
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	/* Get a pointer to the MAD header */
4867c478bd9Sstevel@tonic-gate 	mad_hdr = (ib_mad_hdr_t *)((uintptr_t)recv_wqep->recv_mem +
4877c478bd9Sstevel@tonic-gate 	    sizeof (ib_grh_t));
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	/* Get a pointer to the RMPP header */
4907c478bd9Sstevel@tonic-gate 	rmpp_hdr = (ibmf_rmpp_hdr_t *)((uintptr_t)recv_wqep->recv_mem +
4917c478bd9Sstevel@tonic-gate 	    sizeof (ib_grh_t) + sizeof (ib_mad_hdr_t));
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L3,
4947c478bd9Sstevel@tonic-gate 	    ibmf_i_do_recv_cb, IBMF_TNF_TRACE, "",
4957c478bd9Sstevel@tonic-gate 	    "ibmf_i_do_recv_cb(): %s, tid = %016" PRIx64 ", class = 0x%x, "
4967c478bd9Sstevel@tonic-gate 	    "attrID = 0x%x, lid = 0x%x\n",
4977c478bd9Sstevel@tonic-gate 	    tnf_string, msg, "Received MAD", tnf_opaque, tid,
4987c478bd9Sstevel@tonic-gate 	    b2h64(mad_hdr->TransactionID), tnf_opaque, class,
4997c478bd9Sstevel@tonic-gate 	    mad_hdr->MgmtClass, tnf_opaque, attr_id,
5007c478bd9Sstevel@tonic-gate 	    b2h16(mad_hdr->AttributeID), tnf_opaque, remote_lid, lid);
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	/*
5037c478bd9Sstevel@tonic-gate 	 * Look for the matching message in the client's message list
5047c478bd9Sstevel@tonic-gate 	 * NOTE: if the message is found, the message reference count will
5057c478bd9Sstevel@tonic-gate 	 * have been increased by 1.
5067c478bd9Sstevel@tonic-gate 	 */
5077c478bd9Sstevel@tonic-gate 	msgimplp = ibmf_i_find_msg(clientp, b2h64(mad_hdr->TransactionID),
5087c478bd9Sstevel@tonic-gate 	    mad_hdr->MgmtClass, mad_hdr->R_Method, lid, &gid, grhpresent,
5097c478bd9Sstevel@tonic-gate 	    rmpp_hdr, IBMF_REG_MSG_LIST);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	/*
5127c478bd9Sstevel@tonic-gate 	 * If the message is not on the regular message list, search
5137c478bd9Sstevel@tonic-gate 	 * for it in the termination message list.
5147c478bd9Sstevel@tonic-gate 	 */
5157c478bd9Sstevel@tonic-gate 	if (msgimplp == NULL) {
5167c478bd9Sstevel@tonic-gate 		msgimplp = ibmf_i_find_msg(clientp,
5177c478bd9Sstevel@tonic-gate 		    b2h64(mad_hdr->TransactionID), mad_hdr->MgmtClass,
5187c478bd9Sstevel@tonic-gate 		    mad_hdr->R_Method, lid, &gid, grhpresent, rmpp_hdr,
5197c478bd9Sstevel@tonic-gate 		    IBMF_TERM_MSG_LIST);
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	if (msgimplp != NULL) {
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 		/* if this packet is from the SA */
5257c478bd9Sstevel@tonic-gate 		if (clientp->ic_client_info.client_class == SUBN_ADM_MANAGER) {
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 			/*
5287c478bd9Sstevel@tonic-gate 			 * ibmf_saa's callback arg is its saa_portp;
5297c478bd9Sstevel@tonic-gate 			 * take advantage of this fact to quickly update the
5307c478bd9Sstevel@tonic-gate 			 * port's SA uptime.  ibmf_saa uses the up time to
5317c478bd9Sstevel@tonic-gate 			 * determine if the SA is still alive
5327c478bd9Sstevel@tonic-gate 			 */
5337c478bd9Sstevel@tonic-gate 			saa_portp = clientp->ic_async_cb_arg;
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 			/* update the SA uptime */
5367c478bd9Sstevel@tonic-gate 			mutex_enter(&saa_portp->saa_pt_mutex);
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 			saa_portp->saa_pt_sa_uptime = gethrtime();
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 			mutex_exit(&saa_portp->saa_pt_mutex);
5417c478bd9Sstevel@tonic-gate 		}
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 		mutex_enter(&msgimplp->im_mutex);
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 		/*
5467c478bd9Sstevel@tonic-gate 		 * Clear timers for transactions of solicited incoming packets
5477c478bd9Sstevel@tonic-gate 		 */
5487c478bd9Sstevel@tonic-gate 		if (msgimplp->im_rp_timeout_id != 0) {
5497c478bd9Sstevel@tonic-gate 			ibmf_i_unset_timer(msgimplp, IBMF_RESP_TIMER);
5507c478bd9Sstevel@tonic-gate 		}
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 		/*
5537c478bd9Sstevel@tonic-gate 		 * If a MAD is received in the middle of an RMPP receive
5547c478bd9Sstevel@tonic-gate 		 * transaction, and the MAD's RMPPFlags.Active bit is 0,
5557c478bd9Sstevel@tonic-gate 		 * drop the MAD
5567c478bd9Sstevel@tonic-gate 		 */
5577c478bd9Sstevel@tonic-gate 		if (ibmf_i_is_rmpp(clientp, ibmf_qp_handle) &&
5587c478bd9Sstevel@tonic-gate 		    (msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) &&
5597c478bd9Sstevel@tonic-gate 		    ((rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_ACTIVE) == 0)) {
5607c478bd9Sstevel@tonic-gate 			mutex_exit(&msgimplp->im_mutex);
5617c478bd9Sstevel@tonic-gate 			(void) ibmf_i_repost_recv_buffer(clientp->ic_myci,
5627c478bd9Sstevel@tonic-gate 			    recv_wqep);
5637c478bd9Sstevel@tonic-gate 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L3,
5647c478bd9Sstevel@tonic-gate 			    ibmf_i_do_recv_cb_error, IBMF_TNF_ERROR, "",
5657c478bd9Sstevel@tonic-gate 			    "ibmf_i_do_recv_cb(): %s, msg = %p\n",
5667c478bd9Sstevel@tonic-gate 			    tnf_string, msg,
5677c478bd9Sstevel@tonic-gate 			    "Non-RMPP MAD received in RMPP transaction, "
5687c478bd9Sstevel@tonic-gate 			    "dropping MAD", tnf_opaque, msgimplp, msgimplp);
5697c478bd9Sstevel@tonic-gate 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
5707c478bd9Sstevel@tonic-gate 			    ibmf_i_do_recv_cb_end, IBMF_TNF_TRACE, "",
5717c478bd9Sstevel@tonic-gate 			    "ibmf_i_do_recv_cb() exit\n");
5727c478bd9Sstevel@tonic-gate 			return;
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 		/*
5767c478bd9Sstevel@tonic-gate 		 * If the message has been marked unitialized or done
5777c478bd9Sstevel@tonic-gate 		 * release the message mutex and return
5787c478bd9Sstevel@tonic-gate 		 */
5797c478bd9Sstevel@tonic-gate 		if ((msgimplp->im_trans_state_flags &
5807c478bd9Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_DONE) ||
5817c478bd9Sstevel@tonic-gate 		    (msgimplp->im_trans_state_flags &
5827c478bd9Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_UNINIT)) {
5837c478bd9Sstevel@tonic-gate 			IBMF_MSG_DECR_REFCNT(msgimplp);
5847c478bd9Sstevel@tonic-gate 			msg_trans_state_flags = msgimplp->im_trans_state_flags;
5857c478bd9Sstevel@tonic-gate 			msg_flags = msgimplp->im_flags;
5867c478bd9Sstevel@tonic-gate 			ref_cnt = msgimplp->im_ref_count;
5877c478bd9Sstevel@tonic-gate 			mutex_exit(&msgimplp->im_mutex);
5887c478bd9Sstevel@tonic-gate 			(void) ibmf_i_repost_recv_buffer(clientp->ic_myci,
5897c478bd9Sstevel@tonic-gate 			    recv_wqep);
5907c478bd9Sstevel@tonic-gate 			/*
5917c478bd9Sstevel@tonic-gate 			 * This thread may notify the client only if the
5927c478bd9Sstevel@tonic-gate 			 * transaction is done, the message has been removed
5937c478bd9Sstevel@tonic-gate 			 * from the client's message list, and the message
5947c478bd9Sstevel@tonic-gate 			 * reference count is 0.
5957c478bd9Sstevel@tonic-gate 			 * If the transaction is done, and the message reference
5967c478bd9Sstevel@tonic-gate 			 * count = 0, there is still a possibility that a
5977c478bd9Sstevel@tonic-gate 			 * packet could arrive for the message and its reference
5987c478bd9Sstevel@tonic-gate 			 * count increased if the message is still on the list.
5997c478bd9Sstevel@tonic-gate 			 * If the message is still on the list, it will be
6007c478bd9Sstevel@tonic-gate 			 * removed by a call to ibmf_i_client_rem_msg() at
6017c478bd9Sstevel@tonic-gate 			 * the completion point of the transaction.
6027c478bd9Sstevel@tonic-gate 			 * So, the reference count should be checked after the
6037c478bd9Sstevel@tonic-gate 			 * message has been removed.
6047c478bd9Sstevel@tonic-gate 			 */
6057c478bd9Sstevel@tonic-gate 			if ((msg_trans_state_flags &
6067c478bd9Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_DONE) &&
6077c478bd9Sstevel@tonic-gate 			    !(msg_flags & IBMF_MSG_FLAGS_ON_LIST) &&
6087c478bd9Sstevel@tonic-gate 			    (ref_cnt == 0)) {
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 				ibmf_i_notify_sequence(clientp, msgimplp,
6117c478bd9Sstevel@tonic-gate 				    msg_flags);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 			}
6147c478bd9Sstevel@tonic-gate 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L3,
6157c478bd9Sstevel@tonic-gate 			    ibmf_i_do_recv_cb_error, IBMF_TNF_ERROR, "",
6167c478bd9Sstevel@tonic-gate 			    "ibmf_i_do_recv_cb(): %s, msg = %p\n",
6177c478bd9Sstevel@tonic-gate 			    tnf_string, msg,
6187c478bd9Sstevel@tonic-gate 			    "Message already marked for removal, dropping MAD",
6197c478bd9Sstevel@tonic-gate 			    tnf_opaque, msgimplp, msgimplp);
6207c478bd9Sstevel@tonic-gate 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
6217c478bd9Sstevel@tonic-gate 			    ibmf_i_do_recv_cb_end, IBMF_TNF_TRACE, "",
6227c478bd9Sstevel@tonic-gate 			    "ibmf_i_do_recv_cb() exit\n");
6237c478bd9Sstevel@tonic-gate 			return;
6247c478bd9Sstevel@tonic-gate 		}
6257c478bd9Sstevel@tonic-gate 	} else {
6267c478bd9Sstevel@tonic-gate 		/* unsolicited message packet */
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 		/*
6297c478bd9Sstevel@tonic-gate 		 * Check if the client context, the alternate QP context
6307c478bd9Sstevel@tonic-gate 		 * (if not the default QP), and the incoming MAD support RMPP
6317c478bd9Sstevel@tonic-gate 		 */
6327c478bd9Sstevel@tonic-gate 		if (ibmf_i_is_rmpp(clientp, ibmf_qp_handle) &&
6337c478bd9Sstevel@tonic-gate 		    (rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_ACTIVE)) {
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 			/* Only unsolicited packets should be data seg 1 */
6367c478bd9Sstevel@tonic-gate 			if ((rmpp_hdr->rmpp_flags &
6377c478bd9Sstevel@tonic-gate 			    IBMF_RMPP_FLAGS_FIRST_PKT) == 0) {
6387c478bd9Sstevel@tonic-gate 				(void) ibmf_i_repost_recv_buffer(
6397c478bd9Sstevel@tonic-gate 				    clientp->ic_myci, recv_wqep);
6407c478bd9Sstevel@tonic-gate 				IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L3,
6417c478bd9Sstevel@tonic-gate 				    ibmf_i_do_recv_cb_error, IBMF_TNF_TRACE, "",
6427c478bd9Sstevel@tonic-gate 				    "ibmf_i_do_recv_cb(): %s\n",
6437c478bd9Sstevel@tonic-gate 				    tnf_string, msg,
6447c478bd9Sstevel@tonic-gate 				    "unsolicited rmpp packet not first packet");
6457c478bd9Sstevel@tonic-gate 				IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
6467c478bd9Sstevel@tonic-gate 				    ibmf_i_do_recv_cb_end, IBMF_TNF_TRACE, "",
6477c478bd9Sstevel@tonic-gate 				    "ibmf_i_do_recv_cb() exit\n");
6487c478bd9Sstevel@tonic-gate 				return;
6497c478bd9Sstevel@tonic-gate 			}
6507c478bd9Sstevel@tonic-gate 		}
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 		/*
6537c478bd9Sstevel@tonic-gate 		 * Before we alloc a message context, check to see if
6547c478bd9Sstevel@tonic-gate 		 * a callback has been registered with the client
6557c478bd9Sstevel@tonic-gate 		 * for this unsolicited message.
6567c478bd9Sstevel@tonic-gate 		 * If one has been registered, increment the recvs active
6577c478bd9Sstevel@tonic-gate 		 * count to get the teardown routine to wait until
6587c478bd9Sstevel@tonic-gate 		 * this callback is complete.
6597c478bd9Sstevel@tonic-gate 		 */
6607c478bd9Sstevel@tonic-gate 		if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 			mutex_enter(&clientp->ic_mutex);
6637c478bd9Sstevel@tonic-gate 			if (clientp->ic_recv_cb == NULL) {
6647c478bd9Sstevel@tonic-gate 				mutex_exit(&clientp->ic_mutex);
6657c478bd9Sstevel@tonic-gate 				(void) ibmf_i_repost_recv_buffer(
6667c478bd9Sstevel@tonic-gate 				    clientp->ic_myci, recv_wqep);
6677c478bd9Sstevel@tonic-gate 				IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
6687c478bd9Sstevel@tonic-gate 				    ibmf_i_do_recv_cb_error, IBMF_TNF_ERROR, "",
6697c478bd9Sstevel@tonic-gate 				    "ibmf_i_do_recv_cb(): %s, class %x\n",
6707c478bd9Sstevel@tonic-gate 				    tnf_string, msg,
6717c478bd9Sstevel@tonic-gate 				    "ibmf_tear_down_recv_cb already occurred",
6727c478bd9Sstevel@tonic-gate 				    tnf_opaque, class,
6737c478bd9Sstevel@tonic-gate 				    clientp->ic_client_info.client_class);
6747c478bd9Sstevel@tonic-gate 				IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
6757c478bd9Sstevel@tonic-gate 				    ibmf_i_do_recv_cb_end, IBMF_TNF_TRACE, "",
6767c478bd9Sstevel@tonic-gate 				    "ibmf_i_do_recv_cb() exit\n");
6777c478bd9Sstevel@tonic-gate 				return;
6787c478bd9Sstevel@tonic-gate 			}
6797c478bd9Sstevel@tonic-gate 			IBMF_RECV_CB_SETUP(clientp);
6807c478bd9Sstevel@tonic-gate 			mutex_exit(&clientp->ic_mutex);
6817c478bd9Sstevel@tonic-gate 		} else {
6827c478bd9Sstevel@tonic-gate 			qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 			mutex_enter(&qpp->isq_mutex);
6857c478bd9Sstevel@tonic-gate 			if (qpp->isq_recv_cb == NULL) {
6867c478bd9Sstevel@tonic-gate 				mutex_exit(&qpp->isq_mutex);
6877c478bd9Sstevel@tonic-gate 				(void) ibmf_i_repost_recv_buffer(
6887c478bd9Sstevel@tonic-gate 				    clientp->ic_myci, recv_wqep);
6897c478bd9Sstevel@tonic-gate 				IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
6907c478bd9Sstevel@tonic-gate 				    ibmf_i_do_recv_cb_error, IBMF_TNF_ERROR, "",
6917c478bd9Sstevel@tonic-gate 				    "ibmf_i_do_recv_cb(): %s, class %x\n",
6927c478bd9Sstevel@tonic-gate 				    tnf_string, msg,
6937c478bd9Sstevel@tonic-gate 				    "ibmf_tear_down_recv_cb already occurred",
6947c478bd9Sstevel@tonic-gate 				    tnf_opaque, class,
6957c478bd9Sstevel@tonic-gate 				    clientp->ic_client_info.client_class);
6967c478bd9Sstevel@tonic-gate 				IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
6977c478bd9Sstevel@tonic-gate 				    ibmf_i_do_recv_cb_end, IBMF_TNF_TRACE, "",
6987c478bd9Sstevel@tonic-gate 				    "ibmf_i_do_recv_cb() exit\n");
6997c478bd9Sstevel@tonic-gate 				return;
7007c478bd9Sstevel@tonic-gate 			}
7017c478bd9Sstevel@tonic-gate 			IBMF_ALT_RECV_CB_SETUP(qpp);
7027c478bd9Sstevel@tonic-gate 			mutex_exit(&qpp->isq_mutex);
7037c478bd9Sstevel@tonic-gate 		}
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 		/*
7067c478bd9Sstevel@tonic-gate 		 * Allocate a message context
7077c478bd9Sstevel@tonic-gate 		 */
7087c478bd9Sstevel@tonic-gate 		msgimplp = (ibmf_msg_impl_t *)kmem_zalloc(
7097c478bd9Sstevel@tonic-gate 		    sizeof (ibmf_msg_impl_t), KM_NOSLEEP);
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgimplp))
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 		/* If we cannot allocate memory, drop the packet and clean up */
7147c478bd9Sstevel@tonic-gate 		if (msgimplp == NULL) {
7157c478bd9Sstevel@tonic-gate 			if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
7167c478bd9Sstevel@tonic-gate 				mutex_enter(&clientp->ic_mutex);
7177c478bd9Sstevel@tonic-gate 				IBMF_RECV_CB_CLEANUP(clientp);
7187c478bd9Sstevel@tonic-gate 				mutex_exit(&clientp->ic_mutex);
7197c478bd9Sstevel@tonic-gate 			} else {
7207c478bd9Sstevel@tonic-gate 				qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
7217c478bd9Sstevel@tonic-gate 				mutex_enter(&qpp->isq_mutex);
7227c478bd9Sstevel@tonic-gate 				IBMF_ALT_RECV_CB_CLEANUP(qpp);
7237c478bd9Sstevel@tonic-gate 				mutex_exit(&qpp->isq_mutex);
7247c478bd9Sstevel@tonic-gate 			}
7257c478bd9Sstevel@tonic-gate 			(void) ibmf_i_repost_recv_buffer(clientp->ic_myci,
7267c478bd9Sstevel@tonic-gate 			    recv_wqep);
7277c478bd9Sstevel@tonic-gate 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
7287c478bd9Sstevel@tonic-gate 			    ibmf_i_do_recv_cb_error, IBMF_TNF_ERROR, "",
7297c478bd9Sstevel@tonic-gate 			    "ibmf_i_do_recv_cb(): %s\n", tnf_string, msg,
7307c478bd9Sstevel@tonic-gate 			    "mem allocation failure");
7317c478bd9Sstevel@tonic-gate 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
7327c478bd9Sstevel@tonic-gate 			    ibmf_i_do_recv_cb_end, IBMF_TNF_TRACE, "",
7337c478bd9Sstevel@tonic-gate 			    "ibmf_i_do_recv_cb() exit\n");
7347c478bd9Sstevel@tonic-gate 			return;
7357c478bd9Sstevel@tonic-gate 		}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 		/* Get the port's base LID if it's not in the client context */
7387c478bd9Sstevel@tonic-gate 		if ((clientp->ic_base_lid == 0) &&
7397c478bd9Sstevel@tonic-gate 		    (clientp->ic_qp->iq_qp_num != 0)) {
7407c478bd9Sstevel@tonic-gate 			(void) ibt_get_port_state_byguid(
7417c478bd9Sstevel@tonic-gate 			    clientp->ic_client_info.ci_guid,
7427c478bd9Sstevel@tonic-gate 			    clientp->ic_client_info.port_num, NULL,
7437c478bd9Sstevel@tonic-gate 			    &clientp->ic_base_lid);
7447c478bd9Sstevel@tonic-gate 			if (clientp->ic_base_lid == 0) {
7457c478bd9Sstevel@tonic-gate 				IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
7467c478bd9Sstevel@tonic-gate 				    ibmf_i_do_recv_cb_error, IBMF_TNF_ERROR, "",
7477c478bd9Sstevel@tonic-gate 				    "ibmf_i_do_recv_cb(): %s\n",
7487c478bd9Sstevel@tonic-gate 				    tnf_string, msg, "base_lid is undefined");
7497c478bd9Sstevel@tonic-gate 			}
7507c478bd9Sstevel@tonic-gate 		}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 		/* Set up address information */
7537c478bd9Sstevel@tonic-gate 		addrinfo.ia_local_lid = clientp->ic_base_lid +
7547c478bd9Sstevel@tonic-gate 		    wcp->wc_path_bits;
7557c478bd9Sstevel@tonic-gate 		addrinfo.ia_remote_lid = wcp->wc_slid;
7567c478bd9Sstevel@tonic-gate 		addrinfo.ia_remote_qno = wcp->wc_qpn;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 		/* Get the pkey, including the correct partiton membership */
7597c478bd9Sstevel@tonic-gate 		if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
7607c478bd9Sstevel@tonic-gate 			if (recv_wqep->recv_qpp->iq_qp_num == IBMF_QP1_NUM) {
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 				/*
7637c478bd9Sstevel@tonic-gate 				 * here too we expect the pkey index in the work
7647c478bd9Sstevel@tonic-gate 				 * completion belongs to a pkey in the pkey
7657c478bd9Sstevel@tonic-gate 				 * table
7667c478bd9Sstevel@tonic-gate 				 */
7677c478bd9Sstevel@tonic-gate 				status = ibmf_i_pkey_ix_to_key(
7687c478bd9Sstevel@tonic-gate 				    clientp->ic_myci, recv_wqep->recv_port_num,
7697c478bd9Sstevel@tonic-gate 				    wcp->wc_pkey_ix, &addrinfo.ia_p_key);
7707c478bd9Sstevel@tonic-gate 				if (status != IBMF_SUCCESS) {
7717c478bd9Sstevel@tonic-gate 					IBMF_TRACE_2(IBMF_TNF_NODEBUG,
7727c478bd9Sstevel@tonic-gate 					    DPRINT_L1, ibmf_i_do_recv_cb_error,
7737c478bd9Sstevel@tonic-gate 					    IBMF_TNF_ERROR, "",
7747c478bd9Sstevel@tonic-gate 					    "ibmf_i_do_recv_cb(): "
7757c478bd9Sstevel@tonic-gate 					    "get_pkey failed for ix %d,"
7767c478bd9Sstevel@tonic-gate 					    "status = %d\n", tnf_uint,
7777c478bd9Sstevel@tonic-gate 					    pkeyix, wcp->wc_pkey_ix, tnf_uint,
7787c478bd9Sstevel@tonic-gate 					    ibmf_status, status);
7797c478bd9Sstevel@tonic-gate 					mutex_enter(&clientp->ic_mutex);
7807c478bd9Sstevel@tonic-gate 					IBMF_RECV_CB_CLEANUP(clientp);
7817c478bd9Sstevel@tonic-gate 					mutex_exit(&clientp->ic_mutex);
7827c478bd9Sstevel@tonic-gate 					(void) ibmf_i_repost_recv_buffer(
7837c478bd9Sstevel@tonic-gate 					    clientp->ic_myci, recv_wqep);
7847c478bd9Sstevel@tonic-gate 					mutex_destroy(&msgimplp->im_mutex);
7857c478bd9Sstevel@tonic-gate 					cv_destroy(&msgimplp->im_trans_cv);
7867c478bd9Sstevel@tonic-gate 					kmem_free(msgimplp,
7877c478bd9Sstevel@tonic-gate 					    sizeof (ibmf_msg_impl_t));
7887c478bd9Sstevel@tonic-gate 					IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
7897c478bd9Sstevel@tonic-gate 					    ibmf_i_do_recv_cb_end,
7907c478bd9Sstevel@tonic-gate 					    IBMF_TNF_TRACE, "",
7917c478bd9Sstevel@tonic-gate 					    "ibmf_i_do_recv_cb() exit\n");
7927c478bd9Sstevel@tonic-gate 					return;
7937c478bd9Sstevel@tonic-gate 				}
7947c478bd9Sstevel@tonic-gate 			}
7957c478bd9Sstevel@tonic-gate 			addrinfo.ia_q_key = IBMF_MGMT_Q_KEY;
7967c478bd9Sstevel@tonic-gate 		} else {
7977c478bd9Sstevel@tonic-gate 			qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 			/* For alternate QPs, the pkey is in the QP context */
8007c478bd9Sstevel@tonic-gate 			mutex_enter(&qpp->isq_mutex);
8017c478bd9Sstevel@tonic-gate 			addrinfo.ia_p_key = qpp->isq_pkey;
8027c478bd9Sstevel@tonic-gate 			addrinfo.ia_q_key = qpp->isq_qkey;
8037c478bd9Sstevel@tonic-gate 			mutex_exit(&qpp->isq_mutex);
8047c478bd9Sstevel@tonic-gate 		}
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 		addrinfo.ia_service_level = wcp->wc_sl;
8077c478bd9Sstevel@tonic-gate 		msgimplp->im_local_addr = addrinfo;
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 		/* Initialize the message context */
8107c478bd9Sstevel@tonic-gate 		cv_init(&msgimplp->im_trans_cv, NULL, CV_DRIVER, NULL);
8117c478bd9Sstevel@tonic-gate 		mutex_init(&msgimplp->im_mutex, NULL, MUTEX_DRIVER, NULL);
8127c478bd9Sstevel@tonic-gate 		msgimplp->im_client = clientp;
8137c478bd9Sstevel@tonic-gate 		msgimplp->im_qp_hdl = ibmf_qp_handle;
8147c478bd9Sstevel@tonic-gate 		msgimplp->im_flags = 0;
8157c478bd9Sstevel@tonic-gate 		msgimplp->im_unsolicited = B_TRUE;
8167c478bd9Sstevel@tonic-gate 		msgimplp->im_tid = b2h64(mad_hdr->TransactionID);
8177c478bd9Sstevel@tonic-gate 		msgimplp->im_mgt_class = mad_hdr->MgmtClass;
8187c478bd9Sstevel@tonic-gate 		msgimplp->im_retrans.retrans_retries = IBMF_RETRANS_DEF_RETRIES;
8197c478bd9Sstevel@tonic-gate 		msgimplp->im_retrans.retrans_rtv = IBMF_RETRANS_DEF_RTV;
8207c478bd9Sstevel@tonic-gate 		msgimplp->im_retrans.retrans_rttv = IBMF_RETRANS_DEF_RTTV;
8217c478bd9Sstevel@tonic-gate 		msgimplp->im_retrans.retrans_trans_to =
8227c478bd9Sstevel@tonic-gate 		    IBMF_RETRANS_DEF_TRANS_TO;
8237c478bd9Sstevel@tonic-gate 		msgimplp->im_rmpp_ctx.rmpp_state = IBMF_RMPP_STATE_UNDEFINED;
8247c478bd9Sstevel@tonic-gate 		msgimplp->im_rmpp_ctx.rmpp_respt = IBMF_RMPP_DEFAULT_RRESPT;
8257c478bd9Sstevel@tonic-gate 		IBMF_MSG_INCR_REFCNT(msgimplp);
8267c478bd9Sstevel@tonic-gate 		msgimplp->im_trans_state_flags = IBMF_TRANS_STATE_FLAG_UNINIT;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 		/*
8297c478bd9Sstevel@tonic-gate 		 * Initialize (and possibly allocate) the IBT UD destination
8307c478bd9Sstevel@tonic-gate 		 * address handle.
8317c478bd9Sstevel@tonic-gate 		 */
8327c478bd9Sstevel@tonic-gate 		status = ibmf_i_alloc_ud_dest(clientp, msgimplp,
8337c478bd9Sstevel@tonic-gate 		    &msgimplp->im_ud_dest, B_FALSE);
8347c478bd9Sstevel@tonic-gate 		if (status != IBMF_SUCCESS) {
8357c478bd9Sstevel@tonic-gate 			if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
8367c478bd9Sstevel@tonic-gate 				mutex_enter(&clientp->ic_mutex);
8377c478bd9Sstevel@tonic-gate 				IBMF_RECV_CB_CLEANUP(clientp);
8387c478bd9Sstevel@tonic-gate 				mutex_exit(&clientp->ic_mutex);
8397c478bd9Sstevel@tonic-gate 			} else {
8407c478bd9Sstevel@tonic-gate 				qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
8417c478bd9Sstevel@tonic-gate 				mutex_enter(&qpp->isq_mutex);
8427c478bd9Sstevel@tonic-gate 				IBMF_ALT_RECV_CB_CLEANUP(qpp);
8437c478bd9Sstevel@tonic-gate 				mutex_exit(&qpp->isq_mutex);
8447c478bd9Sstevel@tonic-gate 			}
8457c478bd9Sstevel@tonic-gate 			(void) ibmf_i_repost_recv_buffer(clientp->ic_myci,
8467c478bd9Sstevel@tonic-gate 			    recv_wqep);
8477c478bd9Sstevel@tonic-gate 			mutex_destroy(&msgimplp->im_mutex);
8487c478bd9Sstevel@tonic-gate 			cv_destroy(&msgimplp->im_trans_cv);
8497c478bd9Sstevel@tonic-gate 			kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
8507c478bd9Sstevel@tonic-gate 			IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
8517c478bd9Sstevel@tonic-gate 			    ibmf_i_do_recv_cb_error, IBMF_TNF_ERROR, "",
8527c478bd9Sstevel@tonic-gate 			    "ibmf_i_do_recv_cb(): %s, status = %d\n",
8537c478bd9Sstevel@tonic-gate 			    tnf_string, msg, "alloc ah failed", tnf_uint,
8547c478bd9Sstevel@tonic-gate 			    ibmf_status, status);
8557c478bd9Sstevel@tonic-gate 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
8567c478bd9Sstevel@tonic-gate 			    ibmf_i_do_recv_cb_end, IBMF_TNF_TRACE, "",
8577c478bd9Sstevel@tonic-gate 			    "ibmf_i_do_recv_cb() exit\n");
8587c478bd9Sstevel@tonic-gate 			return;
8597c478bd9Sstevel@tonic-gate 		}
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msgimplp))
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 		/* add message to client's list */
8647c478bd9Sstevel@tonic-gate 		ibmf_i_client_add_msg(clientp, msgimplp);
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 		mutex_enter(&msgimplp->im_mutex);
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 		/* no one should have touched our state */
8697c478bd9Sstevel@tonic-gate 		ASSERT(msgimplp->im_trans_state_flags ==
8707c478bd9Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_UNINIT);
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 		/* transition out of uninit state */
8737c478bd9Sstevel@tonic-gate 		msgimplp->im_trans_state_flags = IBMF_TRANS_STATE_FLAG_INIT;
8747c478bd9Sstevel@tonic-gate 	}
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	/* fill in the grh with the contents of the recv wqe */
8777c478bd9Sstevel@tonic-gate 	if (grhpresent == B_TRUE) {
8787c478bd9Sstevel@tonic-gate 		uint32_t tmp32;
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 		msgimplp->im_msg_flags |= IBMF_MSG_FLAGS_GLOBAL_ADDRESS;
8817c478bd9Sstevel@tonic-gate 		ib_grh = (ib_grh_t *)recv_wqep->recv_mem;
8827c478bd9Sstevel@tonic-gate 		msgimplp->im_global_addr.ig_sender_gid.gid_prefix =
8837c478bd9Sstevel@tonic-gate 		    b2h64(ib_grh->SGID.gid_prefix);
8847c478bd9Sstevel@tonic-gate 		msgimplp->im_global_addr.ig_sender_gid.gid_guid =
8857c478bd9Sstevel@tonic-gate 		    b2h64(ib_grh->SGID.gid_guid);
8867c478bd9Sstevel@tonic-gate 		msgimplp->im_global_addr.ig_recver_gid.gid_prefix =
8877c478bd9Sstevel@tonic-gate 		    b2h64(ib_grh->DGID.gid_prefix);
8887c478bd9Sstevel@tonic-gate 		msgimplp->im_global_addr.ig_recver_gid.gid_guid =
8897c478bd9Sstevel@tonic-gate 		    b2h64(ib_grh->DGID.gid_guid);
8907c478bd9Sstevel@tonic-gate 		/*
8917c478bd9Sstevel@tonic-gate 		 * swap to get byte order back to wire format on little endian
8927c478bd9Sstevel@tonic-gate 		 * systems so we can apply the GRH masks
8937c478bd9Sstevel@tonic-gate 		 */
8947c478bd9Sstevel@tonic-gate 		tmp32 = b2h32(ib_grh->IPVer_TC_Flow);
8957c478bd9Sstevel@tonic-gate 		msgimplp->im_global_addr.ig_flow_label =
8967c478bd9Sstevel@tonic-gate 		    tmp32 & IB_GRH_FLOW_LABEL_MASK;
8977c478bd9Sstevel@tonic-gate 		msgimplp->im_global_addr.ig_tclass =
8987c478bd9Sstevel@tonic-gate 		    (tmp32 & IB_GRH_TCLASS_MASK) >> 20;
8997c478bd9Sstevel@tonic-gate 		msgimplp->im_global_addr.ig_hop_limit =
9007c478bd9Sstevel@tonic-gate 		    ib_grh->HopLmt;
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/* Perform RMPP or non-RMPP processing */
9047c478bd9Sstevel@tonic-gate 	if (ibmf_i_is_rmpp(clientp, ibmf_qp_handle) &&
9057c478bd9Sstevel@tonic-gate 	    (rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_ACTIVE)) {
9067c478bd9Sstevel@tonic-gate 		IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L3,
9077c478bd9Sstevel@tonic-gate 		    ibmf_i_do_recv_cb, IBMF_TNF_TRACE, "",
9087c478bd9Sstevel@tonic-gate 		    "ibmf_i_do_recv_cb(): %s, tid = %016" PRIx64 ","
9097c478bd9Sstevel@tonic-gate 		    "flags = 0x%x rmpp_type = %d, rmpp_segnum = %d\n",
9107c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Handling rmpp MAD",
9117c478bd9Sstevel@tonic-gate 		    tnf_opaque, tid, b2h64(mad_hdr->TransactionID),
9127c478bd9Sstevel@tonic-gate 		    tnf_opaque, flags, rmpp_hdr->rmpp_flags,
9137c478bd9Sstevel@tonic-gate 		    tnf_opaque, type, rmpp_hdr->rmpp_type,
9147c478bd9Sstevel@tonic-gate 		    tnf_opaque, segment, b2h32(rmpp_hdr->rmpp_segnum));
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 		/*
9177c478bd9Sstevel@tonic-gate 		 * Set the RMPP state to "receiver active" on the first packet
9187c478bd9Sstevel@tonic-gate 		 * of all RMPP message, and initialize the
9197c478bd9Sstevel@tonic-gate 		 * the expected segment to 1.
9207c478bd9Sstevel@tonic-gate 		 */
9217c478bd9Sstevel@tonic-gate 		if ((msgimplp->im_rmpp_ctx.rmpp_state ==
9227c478bd9Sstevel@tonic-gate 		    IBMF_RMPP_STATE_UNDEFINED) &&
9237c478bd9Sstevel@tonic-gate 		    (rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_FIRST_PKT)) {
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 			msgimplp->im_flags |= IBMF_MSG_FLAGS_RECV_RMPP;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 			if (rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_DATA) {
9287c478bd9Sstevel@tonic-gate 				msgimplp->im_rmpp_ctx.rmpp_state =
9297c478bd9Sstevel@tonic-gate 				    IBMF_RMPP_STATE_RECEVR_ACTIVE;
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 				IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
9327c478bd9Sstevel@tonic-gate 				    ibmf_i_do_recv_cb, IBMF_TNF_TRACE, "",
9337c478bd9Sstevel@tonic-gate 				    "ibmf_i_do_recv_cb(): %s, msgimplp = %p\n",
9347c478bd9Sstevel@tonic-gate 				    tnf_string, msg, "first RMPP pkt received",
9357c478bd9Sstevel@tonic-gate 				    tnf_opaque, msgimplp, msgimplp);
9367c478bd9Sstevel@tonic-gate 			}
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 			msgimplp->im_rmpp_ctx.rmpp_es = 1;
9397c478bd9Sstevel@tonic-gate 			msgimplp->im_rmpp_ctx.rmpp_wl = 1;
9407c478bd9Sstevel@tonic-gate 			msgimplp->im_rmpp_ctx.rmpp_wf = 1;
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 			/* set double-sided transfer flag for certain methods */
9437c478bd9Sstevel@tonic-gate 			if (mad_hdr->R_Method == SA_SUBN_ADM_GET_MULTI)
9447c478bd9Sstevel@tonic-gate 				msgimplp->im_rmpp_ctx.rmpp_is_ds = B_TRUE;
9457c478bd9Sstevel@tonic-gate 			else	msgimplp->im_rmpp_ctx.rmpp_is_ds = B_FALSE;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 			msgimplp->im_trans_state_flags |=
9487c478bd9Sstevel@tonic-gate 			    IBMF_TRANS_STATE_FLAG_RECV_ACTIVE;
9497c478bd9Sstevel@tonic-gate 		}
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 		if (rmpp_hdr->rmpp_resp_time != IBMF_RMPP_DEFAULT_RRESPT) {
9527c478bd9Sstevel@tonic-gate 			msgimplp->im_retrans.retrans_rtv =
9537c478bd9Sstevel@tonic-gate 			    1 << rmpp_hdr->rmpp_resp_time;
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 			IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
9567c478bd9Sstevel@tonic-gate 			    ibmf_i_do_recv_cb, IBMF_TNF_TRACE, "",
9577c478bd9Sstevel@tonic-gate 			    "ibmf_i_do_recv_cb: %s, resp_time %d\n",
9587c478bd9Sstevel@tonic-gate 			    tnf_string, msg, "new resp time received",
9597c478bd9Sstevel@tonic-gate 			    tnf_uint, resp_time, rmpp_hdr->rmpp_resp_time);
9607c478bd9Sstevel@tonic-gate 		}
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 		ibmf_i_handle_rmpp(clientp, ibmf_qp_handle, msgimplp,
9637c478bd9Sstevel@tonic-gate 		    (uchar_t *)((uintptr_t)recv_wqep->recv_mem +
9647c478bd9Sstevel@tonic-gate 		    sizeof (ib_grh_t)));
9657c478bd9Sstevel@tonic-gate 	} else {
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 		msgimplp->im_trans_state_flags |=
9687c478bd9Sstevel@tonic-gate 		    IBMF_TRANS_STATE_FLAG_RECV_ACTIVE;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 		ibmf_i_handle_non_rmpp(clientp, msgimplp,
9717c478bd9Sstevel@tonic-gate 		    (uchar_t *)((uintptr_t)recv_wqep->recv_mem +
9727c478bd9Sstevel@tonic-gate 		    sizeof (ib_grh_t)));
9737c478bd9Sstevel@tonic-gate 	}
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	msg_rp_unset_id = msg_tr_unset_id = msg_rp_set_id = msg_tr_set_id = 0;
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	/*
9787c478bd9Sstevel@tonic-gate 	 * Save the transaction state flags and the timeout IDs
9797c478bd9Sstevel@tonic-gate 	 * before releasing the mutex as they may be changed after that.
9807c478bd9Sstevel@tonic-gate 	 */
9817c478bd9Sstevel@tonic-gate 	msg_trans_state_flags = msgimplp->im_trans_state_flags;
9827c478bd9Sstevel@tonic-gate 	msg_flags = msgimplp->im_flags;
9837c478bd9Sstevel@tonic-gate 	msg_rp_unset_id = msgimplp->im_rp_unset_timeout_id;
9847c478bd9Sstevel@tonic-gate 	msg_tr_unset_id = msgimplp->im_tr_unset_timeout_id;
9857c478bd9Sstevel@tonic-gate 	msgimplp->im_rp_unset_timeout_id = 0;
9867c478bd9Sstevel@tonic-gate 	msgimplp->im_tr_unset_timeout_id = 0;
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	/*
9897c478bd9Sstevel@tonic-gate 	 * Decrement the message reference count
9907c478bd9Sstevel@tonic-gate 	 * This count was incremented either when the message was found
9917c478bd9Sstevel@tonic-gate 	 * on the client's message list (ibmf_i_find_msg()) or when
9927c478bd9Sstevel@tonic-gate 	 * a new message was created for unsolicited data
9937c478bd9Sstevel@tonic-gate 	 */
9947c478bd9Sstevel@tonic-gate 	IBMF_MSG_DECR_REFCNT(msgimplp);
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	if (msg_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE) {
9977c478bd9Sstevel@tonic-gate 		if (msgimplp->im_rp_timeout_id != 0) {
9987c478bd9Sstevel@tonic-gate 			msg_rp_set_id = msgimplp->im_rp_timeout_id;
9997c478bd9Sstevel@tonic-gate 			msgimplp->im_rp_timeout_id = 0;
10007c478bd9Sstevel@tonic-gate 		}
10017c478bd9Sstevel@tonic-gate 		if (msgimplp->im_tr_timeout_id != 0) {
10027c478bd9Sstevel@tonic-gate 			msg_tr_set_id = msgimplp->im_tr_timeout_id;
10037c478bd9Sstevel@tonic-gate 			msgimplp->im_tr_timeout_id = 0;
10047c478bd9Sstevel@tonic-gate 		}
10057c478bd9Sstevel@tonic-gate 	}
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	mutex_exit(&msgimplp->im_mutex);
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	/*
10107c478bd9Sstevel@tonic-gate 	 * Call untimeout() after releasing the lock because the
10117c478bd9Sstevel@tonic-gate 	 * lock is acquired in the timeout handler as well. Untimeout()
10127c478bd9Sstevel@tonic-gate 	 * does not return until the timeout handler has run, if it already
10137c478bd9Sstevel@tonic-gate 	 * fired, which would result in a deadlock if we did not first
10147c478bd9Sstevel@tonic-gate 	 * release the im_mutex lock.
10157c478bd9Sstevel@tonic-gate 	 */
10167c478bd9Sstevel@tonic-gate 	if (msg_rp_unset_id != 0) {
10177c478bd9Sstevel@tonic-gate 		(void) untimeout(msg_rp_unset_id);
10187c478bd9Sstevel@tonic-gate 	}
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	if (msg_tr_unset_id != 0) {
10217c478bd9Sstevel@tonic-gate 		(void) untimeout(msg_tr_unset_id);
10227c478bd9Sstevel@tonic-gate 	}
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	if (msg_rp_set_id != 0) {
10257c478bd9Sstevel@tonic-gate 		(void) untimeout(msg_rp_set_id);
10267c478bd9Sstevel@tonic-gate 	}
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	if (msg_tr_set_id != 0) {
10297c478bd9Sstevel@tonic-gate 		(void) untimeout(msg_tr_set_id);
10307c478bd9Sstevel@tonic-gate 	}
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	/* Increment the kstats for number of messages received */
10337c478bd9Sstevel@tonic-gate 	mutex_enter(&clientp->ic_kstat_mutex);
10347c478bd9Sstevel@tonic-gate 	IBMF_ADD32_KSTATS(clientp, msgs_received, 1);
10357c478bd9Sstevel@tonic-gate 	mutex_exit(&clientp->ic_kstat_mutex);
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	/*
10387c478bd9Sstevel@tonic-gate 	 * now that we are done gleaning all we want out of the receive
10397c478bd9Sstevel@tonic-gate 	 * completion, we repost the receive request.
10407c478bd9Sstevel@tonic-gate 	 */
10417c478bd9Sstevel@tonic-gate 	(void) ibmf_i_repost_recv_buffer(clientp->ic_myci, recv_wqep);
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 	/*
10447c478bd9Sstevel@tonic-gate 	 * If the transaction flags indicate a completed transaction,
10457c478bd9Sstevel@tonic-gate 	 * notify the client
10467c478bd9Sstevel@tonic-gate 	 */
10477c478bd9Sstevel@tonic-gate 	if (msg_trans_state_flags & IBMF_TRANS_STATE_FLAG_DONE) {
10487c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L3,
10497c478bd9Sstevel@tonic-gate 		    ibmf_i_do_recv_cb, IBMF_TNF_TRACE, "",
10507c478bd9Sstevel@tonic-gate 		    "ibmf_i_do_recv_cb(): %s, msgimplp = %p\n",
10517c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "notifying client",
10527c478bd9Sstevel@tonic-gate 		    tnf_opaque, msgimplp, msgimplp);
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 		/* Remove the message from the client's message list */
10557c478bd9Sstevel@tonic-gate 		ibmf_i_client_rem_msg(clientp, msgimplp, &ref_cnt);
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 		/*
10587c478bd9Sstevel@tonic-gate 		 * Notify the client if the message reference count is zero.
10597c478bd9Sstevel@tonic-gate 		 * At this point, we know that the transaction is done and
10607c478bd9Sstevel@tonic-gate 		 * the message has been removed from the client's message list.
10617c478bd9Sstevel@tonic-gate 		 * So, we only need to make sure the reference count is zero
10627c478bd9Sstevel@tonic-gate 		 * before notifying the client.
10637c478bd9Sstevel@tonic-gate 		 */
10647c478bd9Sstevel@tonic-gate 		if (ref_cnt == 0) {
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 			ibmf_i_notify_sequence(clientp, msgimplp, msg_flags);
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 		}
10697c478bd9Sstevel@tonic-gate 	}
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
10727c478bd9Sstevel@tonic-gate 	    ibmf_i_do_recv_cb_end, IBMF_TNF_TRACE, "",
10737c478bd9Sstevel@tonic-gate 	    "ibmf_i_do_recv_cb() exit, msgimplp = %p\n",
10747c478bd9Sstevel@tonic-gate 	    tnf_opaque, msgimplp, msgimplp);
10757c478bd9Sstevel@tonic-gate }
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate /*
10787c478bd9Sstevel@tonic-gate  * ibmf_i_handle_non_rmpp():
10797c478bd9Sstevel@tonic-gate  *	Handle non-RMPP processing of an incoming IB packet
10807c478bd9Sstevel@tonic-gate  */
10817c478bd9Sstevel@tonic-gate void
ibmf_i_handle_non_rmpp(ibmf_client_t * clientp,ibmf_msg_impl_t * msgimplp,uchar_t * mad)10827c478bd9Sstevel@tonic-gate ibmf_i_handle_non_rmpp(ibmf_client_t *clientp, ibmf_msg_impl_t *msgimplp,
10837c478bd9Sstevel@tonic-gate     uchar_t *mad)
10847c478bd9Sstevel@tonic-gate {
10857c478bd9Sstevel@tonic-gate 	ibmf_rmpp_ctx_t	*rmpp_ctx = &msgimplp->im_rmpp_ctx;
10867c478bd9Sstevel@tonic-gate 	ib_mad_hdr_t	*mad_hdr;
10877c478bd9Sstevel@tonic-gate 	size_t		offset;
10887c478bd9Sstevel@tonic-gate 	uchar_t		*msgbufp;
10897c478bd9Sstevel@tonic-gate 	uint32_t	clhdrsz, clhdroff;
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L4,
10927c478bd9Sstevel@tonic-gate 	    ibmf_i_handle_non_rmpp_start, IBMF_TNF_TRACE, "",
10937c478bd9Sstevel@tonic-gate 	    "ibmf_i_handle_non_rmpp(): clientp = 0x%p, "
10947c478bd9Sstevel@tonic-gate 	    "msgp = 0x%p, madp = 0x%p\n", tnf_opaque, clientp, clientp,
10957c478bd9Sstevel@tonic-gate 	    tnf_opaque, msg, msgimplp, tnf_opaque, mad, mad);
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	/* Get the MAD header */
11007c478bd9Sstevel@tonic-gate 	mad_hdr = (ib_mad_hdr_t *)mad;
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	/* Determine the MAD's class header size */
11037c478bd9Sstevel@tonic-gate 	ibmf_i_mgt_class_to_hdr_sz_off(mad_hdr->MgmtClass, &clhdrsz, &clhdroff);
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	/* Allocate the message receive buffers if not already allocated */
11067c478bd9Sstevel@tonic-gate 	if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 		msgimplp->im_msgbufs_recv.im_bufs_mad_hdr =
11097c478bd9Sstevel@tonic-gate 		    (ib_mad_hdr_t *)kmem_zalloc(IBMF_MAD_SIZE, KM_NOSLEEP);
11107c478bd9Sstevel@tonic-gate 		if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 			IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
11137c478bd9Sstevel@tonic-gate 			    ibmf_i_handle_non_rmpp_err, IBMF_TNF_ERROR, "",
11147c478bd9Sstevel@tonic-gate 			    "ibmf_i_handle_non_rmpp(): %s\n", tnf_string, msg,
11157c478bd9Sstevel@tonic-gate 			    "mem allocation failure (non-rmpp payload)");
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 			IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
11187c478bd9Sstevel@tonic-gate 			    ibmf_i_handle_non_rmpp_end, IBMF_TNF_TRACE, "",
11197c478bd9Sstevel@tonic-gate 			    "ibmf_i_handle_non_rmpp() exit\n");
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 			return;
11227c478bd9Sstevel@tonic-gate 		}
11237c478bd9Sstevel@tonic-gate 		mutex_enter(&clientp->ic_kstat_mutex);
11247c478bd9Sstevel@tonic-gate 		IBMF_ADD32_KSTATS(clientp, recv_bufs_alloced, 1);
11257c478bd9Sstevel@tonic-gate 		mutex_exit(&clientp->ic_kstat_mutex);
11267c478bd9Sstevel@tonic-gate 	}
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	/* Get a pointer to the MAD location in the receive buffer */
11297c478bd9Sstevel@tonic-gate 	msgbufp = (uchar_t *)msgimplp->im_msgbufs_recv.im_bufs_mad_hdr;
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	/* Copy the incoming MAD into the receive buffer */
11327c478bd9Sstevel@tonic-gate 	bcopy((const void *)mad, (void *)msgbufp, IBMF_MAD_SIZE);
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	/* Get the offset of the class header */
11357c478bd9Sstevel@tonic-gate 	offset = sizeof (ib_mad_hdr_t) + clhdroff;
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	/* initialize class header pointer */
11387c478bd9Sstevel@tonic-gate 	if (clhdrsz == 0) {
11397c478bd9Sstevel@tonic-gate 		msgimplp->im_msgbufs_recv.im_bufs_cl_hdr = NULL;
11407c478bd9Sstevel@tonic-gate 	} else {
11417c478bd9Sstevel@tonic-gate 		msgimplp->im_msgbufs_recv.im_bufs_cl_hdr =
11427c478bd9Sstevel@tonic-gate 		    (void *)(msgbufp + offset);
11437c478bd9Sstevel@tonic-gate 	}
11447c478bd9Sstevel@tonic-gate 	msgimplp->im_msgbufs_recv.im_bufs_cl_hdr_len = clhdrsz;
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	offset += clhdrsz;
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	/* initialize data area pointer */
11497c478bd9Sstevel@tonic-gate 	msgimplp->im_msgbufs_recv.im_bufs_cl_data = (void *)(msgbufp + offset);
11507c478bd9Sstevel@tonic-gate 	msgimplp->im_msgbufs_recv.im_bufs_cl_data_len = IBMF_MAD_SIZE -
11517c478bd9Sstevel@tonic-gate 	    sizeof (ib_mad_hdr_t) - clhdroff - clhdrsz;
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	rmpp_ctx->rmpp_state = IBMF_RMPP_STATE_DONE;
11547c478bd9Sstevel@tonic-gate 	ibmf_i_terminate_transaction(clientp, msgimplp, IBMF_SUCCESS);
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,	ibmf_i_handle_non_rmpp_end,
11577c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_handle_non_rmpp() exit\n");
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate /*
11617c478bd9Sstevel@tonic-gate  * ibmf_i_repost_recv_buffer():
11627c478bd9Sstevel@tonic-gate  *	Repost a WQE to the RQ after processing it
11637c478bd9Sstevel@tonic-gate  */
11647c478bd9Sstevel@tonic-gate /* ARGSUSED */
11657c478bd9Sstevel@tonic-gate int
ibmf_i_repost_recv_buffer(ibmf_ci_t * cip,ibmf_recv_wqe_t * recv_wqep)11667c478bd9Sstevel@tonic-gate ibmf_i_repost_recv_buffer(ibmf_ci_t *cip, ibmf_recv_wqe_t *recv_wqep)
11677c478bd9Sstevel@tonic-gate {
11687c478bd9Sstevel@tonic-gate 	int			ret;
11697c478bd9Sstevel@tonic-gate 	ibt_status_t		status;
11707c478bd9Sstevel@tonic-gate 	ibmf_qp_handle_t	ibmf_qp_handle = recv_wqep->recv_ibmf_qp_handle;
11717c478bd9Sstevel@tonic-gate 	struct kmem_cache	*kmem_cachep;
11727c478bd9Sstevel@tonic-gate 	ibmf_alt_qp_t		*altqp;
11737c478bd9Sstevel@tonic-gate 	ibmf_qp_t		*qpp;
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
11767c478bd9Sstevel@tonic-gate 	    ibmf_i_repost_recv_buffer_start, IBMF_TNF_TRACE, "",
11777c478bd9Sstevel@tonic-gate 	    "ibmf_i_repost_recv_buffer() enter, cip = %p, rwqep = %p\n",
11787c478bd9Sstevel@tonic-gate 	    tnf_opaque, cip, cip, tnf_opaque, rwqep, recv_wqep);
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&cip->ci_mutex));
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	/* Get the WQE kmem cache pointer based on the QP type */
11837c478bd9Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
11847c478bd9Sstevel@tonic-gate 		kmem_cachep = cip->ci_recv_wqes_cache;
11857c478bd9Sstevel@tonic-gate 		qpp = recv_wqep->recv_qpp;
11867c478bd9Sstevel@tonic-gate 	} else {
11877c478bd9Sstevel@tonic-gate 		altqp = (ibmf_alt_qp_t *)ibmf_qp_handle;
11887c478bd9Sstevel@tonic-gate 		kmem_cachep = altqp->isq_recv_wqes_cache;
11897c478bd9Sstevel@tonic-gate 	}
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	/* post recv wqe; free it if the post fails */
11927c478bd9Sstevel@tonic-gate 	status = ibt_post_recv(recv_wqep->recv_qp_handle, &recv_wqep->recv_wr,
11937c478bd9Sstevel@tonic-gate 	    1, NULL);
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	ret = ibmf_i_ibt_to_ibmf_status(status);
11967c478bd9Sstevel@tonic-gate 	if (ret != IBMF_SUCCESS) {
11977c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
11987c478bd9Sstevel@tonic-gate 		    ibmf_i_repost_recv_buffer_err, IBMF_TNF_ERROR, "",
11997c478bd9Sstevel@tonic-gate 		    "ibmf_i_repost_recv_buffer(): %s, status = %d\n",
12007c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "repost_recv failed", tnf_uint,
12017c478bd9Sstevel@tonic-gate 		    ibt_status, status);
12027c478bd9Sstevel@tonic-gate 		kmem_free(recv_wqep->recv_wr.wr_sgl,
12037c478bd9Sstevel@tonic-gate 		    IBMF_MAX_RQ_WR_SGL_ELEMENTS * sizeof (ibt_wr_ds_t));
12047c478bd9Sstevel@tonic-gate 		kmem_cache_free(kmem_cachep, recv_wqep);
12057c478bd9Sstevel@tonic-gate 		mutex_enter(&cip->ci_mutex);
12067c478bd9Sstevel@tonic-gate 		IBMF_SUB32_PORT_KSTATS(cip, recv_wqes_alloced, 1);
12077c478bd9Sstevel@tonic-gate 		mutex_exit(&cip->ci_mutex);
12087c478bd9Sstevel@tonic-gate 		if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
12097c478bd9Sstevel@tonic-gate 			mutex_enter(&cip->ci_mutex);
12107c478bd9Sstevel@tonic-gate 			cip->ci_wqes_alloced--;
12117c478bd9Sstevel@tonic-gate 			if (cip->ci_wqes_alloced == 0)
12127c478bd9Sstevel@tonic-gate 				cv_signal(&cip->ci_wqes_cv);
12137c478bd9Sstevel@tonic-gate 			mutex_exit(&cip->ci_mutex);
12147c478bd9Sstevel@tonic-gate 		} else {
12157c478bd9Sstevel@tonic-gate 			mutex_enter(&altqp->isq_mutex);
12167c478bd9Sstevel@tonic-gate 			altqp->isq_wqes_alloced--;
12177c478bd9Sstevel@tonic-gate 			if (altqp->isq_wqes_alloced == 0)
12187c478bd9Sstevel@tonic-gate 				cv_signal(&altqp->isq_wqes_cv);
12197c478bd9Sstevel@tonic-gate 			mutex_exit(&altqp->isq_mutex);
12207c478bd9Sstevel@tonic-gate 		}
12217c478bd9Sstevel@tonic-gate 	}
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
12247c478bd9Sstevel@tonic-gate 		mutex_enter(&qpp->iq_mutex);
12257c478bd9Sstevel@tonic-gate 		qpp->iq_rwqes_posted++;
12267c478bd9Sstevel@tonic-gate 		mutex_exit(&qpp->iq_mutex);
12277c478bd9Sstevel@tonic-gate 	} else {
12287c478bd9Sstevel@tonic-gate 		mutex_enter(&altqp->isq_mutex);
12297c478bd9Sstevel@tonic-gate 		altqp->isq_rwqes_posted++;
12307c478bd9Sstevel@tonic-gate 		mutex_exit(&altqp->isq_mutex);
12317c478bd9Sstevel@tonic-gate 	}
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_repost_recv_buffer_end,
12347c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_i_repost_recv_buffer() exit\n");
12357c478bd9Sstevel@tonic-gate 	return (ret);
12367c478bd9Sstevel@tonic-gate }
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate /*
12397c478bd9Sstevel@tonic-gate  * ibmf_i_get_class:
12407c478bd9Sstevel@tonic-gate  * Parses the mad header and determines which class should be notified of the
12417c478bd9Sstevel@tonic-gate  * notification.
12427c478bd9Sstevel@tonic-gate  *
12437c478bd9Sstevel@tonic-gate  * Input Argument
12447c478bd9Sstevel@tonic-gate  * madhdrp    contents of mad header for the packet
12457c478bd9Sstevel@tonic-gate  *
12467c478bd9Sstevel@tonic-gate  * Output Argument
12477c478bd9Sstevel@tonic-gate  * dest_classp pointer to the class type of the client that should be notified
12487c478bd9Sstevel@tonic-gate  *
12497c478bd9Sstevel@tonic-gate  * Returns
12507c478bd9Sstevel@tonic-gate  * status
12517c478bd9Sstevel@tonic-gate  */
12527c478bd9Sstevel@tonic-gate static int
ibmf_i_get_class(ib_mad_hdr_t * madhdrp,ibmf_qp_handle_t dest_ibmf_qp_handle,ib_lid_t slid,ibmf_client_type_t * dest_classp)12537c478bd9Sstevel@tonic-gate ibmf_i_get_class(ib_mad_hdr_t *madhdrp, ibmf_qp_handle_t dest_ibmf_qp_handle,
12547c478bd9Sstevel@tonic-gate     ib_lid_t slid, ibmf_client_type_t *dest_classp)
12557c478bd9Sstevel@tonic-gate {
12567c478bd9Sstevel@tonic-gate 	int		method = madhdrp->R_Method;
12577c478bd9Sstevel@tonic-gate 	int		attrib = b2h16(madhdrp->AttributeID);
12587c478bd9Sstevel@tonic-gate 	int		class = madhdrp->MgmtClass;
12597c478bd9Sstevel@tonic-gate 	uint32_t	attrib_mod = b2h32(madhdrp->AttributeModifier);
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
12627c478bd9Sstevel@tonic-gate 	    ibmf_i_get_class_start, IBMF_TNF_TRACE, "",
12637c478bd9Sstevel@tonic-gate 	    "ibmf_i_get_class() enter, class = 0x%x, method = 0x%x, "
12647c478bd9Sstevel@tonic-gate 	    "attribute = 0x%x, dest_qp_hdl = 0x%p\n",
12657c478bd9Sstevel@tonic-gate 	    tnf_opaque, class, class,
12667c478bd9Sstevel@tonic-gate 	    tnf_opaque, method, method,
12677c478bd9Sstevel@tonic-gate 	    tnf_opaque, attrib, attrib,
12687c478bd9Sstevel@tonic-gate 	    tnf_opaque, ibmf_qp_handle, dest_ibmf_qp_handle);
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	/* set default for error checking */
12717c478bd9Sstevel@tonic-gate 	*dest_classp = 0;
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	/*
12747c478bd9Sstevel@tonic-gate 	 * Determine the class type
12757c478bd9Sstevel@tonic-gate 	 */
12767c478bd9Sstevel@tonic-gate 	switch (class) {
12777c478bd9Sstevel@tonic-gate 	case MAD_MGMT_CLASS_SUBN_LID_ROUTED:
12787c478bd9Sstevel@tonic-gate 	case MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE:
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 		/*
12817c478bd9Sstevel@tonic-gate 		 * tavor generates trap by sending mad with slid 0;
12827c478bd9Sstevel@tonic-gate 		 * deliver this to SMA
12837c478bd9Sstevel@tonic-gate 		 */
12847c478bd9Sstevel@tonic-gate 		if ((method == MAD_METHOD_TRAP) && (slid == 0)) {
12857c478bd9Sstevel@tonic-gate 			*dest_classp = SUBN_AGENT;
12867c478bd9Sstevel@tonic-gate 			break;
12877c478bd9Sstevel@tonic-gate 		}
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 		/* this is derived from table 109 of IB Spec 1.1, vol1 */
12907c478bd9Sstevel@tonic-gate 		if (attrib == SM_SMINFO_ATTRID || method == MAD_METHOD_TRAP ||
12917c478bd9Sstevel@tonic-gate 		    method == MAD_METHOD_GET_RESPONSE)
12927c478bd9Sstevel@tonic-gate 			*dest_classp = SUBN_MANAGER;
12937c478bd9Sstevel@tonic-gate 		else
12947c478bd9Sstevel@tonic-gate 			*dest_classp = SUBN_AGENT;
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 		break;
12977c478bd9Sstevel@tonic-gate 	case MAD_MGMT_CLASS_SUBN_ADM:
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 		/*
13007c478bd9Sstevel@tonic-gate 		 * Deliver to SA client (agent) if packet was sent to default qp
13017c478bd9Sstevel@tonic-gate 		 * Deliver to ibmf_saa client (manager) if packet was sent to
13027c478bd9Sstevel@tonic-gate 		 * alternate qp
13037c478bd9Sstevel@tonic-gate 		 */
13047c478bd9Sstevel@tonic-gate 		if (dest_ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT)
13057c478bd9Sstevel@tonic-gate 			*dest_classp = SUBN_ADM_AGENT;
13067c478bd9Sstevel@tonic-gate 		else
13077c478bd9Sstevel@tonic-gate 			*dest_classp = SUBN_ADM_MANAGER;
13087c478bd9Sstevel@tonic-gate 		break;
13097c478bd9Sstevel@tonic-gate 	case MAD_MGMT_CLASS_PERF:
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 		/* Deliver to PM if response bit is set */
13127c478bd9Sstevel@tonic-gate 		if ((method & MAD_RESPONSE_BIT_MASK) == MAD_RESPONSE_BIT)
13137c478bd9Sstevel@tonic-gate 			*dest_classp = PERF_MANAGER;
13147c478bd9Sstevel@tonic-gate 		else
13157c478bd9Sstevel@tonic-gate 			*dest_classp = PERF_AGENT;
13167c478bd9Sstevel@tonic-gate 		break;
13177c478bd9Sstevel@tonic-gate 	case MAD_MGMT_CLASS_BM:
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 		/*
13207c478bd9Sstevel@tonic-gate 		 * Deliver to BM if response bit is set, packet is a trap,
13217c478bd9Sstevel@tonic-gate 		 * or packet is a BMSend
13227c478bd9Sstevel@tonic-gate 		 */
13237c478bd9Sstevel@tonic-gate 		if (((method & MAD_RESPONSE_BIT_MASK) == MAD_RESPONSE_BIT) ||
13247c478bd9Sstevel@tonic-gate 		    (method == MAD_METHOD_TRAP) ||
13257c478bd9Sstevel@tonic-gate 		    ((method == MAD_METHOD_SEND) &&
13267c478bd9Sstevel@tonic-gate 		    ((attrib_mod & IBMF_BM_MAD_ATTR_MOD_REQRESP_BIT) ==
13277c478bd9Sstevel@tonic-gate 		    IBMF_BM_MAD_ATTR_MOD_RESP)))
13287c478bd9Sstevel@tonic-gate 			*dest_classp = BM_MANAGER;
13297c478bd9Sstevel@tonic-gate 		else
13307c478bd9Sstevel@tonic-gate 			*dest_classp = BM_AGENT;
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 		break;
13337c478bd9Sstevel@tonic-gate 	case MAD_MGMT_CLASS_DEV_MGT:
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 		/* Deliver to DM if response bit is set or packet is a trap */
13367c478bd9Sstevel@tonic-gate 		if (((method & MAD_RESPONSE_BIT_MASK) == MAD_RESPONSE_BIT) ||
13377c478bd9Sstevel@tonic-gate 		    (method == MAD_METHOD_TRAP))
13387c478bd9Sstevel@tonic-gate 			*dest_classp = DEV_MGT_MANAGER;
13397c478bd9Sstevel@tonic-gate 		else
13407c478bd9Sstevel@tonic-gate 			*dest_classp = DEV_MGT_AGENT;
13417c478bd9Sstevel@tonic-gate 		break;
13427c478bd9Sstevel@tonic-gate 	case MAD_MGMT_CLASS_COMM_MGT:
13437c478bd9Sstevel@tonic-gate 		*dest_classp = COMM_MGT_MANAGER_AGENT;
13447c478bd9Sstevel@tonic-gate 		break;
13457c478bd9Sstevel@tonic-gate 	case MAD_MGMT_CLASS_SNMP:
13467c478bd9Sstevel@tonic-gate 		*dest_classp = SNMP_MANAGER_AGENT;
13477c478bd9Sstevel@tonic-gate 		break;
13487c478bd9Sstevel@tonic-gate 	default:
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 		if ((class >= MAD_MGMT_CLASS_VENDOR_START) &&
13517c478bd9Sstevel@tonic-gate 		    (class <= MAD_MGMT_CLASS_VENDOR_END)) {
13527c478bd9Sstevel@tonic-gate 			*dest_classp = VENDOR_09_MANAGER_AGENT +
13537c478bd9Sstevel@tonic-gate 			    (class - MAD_MGMT_CLASS_VENDOR_START);
13547c478bd9Sstevel@tonic-gate 		} else if ((class >= MAD_MGMT_CLASS_VENDOR2_START) &&
13557c478bd9Sstevel@tonic-gate 		    (class <= MAD_MGMT_CLASS_VENDOR2_END)) {
13567c478bd9Sstevel@tonic-gate 			*dest_classp = VENDOR_30_MANAGER_AGENT +
13577c478bd9Sstevel@tonic-gate 			    (class - MAD_MGMT_CLASS_VENDOR2_START);
13587c478bd9Sstevel@tonic-gate 		} else if ((class >= MAD_MGMT_CLASS_APPLICATION_START) &&
13597c478bd9Sstevel@tonic-gate 		    (class <= MAD_MGMT_CLASS_APPLICATION_END)) {
13607c478bd9Sstevel@tonic-gate 			*dest_classp = APPLICATION_10_MANAGER_AGENT +
13617c478bd9Sstevel@tonic-gate 			    (class - MAD_MGMT_CLASS_APPLICATION_START);
13627c478bd9Sstevel@tonic-gate 		}
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 		break;
13657c478bd9Sstevel@tonic-gate 	}
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 	if (*dest_classp == 0) {
13687c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
13697c478bd9Sstevel@tonic-gate 		    ibmf_i_get_class_type_err, IBMF_TNF_TRACE, "",
13707c478bd9Sstevel@tonic-gate 		    "ibmf_i_get_class(): %s, class = 0x%x\n",
13717c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "invalid class", tnf_opaque, class, class);
13727c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_get_class_end,
13737c478bd9Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_i_get_class() exit\n");
13747c478bd9Sstevel@tonic-gate 		return (IBMF_FAILURE);
13757c478bd9Sstevel@tonic-gate 	}
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
13787c478bd9Sstevel@tonic-gate 	    ibmf_i_get_class_end, IBMF_TNF_TRACE, "",
13797c478bd9Sstevel@tonic-gate 	    "ibmf_i_get_class() exit, class = 0x%x\n",
13807c478bd9Sstevel@tonic-gate 	    tnf_opaque, class, *dest_classp);
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 	return (IBMF_SUCCESS);
13837c478bd9Sstevel@tonic-gate }
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate /*
13867c478bd9Sstevel@tonic-gate  * ibmf_get_mod_name():
13877c478bd9Sstevel@tonic-gate  * Constructs the module name based on the naming convention described in
13887c478bd9Sstevel@tonic-gate  * PSARC case 2003/753.
13897c478bd9Sstevel@tonic-gate  * The name should be "sunwibmgt<MgtClass><a_m>
13907c478bd9Sstevel@tonic-gate  * where:
13917c478bd9Sstevel@tonic-gate  *	MgtClass = Management class field in the MAD header.
13927c478bd9Sstevel@tonic-gate  *		   Two lower-case characters are used to represent
13937c478bd9Sstevel@tonic-gate  *		   this 8-bit value as 2 hex digits.
13947c478bd9Sstevel@tonic-gate  *	a_m	 = "a" if the client is an agent-only module
13957c478bd9Sstevel@tonic-gate  *		   "m" if the client is a manager-only module
13967c478bd9Sstevel@tonic-gate  *		   ""  if the client is both agent and manager.
13977c478bd9Sstevel@tonic-gate  *
13987c478bd9Sstevel@tonic-gate  * Input Argument
13997c478bd9Sstevel@tonic-gate  * mad_class	management class in the MAD header
14007c478bd9Sstevel@tonic-gate  * class	IBMF management class of incoming MAD
14017c478bd9Sstevel@tonic-gate  *
14027c478bd9Sstevel@tonic-gate  * Output Argument
14037c478bd9Sstevel@tonic-gate  * modname	pointer to the character array that holds the module name
14047c478bd9Sstevel@tonic-gate  *
14057c478bd9Sstevel@tonic-gate  * Status
14067c478bd9Sstevel@tonic-gate  * None
14077c478bd9Sstevel@tonic-gate  */
14087c478bd9Sstevel@tonic-gate static void
ibmf_get_mod_name(uint8_t mad_class,ibmf_client_type_t class,char * modname)14097c478bd9Sstevel@tonic-gate ibmf_get_mod_name(uint8_t mad_class, ibmf_client_type_t class, char *modname)
14107c478bd9Sstevel@tonic-gate {
14117c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_get_mod_name_start,
14127c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_get_mod_name_qphdl() enter\n");
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	if (AGENT_CLASS(class)) {
14157c478bd9Sstevel@tonic-gate 		(void) sprintf(modname, "sunwibmgt%02xa", mad_class);
14167c478bd9Sstevel@tonic-gate 	} else if (MANAGER_CLASS(class)) {
14177c478bd9Sstevel@tonic-gate 		(void) sprintf(modname, "sunwibmgt%02xm", mad_class);
14187c478bd9Sstevel@tonic-gate 	} else {
14197c478bd9Sstevel@tonic-gate 		/* AGENT+MANAGER class */
14207c478bd9Sstevel@tonic-gate 		(void) sprintf(modname, "sunwibmgt%02x", mad_class);
14217c478bd9Sstevel@tonic-gate 	}
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L3, ibmf_get_mod_name,
14247c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_get_mod_name(): name = %s\n",
14257c478bd9Sstevel@tonic-gate 	    tnf_string, msg, modname);
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_get_mod_name_end,
14287c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_get_mod_name() exit\n");
14297c478bd9Sstevel@tonic-gate }
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate /*
14327c478bd9Sstevel@tonic-gate  * ibmf_send_busy():
14337c478bd9Sstevel@tonic-gate  *
14347c478bd9Sstevel@tonic-gate  * When a MAD request is received for an IB mandatory agent (BMA or PMA),
14357c478bd9Sstevel@tonic-gate  * which has not yet registered with IBMF, IBMF returns a BUSY MAD
14367c478bd9Sstevel@tonic-gate  * to the source of the request to solicit a retry while IBMF attempts
14377c478bd9Sstevel@tonic-gate  * to load the mandatory agent.
14387c478bd9Sstevel@tonic-gate  * A temporary, alternate QP is allocated for the purpose of sending the
14397c478bd9Sstevel@tonic-gate  * MAD. This QP is configured to be in the same partition as the manager
14407c478bd9Sstevel@tonic-gate  * that sent the request.
14417c478bd9Sstevel@tonic-gate  *
14427c478bd9Sstevel@tonic-gate  * Input Argument
14437c478bd9Sstevel@tonic-gate  * modlargsp	Pointer to ibmf_mod_load_args_t structure
14447c478bd9Sstevel@tonic-gate  *
14457c478bd9Sstevel@tonic-gate  * Output Argument
14467c478bd9Sstevel@tonic-gate  * None
14477c478bd9Sstevel@tonic-gate  *
14487c478bd9Sstevel@tonic-gate  * Status
14497c478bd9Sstevel@tonic-gate  * None
14507c478bd9Sstevel@tonic-gate  */
14517c478bd9Sstevel@tonic-gate static void
ibmf_send_busy(ibmf_mod_load_args_t * modlargsp)14527c478bd9Sstevel@tonic-gate ibmf_send_busy(ibmf_mod_load_args_t *modlargsp)
14537c478bd9Sstevel@tonic-gate {
14547c478bd9Sstevel@tonic-gate 	ibmf_ci_t		*cip = modlargsp->cip;
14557c478bd9Sstevel@tonic-gate 	ibmf_recv_wqe_t		*recv_wqep = modlargsp->recv_wqep;
14567c478bd9Sstevel@tonic-gate 	ibt_wr_ds_t		sgl[1];
14577c478bd9Sstevel@tonic-gate 	ibmf_send_wqe_t		*send_wqep;
14587c478bd9Sstevel@tonic-gate 	ibt_send_wr_t		*swrp;
1459*525f8227SToomas Soome 	ibmf_msg_impl_t		*msgimplp;
14607c478bd9Sstevel@tonic-gate 	ibmf_ud_dest_t		*ibmf_ud_dest;
14617c478bd9Sstevel@tonic-gate 	ibt_ud_dest_t		*ud_dest;
14627c478bd9Sstevel@tonic-gate 	ib_mad_hdr_t		*smadhdrp, *rmadhdrp;
14637c478bd9Sstevel@tonic-gate 	ibt_adds_vect_t		adds_vec;
14647c478bd9Sstevel@tonic-gate 	ibt_wc_t		*wcp = &recv_wqep->recv_wc;
14657c478bd9Sstevel@tonic-gate 	ibt_status_t		ibtstatus;
14667c478bd9Sstevel@tonic-gate 	uint_t			num_work_reqs;
14677c478bd9Sstevel@tonic-gate 	ibt_qp_alloc_attr_t	qp_attrs;
14687c478bd9Sstevel@tonic-gate 	ibt_qp_info_t		qp_modify_attr;
14697c478bd9Sstevel@tonic-gate 	ibt_chan_sizes_t	qp_sizes;
14707c478bd9Sstevel@tonic-gate 	ib_qpn_t		qp_num;
14717c478bd9Sstevel@tonic-gate 	ibt_qp_hdl_t		ibt_qp_handle;
14727c478bd9Sstevel@tonic-gate 	ibt_mr_hdl_t		mem_hdl;
14737c478bd9Sstevel@tonic-gate 	ibt_mr_desc_t		mem_desc;
14747c478bd9Sstevel@tonic-gate 	ibt_mr_attr_t		mem_attr;
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_send_busy_start,
14777c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_send_busy() enter\n");
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate 	/* setup the qp attrs for the alloc call */
14807c478bd9Sstevel@tonic-gate 	qp_attrs.qp_scq_hdl = cip->ci_alt_cq_handle;
14817c478bd9Sstevel@tonic-gate 	qp_attrs.qp_rcq_hdl = cip->ci_alt_cq_handle;
14827c478bd9Sstevel@tonic-gate 	qp_attrs.qp_pd_hdl = cip->ci_pd;
14837c478bd9Sstevel@tonic-gate 	qp_attrs.qp_sizes.cs_sq_sgl = IBMF_MAX_SQ_WR_SGL_ELEMENTS;
14847c478bd9Sstevel@tonic-gate 	qp_attrs.qp_sizes.cs_rq_sgl = IBMF_MAX_RQ_WR_SGL_ELEMENTS;
14857c478bd9Sstevel@tonic-gate 	qp_attrs.qp_sizes.cs_sq = ibmf_send_wqes_posted_per_qp;
14867c478bd9Sstevel@tonic-gate 	qp_attrs.qp_sizes.cs_rq = ibmf_recv_wqes_posted_per_qp;
14877c478bd9Sstevel@tonic-gate 	qp_attrs.qp_flags = IBT_ALL_SIGNALED;
14887c478bd9Sstevel@tonic-gate 	qp_attrs.qp_alloc_flags = IBT_QP_NO_FLAGS;
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	/* request IBT for a qp with the desired attributes */
14917c478bd9Sstevel@tonic-gate 	ibtstatus = ibt_alloc_qp(cip->ci_ci_handle, IBT_UD_RQP,
14927c478bd9Sstevel@tonic-gate 	    &qp_attrs, &qp_sizes, &qp_num, &ibt_qp_handle);
14937c478bd9Sstevel@tonic-gate 	if (ibtstatus != IBT_SUCCESS) {
14947c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_send_busy_err,
14957c478bd9Sstevel@tonic-gate 		    IBMF_TNF_ERROR, "", "ibmf_send_busy(): %s, status = %d\n",
14967c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "failed to allocate alternate QP",
14977c478bd9Sstevel@tonic-gate 		    tnf_int, ibt_status, ibtstatus);
14987c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_send_busy_end,
14997c478bd9Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_send_busy() exit\n");
15007c478bd9Sstevel@tonic-gate 		return;
15017c478bd9Sstevel@tonic-gate 	}
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	qp_modify_attr.qp_trans = IBT_UD_SRV;
15047c478bd9Sstevel@tonic-gate 	qp_modify_attr.qp_flags = IBT_CEP_NO_FLAGS;
15057c478bd9Sstevel@tonic-gate 	qp_modify_attr.qp_transport.ud.ud_qkey = IB_GSI_QKEY;
15067c478bd9Sstevel@tonic-gate 	qp_modify_attr.qp_transport.ud.ud_sq_psn = 0;
15077c478bd9Sstevel@tonic-gate 	qp_modify_attr.qp_transport.ud.ud_pkey_ix = wcp->wc_pkey_ix;
15087c478bd9Sstevel@tonic-gate 	qp_modify_attr.qp_transport.ud.ud_port = recv_wqep->recv_port_num;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	/* call the IB transport to initialize the QP */
15117c478bd9Sstevel@tonic-gate 	ibtstatus = ibt_initialize_qp(ibt_qp_handle, &qp_modify_attr);
15127c478bd9Sstevel@tonic-gate 	if (ibtstatus != IBT_SUCCESS) {
15137c478bd9Sstevel@tonic-gate 		(void) ibt_free_qp(ibt_qp_handle);
15147c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_send_busy_err,
15157c478bd9Sstevel@tonic-gate 		    IBMF_TNF_ERROR, "", "ibmf_send_busy(): %s, status = %d\n",
15167c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "failed to initialize alternate QP",
15177c478bd9Sstevel@tonic-gate 		    tnf_int, ibt_status, ibtstatus);
15187c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_send_busy_end,
15197c478bd9Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_send_busy() exit\n");
15207c478bd9Sstevel@tonic-gate 		return;
15217c478bd9Sstevel@tonic-gate 	}
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 	/* allocate the message context */
15247c478bd9Sstevel@tonic-gate 	msgimplp = (ibmf_msg_impl_t *)kmem_zalloc(sizeof (ibmf_msg_impl_t),
15257c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msgimplp))
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 	ibmf_i_pop_ud_dest_thread(cip);
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate 	/*
15327c478bd9Sstevel@tonic-gate 	 * Get a UD dest structure from the pool, this will not fail
15337c478bd9Sstevel@tonic-gate 	 * because ibmf_i_pop_ud_dest_thread() calls
15347c478bd9Sstevel@tonic-gate 	 * ibmf_i_populate_ud_dest_list with the KM_SLEEP flag.
15357c478bd9Sstevel@tonic-gate 	 */
15367c478bd9Sstevel@tonic-gate 	ibmf_ud_dest = ibmf_i_get_ud_dest(cip);
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	msgimplp->im_ibmf_ud_dest = ibmf_ud_dest;
15397c478bd9Sstevel@tonic-gate 	msgimplp->im_ud_dest = &ibmf_ud_dest->ud_dest;
15407c478bd9Sstevel@tonic-gate 	msgimplp->im_qp_hdl = NULL;
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 	/*
15437c478bd9Sstevel@tonic-gate 	 * Reset send_done to indicate we have not received the completion
15447c478bd9Sstevel@tonic-gate 	 * for this send yet.
15457c478bd9Sstevel@tonic-gate 	 */
15467c478bd9Sstevel@tonic-gate 	msgimplp->im_trans_state_flags &= ~IBMF_TRANS_STATE_FLAG_SEND_DONE;
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*send_wqep))
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	/*
15517c478bd9Sstevel@tonic-gate 	 * Allocate resources needed to send a UD packet including the
15527c478bd9Sstevel@tonic-gate 	 * send WQE context
15537c478bd9Sstevel@tonic-gate 	 */
15547c478bd9Sstevel@tonic-gate 	send_wqep = (ibmf_send_wqe_t *)kmem_zalloc(sizeof (ibmf_send_wqe_t),
15557c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
15567c478bd9Sstevel@tonic-gate 	send_wqep->send_mem = (void *)kmem_zalloc(IBMF_MEM_PER_WQE, KM_SLEEP);
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 	mem_attr.mr_vaddr = (ib_vaddr_t)(uintptr_t)send_wqep->send_mem;
15597c478bd9Sstevel@tonic-gate 	mem_attr.mr_len = IBMF_MEM_PER_WQE;
15607c478bd9Sstevel@tonic-gate 	mem_attr.mr_flags = IBT_MR_SLEEP | IBT_MR_ENABLE_LOCAL_WRITE;
15617c478bd9Sstevel@tonic-gate 	mem_attr.mr_as = NULL;
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 	/* Register the allocated memory */
15647c478bd9Sstevel@tonic-gate 	ibtstatus = ibt_register_mr(cip->ci_ci_handle, cip->ci_pd, &mem_attr,
15657c478bd9Sstevel@tonic-gate 	    &mem_hdl, &mem_desc);
15667c478bd9Sstevel@tonic-gate 	if (ibtstatus != IBT_SUCCESS) {
1567651fc39cSLida.Horn 		kmem_free(send_wqep->send_mem, IBMF_MEM_PER_WQE);
15687c478bd9Sstevel@tonic-gate 		kmem_free(send_wqep, sizeof (ibmf_send_wqe_t));
15697c478bd9Sstevel@tonic-gate 		ibmf_i_put_ud_dest(cip, msgimplp->im_ibmf_ud_dest);
15707c478bd9Sstevel@tonic-gate 		kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
15717c478bd9Sstevel@tonic-gate 		(void) ibt_free_qp(ibt_qp_handle);
15727c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_send_busy_err,
15737c478bd9Sstevel@tonic-gate 		    IBMF_TNF_ERROR, "", "ibmf_send_busy(): %s, status = %d\n",
15747c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "failed to register memory",
15757c478bd9Sstevel@tonic-gate 		    tnf_int, ibt_status, ibtstatus);
15767c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_send_busy_end,
15777c478bd9Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_send_busy() exit\n");
15787c478bd9Sstevel@tonic-gate 		return;
15797c478bd9Sstevel@tonic-gate 	}
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	send_wqep->send_sg_lkey = mem_desc.md_lkey;
15827c478bd9Sstevel@tonic-gate 	send_wqep->send_mem_hdl = mem_hdl;
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate 	swrp = &send_wqep->send_wr;
15857c478bd9Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*swrp))
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 	/* use send wqe pointer as the WR ID */
15887c478bd9Sstevel@tonic-gate 	swrp->wr_id		= (ibt_wrid_t)(uintptr_t)send_wqep;
1589*525f8227SToomas Soome 	ASSERT(swrp->wr_id != 0);
15907c478bd9Sstevel@tonic-gate 	swrp->wr_flags		= IBT_WR_NO_FLAGS;
15917c478bd9Sstevel@tonic-gate 	swrp->wr_opcode		= IBT_WRC_SEND;
15927c478bd9Sstevel@tonic-gate 	swrp->wr_trans		= IBT_UD_SRV;
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	send_wqep->send_client	= NULL;
15957c478bd9Sstevel@tonic-gate 	send_wqep->send_msg	= msgimplp;
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 	/* Initialize the scatter-gather list */
15987c478bd9Sstevel@tonic-gate 	sgl[0].ds_va		= (ib_vaddr_t)(uintptr_t)send_wqep->send_mem;
15997c478bd9Sstevel@tonic-gate 	sgl[0].ds_key		= send_wqep->send_sg_lkey;
16007c478bd9Sstevel@tonic-gate 	sgl[0].ds_len		= IBMF_MAD_SIZE;
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	wcp			= &recv_wqep->recv_wc;
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	/* Initialize the address vector */
16057c478bd9Sstevel@tonic-gate 	adds_vec.av_send_grh	= B_FALSE;
16067c478bd9Sstevel@tonic-gate 	adds_vec.av_dlid	= wcp->wc_slid;
16077c478bd9Sstevel@tonic-gate 	adds_vec.av_src_path	= wcp->wc_path_bits;
16087c478bd9Sstevel@tonic-gate 	adds_vec.av_srvl	= 0;
16097c478bd9Sstevel@tonic-gate 	adds_vec.av_srate	= IBT_SRATE_1X;
16107c478bd9Sstevel@tonic-gate 	adds_vec.av_port_num	= recv_wqep->recv_port_num;
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 	ud_dest			= msgimplp->im_ud_dest;
16137c478bd9Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ud_dest))
16147c478bd9Sstevel@tonic-gate 	ud_dest->ud_qkey	= IB_GSI_QKEY;
16157c478bd9Sstevel@tonic-gate 	ud_dest->ud_dst_qpn	= wcp->wc_qpn;
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	/* modify the address handle with the address vector information */
16187c478bd9Sstevel@tonic-gate 	ibtstatus = ibt_modify_ah(cip->ci_ci_handle, ud_dest->ud_ah, &adds_vec);
16197c478bd9Sstevel@tonic-gate 	if (ibtstatus != IBT_SUCCESS) {
16207c478bd9Sstevel@tonic-gate 		(void) ibt_deregister_mr(cip->ci_ci_handle, mem_hdl);
16217133abc2SLida.Horn 		kmem_free(send_wqep->send_mem, IBMF_MEM_PER_WQE);
16227c478bd9Sstevel@tonic-gate 		kmem_free(send_wqep, sizeof (ibmf_send_wqe_t));
16237c478bd9Sstevel@tonic-gate 		ibmf_i_put_ud_dest(cip, msgimplp->im_ibmf_ud_dest);
16247c478bd9Sstevel@tonic-gate 		kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
16257c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1, ibmf_send_busy_err,
16267c478bd9Sstevel@tonic-gate 		    IBMF_TNF_ERROR, "", "ibmf_send_busy(): %s, status = %d\n",
16277c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "ibt modify ah failed", tnf_uint,
16287c478bd9Sstevel@tonic-gate 		    ibt_status, ibtstatus);
16297c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_send_busy_end,
16307c478bd9Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_send_busy(() exit\n");
16317c478bd9Sstevel@tonic-gate 		return;
16327c478bd9Sstevel@tonic-gate 	}
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate 	bzero(send_wqep->send_mem, IBMF_MAD_SIZE);
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	rmadhdrp = (ib_mad_hdr_t *)((uintptr_t)recv_wqep->recv_mem +
16377c478bd9Sstevel@tonic-gate 	    sizeof (ib_grh_t));
16387c478bd9Sstevel@tonic-gate 	smadhdrp = (ib_mad_hdr_t *)send_wqep->send_mem;
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rmadhdrp))
16417c478bd9Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*smadhdrp))
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 	/* Set up the MAD header */
16447c478bd9Sstevel@tonic-gate 	smadhdrp->BaseVersion	= rmadhdrp->BaseVersion;
16457c478bd9Sstevel@tonic-gate 	smadhdrp->MgmtClass	= rmadhdrp->MgmtClass;
16467c478bd9Sstevel@tonic-gate 	smadhdrp->ClassVersion	= rmadhdrp->ClassVersion;
16477c478bd9Sstevel@tonic-gate 	smadhdrp->R_Method	= MAD_METHOD_GET_RESPONSE;
16487c478bd9Sstevel@tonic-gate 	smadhdrp->Status	= MAD_STATUS_BUSY;
16497c478bd9Sstevel@tonic-gate 	smadhdrp->TransactionID	= rmadhdrp->TransactionID;
16507c478bd9Sstevel@tonic-gate 	smadhdrp->AttributeID	= rmadhdrp->AttributeID;
16517c478bd9Sstevel@tonic-gate 	smadhdrp->AttributeModifier = rmadhdrp->AttributeModifier;
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 	swrp->wr_sgl		= sgl;
16547c478bd9Sstevel@tonic-gate 	swrp->wr_nds		= 1;
16557c478bd9Sstevel@tonic-gate 	swrp->wr.ud.udwr_dest	= msgimplp->im_ud_dest;
16567c478bd9Sstevel@tonic-gate 	send_wqep->send_port_num = recv_wqep->recv_port_num;
16577c478bd9Sstevel@tonic-gate 	send_wqep->send_qp_handle = ibt_qp_handle;
16587c478bd9Sstevel@tonic-gate 	send_wqep->send_ibmf_qp_handle = NULL;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	/* Post the MAD to the IBT layer */
16617c478bd9Sstevel@tonic-gate 	num_work_reqs		= 1;
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	ibtstatus = ibt_post_send(ibt_qp_handle, &send_wqep->send_wr,
16647c478bd9Sstevel@tonic-gate 	    num_work_reqs, NULL);
16657c478bd9Sstevel@tonic-gate 	if (ibtstatus != IBT_SUCCESS) {
16667c478bd9Sstevel@tonic-gate 		(void) ibt_deregister_mr(cip->ci_ci_handle, mem_hdl);
16677133abc2SLida.Horn 		kmem_free(send_wqep->send_mem, IBMF_MEM_PER_WQE);
16687c478bd9Sstevel@tonic-gate 		kmem_free(send_wqep, sizeof (ibmf_send_wqe_t));
16697c478bd9Sstevel@tonic-gate 		ibmf_i_put_ud_dest(cip, msgimplp->im_ibmf_ud_dest);
16707c478bd9Sstevel@tonic-gate 		kmem_free(msgimplp, sizeof (ibmf_msg_impl_t));
16717c478bd9Sstevel@tonic-gate 		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
16727c478bd9Sstevel@tonic-gate 		    ibmf_send_busy_err, IBMF_TNF_TRACE, "",
16737c478bd9Sstevel@tonic-gate 		    "ibmf_send_busy(): %s, status = %d\n", tnf_string, msg,
16747c478bd9Sstevel@tonic-gate 		    "post send failure", tnf_uint, ibt_status, ibtstatus);
16757c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_send_busy_end,
16767c478bd9Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_send_busy(() exit\n");
16777c478bd9Sstevel@tonic-gate 		return;
16787c478bd9Sstevel@tonic-gate 	}
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_send_busy_end,
16817c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_send_busy() exit\n");
16827c478bd9Sstevel@tonic-gate }
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate /*
16857c478bd9Sstevel@tonic-gate  * ibmf_module_load():
16867c478bd9Sstevel@tonic-gate  * This function attempts to load a client module that has not yet
16877c478bd9Sstevel@tonic-gate  * registered with IBMF at the time a request MAD arrives for it.
16887c478bd9Sstevel@tonic-gate  * Prior to loading the module, it sends a busy MAD to the sender of
16897c478bd9Sstevel@tonic-gate  * the request MAD, this soliciting a resend of the request MAD.
16907c478bd9Sstevel@tonic-gate  *
16917c478bd9Sstevel@tonic-gate  * Input Argument
16927c478bd9Sstevel@tonic-gate  * modlargsp	Pointer to ibmf_mod_load_args_t structure
16937c478bd9Sstevel@tonic-gate  *
16947c478bd9Sstevel@tonic-gate  * Output Argument
16957c478bd9Sstevel@tonic-gate  * None
16967c478bd9Sstevel@tonic-gate  *
16977c478bd9Sstevel@tonic-gate  * Status
16987c478bd9Sstevel@tonic-gate  * None
16997c478bd9Sstevel@tonic-gate  */
17007c478bd9Sstevel@tonic-gate static void
ibmf_module_load(void * taskq_arg)17017c478bd9Sstevel@tonic-gate ibmf_module_load(void *taskq_arg)
17027c478bd9Sstevel@tonic-gate {
17037c478bd9Sstevel@tonic-gate 	char *modname;
17047c478bd9Sstevel@tonic-gate 	ibmf_mod_load_args_t *modlargsp = (ibmf_mod_load_args_t *)taskq_arg;
17057c478bd9Sstevel@tonic-gate 	ibmf_ci_t *cip = modlargsp->cip;
17067c478bd9Sstevel@tonic-gate 	ibmf_recv_wqe_t	*recv_wqep = modlargsp->recv_wqep;
17077c478bd9Sstevel@tonic-gate 	ibmf_client_type_t class = modlargsp->ibmf_class;
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_module_load_start,
17107c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_module_load_busy() enter\n");
17117c478bd9Sstevel@tonic-gate 	modname = modlargsp->modname;
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 	if (IS_MANDATORY_CLASS(class)) {
17147c478bd9Sstevel@tonic-gate 		ibmf_send_busy(modlargsp);
17157c478bd9Sstevel@tonic-gate 	}
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate 	if (modload("misc", modname) < 0) {
17187c478bd9Sstevel@tonic-gate 		(void) ibmf_i_repost_recv_buffer(cip, recv_wqep);
17197c478bd9Sstevel@tonic-gate 		kmem_free(modlargsp, sizeof (ibmf_mod_load_args_t));
17207c478bd9Sstevel@tonic-gate 		IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L1, ibmf_module_load_error,
17217c478bd9Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "",
17227c478bd9Sstevel@tonic-gate 		    "ibmf_module_load(): modload failed for %s\n",
17237c478bd9Sstevel@tonic-gate 		    tnf_string, module, modname);
17247c478bd9Sstevel@tonic-gate 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_module_load_end,
17257c478bd9Sstevel@tonic-gate 		    IBMF_TNF_TRACE, "", "ibmf_module_load() exit\n");
17267c478bd9Sstevel@tonic-gate 		return;
17277c478bd9Sstevel@tonic-gate 	}
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 	(void) ibmf_i_repost_recv_buffer(cip, recv_wqep);
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 	kmem_free(modlargsp, sizeof (ibmf_mod_load_args_t));
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_module_load_end,
17347c478bd9Sstevel@tonic-gate 	    IBMF_TNF_TRACE, "", "ibmf_module_load_busy() exit\n");
17357c478bd9Sstevel@tonic-gate }
1736