xref: /onnv-gate/usr/src/uts/common/io/ib/adapters/hermon/hermon_qp.c (revision 12965:b65a8427f8fe)
19517SBill.Taylor@Sun.COM /*
29517SBill.Taylor@Sun.COM  * CDDL HEADER START
39517SBill.Taylor@Sun.COM  *
49517SBill.Taylor@Sun.COM  * The contents of this file are subject to the terms of the
59517SBill.Taylor@Sun.COM  * Common Development and Distribution License (the "License").
69517SBill.Taylor@Sun.COM  * You may not use this file except in compliance with the License.
79517SBill.Taylor@Sun.COM  *
89517SBill.Taylor@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99517SBill.Taylor@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109517SBill.Taylor@Sun.COM  * See the License for the specific language governing permissions
119517SBill.Taylor@Sun.COM  * and limitations under the License.
129517SBill.Taylor@Sun.COM  *
139517SBill.Taylor@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149517SBill.Taylor@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159517SBill.Taylor@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169517SBill.Taylor@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179517SBill.Taylor@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189517SBill.Taylor@Sun.COM  *
199517SBill.Taylor@Sun.COM  * CDDL HEADER END
209517SBill.Taylor@Sun.COM  */
219517SBill.Taylor@Sun.COM 
229517SBill.Taylor@Sun.COM /*
23*12965SWilliam.Taylor@Oracle.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249517SBill.Taylor@Sun.COM  */
259517SBill.Taylor@Sun.COM 
269517SBill.Taylor@Sun.COM /*
279517SBill.Taylor@Sun.COM  * hermon_qp.c
289517SBill.Taylor@Sun.COM  *    Hermon Queue Pair Processing Routines
299517SBill.Taylor@Sun.COM  *
309517SBill.Taylor@Sun.COM  *    Implements all the routines necessary for allocating, freeing, and
319517SBill.Taylor@Sun.COM  *    querying the Hermon queue pairs.
329517SBill.Taylor@Sun.COM  */
339517SBill.Taylor@Sun.COM 
349517SBill.Taylor@Sun.COM #include <sys/types.h>
359517SBill.Taylor@Sun.COM #include <sys/conf.h>
369517SBill.Taylor@Sun.COM #include <sys/ddi.h>
379517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
389517SBill.Taylor@Sun.COM #include <sys/modctl.h>
399517SBill.Taylor@Sun.COM #include <sys/bitmap.h>
409517SBill.Taylor@Sun.COM #include <sys/sysmacros.h>
419517SBill.Taylor@Sun.COM 
429517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
439517SBill.Taylor@Sun.COM #include <sys/ib/ib_pkt_hdrs.h>
449517SBill.Taylor@Sun.COM 
459517SBill.Taylor@Sun.COM static int hermon_qp_create_qpn(hermon_state_t *state, hermon_qphdl_t qp,
469517SBill.Taylor@Sun.COM     hermon_rsrc_t *qpc);
479517SBill.Taylor@Sun.COM static int hermon_qpn_avl_compare(const void *q, const void *e);
489517SBill.Taylor@Sun.COM static int hermon_special_qp_rsrc_alloc(hermon_state_t *state,
499517SBill.Taylor@Sun.COM     ibt_sqp_type_t type, uint_t port, hermon_rsrc_t **qp_rsrc);
509517SBill.Taylor@Sun.COM static int hermon_special_qp_rsrc_free(hermon_state_t *state,
519517SBill.Taylor@Sun.COM     ibt_sqp_type_t type, uint_t port);
529517SBill.Taylor@Sun.COM static void hermon_qp_sgl_to_logwqesz(hermon_state_t *state, uint_t num_sgl,
539517SBill.Taylor@Sun.COM     uint_t real_max_sgl, hermon_qp_wq_type_t wq_type,
549517SBill.Taylor@Sun.COM     uint_t *logwqesz, uint_t *max_sgl);
559517SBill.Taylor@Sun.COM 
569517SBill.Taylor@Sun.COM /*
579517SBill.Taylor@Sun.COM  * hermon_qp_alloc()
589517SBill.Taylor@Sun.COM  *    Context: Can be called only from user or kernel context.
599517SBill.Taylor@Sun.COM  */
609517SBill.Taylor@Sun.COM int
hermon_qp_alloc(hermon_state_t * state,hermon_qp_info_t * qpinfo,uint_t sleepflag)619517SBill.Taylor@Sun.COM hermon_qp_alloc(hermon_state_t *state, hermon_qp_info_t *qpinfo,
629517SBill.Taylor@Sun.COM     uint_t sleepflag)
639517SBill.Taylor@Sun.COM {
649517SBill.Taylor@Sun.COM 	hermon_rsrc_t			*qpc, *rsrc;
65*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_type_t		rsrc_type;
669517SBill.Taylor@Sun.COM 	hermon_umap_db_entry_t		*umapdb;
679517SBill.Taylor@Sun.COM 	hermon_qphdl_t			qp;
689517SBill.Taylor@Sun.COM 	ibt_qp_alloc_attr_t		*attr_p;
69*12965SWilliam.Taylor@Oracle.COM 	ibt_qp_alloc_flags_t		alloc_flags;
709517SBill.Taylor@Sun.COM 	ibt_qp_type_t			type;
719517SBill.Taylor@Sun.COM 	hermon_qp_wq_type_t		swq_type;
729517SBill.Taylor@Sun.COM 	ibtl_qp_hdl_t			ibt_qphdl;
739517SBill.Taylor@Sun.COM 	ibt_chan_sizes_t		*queuesz_p;
749517SBill.Taylor@Sun.COM 	ib_qpn_t			*qpn;
759517SBill.Taylor@Sun.COM 	hermon_qphdl_t			*qphdl;
769517SBill.Taylor@Sun.COM 	ibt_mr_attr_t			mr_attr;
779517SBill.Taylor@Sun.COM 	hermon_mr_options_t		mr_op;
789517SBill.Taylor@Sun.COM 	hermon_srqhdl_t			srq;
799517SBill.Taylor@Sun.COM 	hermon_pdhdl_t			pd;
809517SBill.Taylor@Sun.COM 	hermon_cqhdl_t			sq_cq, rq_cq;
819517SBill.Taylor@Sun.COM 	hermon_mrhdl_t			mr;
829517SBill.Taylor@Sun.COM 	uint64_t			value, qp_desc_off;
839517SBill.Taylor@Sun.COM 	uint64_t			*thewqe, thewqesz;
849517SBill.Taylor@Sun.COM 	uint32_t			*sq_buf, *rq_buf;
859517SBill.Taylor@Sun.COM 	uint32_t			log_qp_sq_size, log_qp_rq_size;
869517SBill.Taylor@Sun.COM 	uint32_t			sq_size, rq_size;
879517SBill.Taylor@Sun.COM 	uint32_t			sq_depth, rq_depth;
889517SBill.Taylor@Sun.COM 	uint32_t			sq_wqe_size, rq_wqe_size, wqesz_shift;
899517SBill.Taylor@Sun.COM 	uint32_t			max_sgl, max_recv_sgl, uarpg;
909517SBill.Taylor@Sun.COM 	uint_t				qp_is_umap;
919517SBill.Taylor@Sun.COM 	uint_t				qp_srq_en, i, j;
929517SBill.Taylor@Sun.COM 	int				status, flag;
939517SBill.Taylor@Sun.COM 
949517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*attr_p, *queuesz_p))
959517SBill.Taylor@Sun.COM 
969517SBill.Taylor@Sun.COM 	/*
979517SBill.Taylor@Sun.COM 	 * Extract the necessary info from the hermon_qp_info_t structure
989517SBill.Taylor@Sun.COM 	 */
999517SBill.Taylor@Sun.COM 	attr_p	  = qpinfo->qpi_attrp;
1009517SBill.Taylor@Sun.COM 	type	  = qpinfo->qpi_type;
1019517SBill.Taylor@Sun.COM 	ibt_qphdl = qpinfo->qpi_ibt_qphdl;
1029517SBill.Taylor@Sun.COM 	queuesz_p = qpinfo->qpi_queueszp;
1039517SBill.Taylor@Sun.COM 	qpn	  = qpinfo->qpi_qpn;
1049517SBill.Taylor@Sun.COM 	qphdl	  = &qpinfo->qpi_qphdl;
105*12965SWilliam.Taylor@Oracle.COM 	alloc_flags = attr_p->qp_alloc_flags;
106*12965SWilliam.Taylor@Oracle.COM 
107*12965SWilliam.Taylor@Oracle.COM 	/*
108*12965SWilliam.Taylor@Oracle.COM 	 * Verify correctness of alloc_flags.
109*12965SWilliam.Taylor@Oracle.COM 	 *
110*12965SWilliam.Taylor@Oracle.COM 	 * 1. FEXCH and RSS are only allocated via qp_range.
111*12965SWilliam.Taylor@Oracle.COM 	 */
112*12965SWilliam.Taylor@Oracle.COM 	if (alloc_flags & (IBT_QP_USES_FEXCH | IBT_QP_USES_RSS)) {
113*12965SWilliam.Taylor@Oracle.COM 		return (IBT_INVALID_PARAM);
114*12965SWilliam.Taylor@Oracle.COM 	}
115*12965SWilliam.Taylor@Oracle.COM 	rsrc_type = HERMON_QPC;
116*12965SWilliam.Taylor@Oracle.COM 	qp_is_umap = 0;
117*12965SWilliam.Taylor@Oracle.COM 
118*12965SWilliam.Taylor@Oracle.COM 	/* 2. Make sure only one of these flags is set. */
119*12965SWilliam.Taylor@Oracle.COM 	switch (alloc_flags &
120*12965SWilliam.Taylor@Oracle.COM 	    (IBT_QP_USER_MAP | IBT_QP_USES_RFCI | IBT_QP_USES_FCMD)) {
121*12965SWilliam.Taylor@Oracle.COM 	case IBT_QP_USER_MAP:
122*12965SWilliam.Taylor@Oracle.COM 		qp_is_umap = 1;
123*12965SWilliam.Taylor@Oracle.COM 		break;
124*12965SWilliam.Taylor@Oracle.COM 	case IBT_QP_USES_RFCI:
125*12965SWilliam.Taylor@Oracle.COM 		if (type != IBT_UD_RQP)
126*12965SWilliam.Taylor@Oracle.COM 			return (IBT_INVALID_PARAM);
127*12965SWilliam.Taylor@Oracle.COM 
128*12965SWilliam.Taylor@Oracle.COM 		switch (attr_p->qp_fc.fc_hca_port) {
129*12965SWilliam.Taylor@Oracle.COM 		case 1:
130*12965SWilliam.Taylor@Oracle.COM 			rsrc_type = HERMON_QPC_RFCI_PORT1;
131*12965SWilliam.Taylor@Oracle.COM 			break;
132*12965SWilliam.Taylor@Oracle.COM 		case 2:
133*12965SWilliam.Taylor@Oracle.COM 			rsrc_type = HERMON_QPC_RFCI_PORT2;
134*12965SWilliam.Taylor@Oracle.COM 			break;
135*12965SWilliam.Taylor@Oracle.COM 		default:
136*12965SWilliam.Taylor@Oracle.COM 			return (IBT_INVALID_PARAM);
137*12965SWilliam.Taylor@Oracle.COM 		}
138*12965SWilliam.Taylor@Oracle.COM 		break;
139*12965SWilliam.Taylor@Oracle.COM 	case IBT_QP_USES_FCMD:
140*12965SWilliam.Taylor@Oracle.COM 		if (type != IBT_UD_RQP)
141*12965SWilliam.Taylor@Oracle.COM 			return (IBT_INVALID_PARAM);
142*12965SWilliam.Taylor@Oracle.COM 		break;
143*12965SWilliam.Taylor@Oracle.COM 	case 0:
144*12965SWilliam.Taylor@Oracle.COM 		break;
145*12965SWilliam.Taylor@Oracle.COM 	default:
146*12965SWilliam.Taylor@Oracle.COM 		return (IBT_INVALID_PARAM);	/* conflicting flags set */
147*12965SWilliam.Taylor@Oracle.COM 	}
1489517SBill.Taylor@Sun.COM 
1499517SBill.Taylor@Sun.COM 	/*
1509517SBill.Taylor@Sun.COM 	 * Determine whether QP is being allocated for userland access or
1519517SBill.Taylor@Sun.COM 	 * whether it is being allocated for kernel access.  If the QP is
1529517SBill.Taylor@Sun.COM 	 * being allocated for userland access, then lookup the UAR
1539517SBill.Taylor@Sun.COM 	 * page number for the current process.  Note:  If this is not found
1549517SBill.Taylor@Sun.COM 	 * (e.g. if the process has not previously open()'d the Hermon driver),
1559517SBill.Taylor@Sun.COM 	 * then an error is returned.
1569517SBill.Taylor@Sun.COM 	 */
1579517SBill.Taylor@Sun.COM 	if (qp_is_umap) {
1589517SBill.Taylor@Sun.COM 		status = hermon_umap_db_find(state->hs_instance, ddi_get_pid(),
1599517SBill.Taylor@Sun.COM 		    MLNX_UMAP_UARPG_RSRC, &value, 0, NULL);
1609517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
161*12965SWilliam.Taylor@Oracle.COM 			return (IBT_INVALID_PARAM);
1629517SBill.Taylor@Sun.COM 		}
1639517SBill.Taylor@Sun.COM 		uarpg = ((hermon_rsrc_t *)(uintptr_t)value)->hr_indx;
1649517SBill.Taylor@Sun.COM 	} else {
1659517SBill.Taylor@Sun.COM 		uarpg = state->hs_kernel_uar_index;
1669517SBill.Taylor@Sun.COM 	}
1679517SBill.Taylor@Sun.COM 
1689517SBill.Taylor@Sun.COM 	/*
1699517SBill.Taylor@Sun.COM 	 * Determine whether QP is being associated with an SRQ
1709517SBill.Taylor@Sun.COM 	 */
171*12965SWilliam.Taylor@Oracle.COM 	qp_srq_en = (alloc_flags & IBT_QP_USES_SRQ) ? 1 : 0;
1729517SBill.Taylor@Sun.COM 	if (qp_srq_en) {
1739517SBill.Taylor@Sun.COM 		/*
1749517SBill.Taylor@Sun.COM 		 * Check for valid SRQ handle pointers
1759517SBill.Taylor@Sun.COM 		 */
1769517SBill.Taylor@Sun.COM 		if (attr_p->qp_ibc_srq_hdl == NULL) {
1779517SBill.Taylor@Sun.COM 			status = IBT_SRQ_HDL_INVALID;
1789517SBill.Taylor@Sun.COM 			goto qpalloc_fail;
1799517SBill.Taylor@Sun.COM 		}
1809517SBill.Taylor@Sun.COM 		srq = (hermon_srqhdl_t)attr_p->qp_ibc_srq_hdl;
1819517SBill.Taylor@Sun.COM 	}
1829517SBill.Taylor@Sun.COM 
1839517SBill.Taylor@Sun.COM 	/*
1849517SBill.Taylor@Sun.COM 	 * Check for valid QP service type (only UD/RC/UC supported)
1859517SBill.Taylor@Sun.COM 	 */
1869517SBill.Taylor@Sun.COM 	if (((type != IBT_UD_RQP) && (type != IBT_RC_RQP) &&
1879517SBill.Taylor@Sun.COM 	    (type != IBT_UC_RQP))) {
1889517SBill.Taylor@Sun.COM 		status = IBT_QP_SRV_TYPE_INVALID;
1899517SBill.Taylor@Sun.COM 		goto qpalloc_fail;
1909517SBill.Taylor@Sun.COM 	}
1919517SBill.Taylor@Sun.COM 
1929517SBill.Taylor@Sun.COM 
1939517SBill.Taylor@Sun.COM 	/*
1949517SBill.Taylor@Sun.COM 	 * Check for valid PD handle pointer
1959517SBill.Taylor@Sun.COM 	 */
1969517SBill.Taylor@Sun.COM 	if (attr_p->qp_pd_hdl == NULL) {
1979517SBill.Taylor@Sun.COM 		status = IBT_PD_HDL_INVALID;
1989517SBill.Taylor@Sun.COM 		goto qpalloc_fail;
1999517SBill.Taylor@Sun.COM 	}
2009517SBill.Taylor@Sun.COM 	pd = (hermon_pdhdl_t)attr_p->qp_pd_hdl;
2019517SBill.Taylor@Sun.COM 
2029517SBill.Taylor@Sun.COM 	/*
2039517SBill.Taylor@Sun.COM 	 * If on an SRQ, check to make sure the PD is the same
2049517SBill.Taylor@Sun.COM 	 */
2059517SBill.Taylor@Sun.COM 	if (qp_srq_en && (pd->pd_pdnum != srq->srq_pdhdl->pd_pdnum)) {
2069517SBill.Taylor@Sun.COM 		status = IBT_PD_HDL_INVALID;
2079517SBill.Taylor@Sun.COM 		goto qpalloc_fail;
2089517SBill.Taylor@Sun.COM 	}
2099517SBill.Taylor@Sun.COM 
2109517SBill.Taylor@Sun.COM 	/* Increment the reference count on the protection domain (PD) */
2119517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_inc(pd);
2129517SBill.Taylor@Sun.COM 
2139517SBill.Taylor@Sun.COM 	/*
2149517SBill.Taylor@Sun.COM 	 * Check for valid CQ handle pointers
215*12965SWilliam.Taylor@Oracle.COM 	 *
216*12965SWilliam.Taylor@Oracle.COM 	 * FCMD QPs do not require a receive cq handle.
2179517SBill.Taylor@Sun.COM 	 */
218*12965SWilliam.Taylor@Oracle.COM 	if (attr_p->qp_ibc_scq_hdl == NULL) {
2199517SBill.Taylor@Sun.COM 		status = IBT_CQ_HDL_INVALID;
2209517SBill.Taylor@Sun.COM 		goto qpalloc_fail1;
2219517SBill.Taylor@Sun.COM 	}
2229517SBill.Taylor@Sun.COM 	sq_cq = (hermon_cqhdl_t)attr_p->qp_ibc_scq_hdl;
223*12965SWilliam.Taylor@Oracle.COM 	if ((attr_p->qp_ibc_rcq_hdl == NULL)) {
224*12965SWilliam.Taylor@Oracle.COM 		if ((alloc_flags & IBT_QP_USES_FCMD) == 0) {
225*12965SWilliam.Taylor@Oracle.COM 			status = IBT_CQ_HDL_INVALID;
226*12965SWilliam.Taylor@Oracle.COM 			goto qpalloc_fail1;
227*12965SWilliam.Taylor@Oracle.COM 		}
228*12965SWilliam.Taylor@Oracle.COM 		rq_cq = sq_cq;	/* just use the send cq */
229*12965SWilliam.Taylor@Oracle.COM 	} else
230*12965SWilliam.Taylor@Oracle.COM 		rq_cq = (hermon_cqhdl_t)attr_p->qp_ibc_rcq_hdl;
2319517SBill.Taylor@Sun.COM 
2329517SBill.Taylor@Sun.COM 	/*
2339517SBill.Taylor@Sun.COM 	 * Increment the reference count on the CQs.  One or both of these
2349517SBill.Taylor@Sun.COM 	 * could return error if we determine that the given CQ is already
2359517SBill.Taylor@Sun.COM 	 * being used with a special (SMI/GSI) QP.
2369517SBill.Taylor@Sun.COM 	 */
2379517SBill.Taylor@Sun.COM 	status = hermon_cq_refcnt_inc(sq_cq, HERMON_CQ_IS_NORMAL);
2389517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
2399517SBill.Taylor@Sun.COM 		status = IBT_CQ_HDL_INVALID;
2409517SBill.Taylor@Sun.COM 		goto qpalloc_fail1;
2419517SBill.Taylor@Sun.COM 	}
2429517SBill.Taylor@Sun.COM 	status = hermon_cq_refcnt_inc(rq_cq, HERMON_CQ_IS_NORMAL);
2439517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
2449517SBill.Taylor@Sun.COM 		status = IBT_CQ_HDL_INVALID;
2459517SBill.Taylor@Sun.COM 		goto qpalloc_fail2;
2469517SBill.Taylor@Sun.COM 	}
2479517SBill.Taylor@Sun.COM 
2489517SBill.Taylor@Sun.COM 	/*
2499517SBill.Taylor@Sun.COM 	 * Allocate an QP context entry.  This will be filled in with all
2509517SBill.Taylor@Sun.COM 	 * the necessary parameters to define the Queue Pair.  Unlike
2519517SBill.Taylor@Sun.COM 	 * other Hermon hardware resources, ownership is not immediately
2529517SBill.Taylor@Sun.COM 	 * given to hardware in the final step here.  Instead, we must
2539517SBill.Taylor@Sun.COM 	 * wait until the QP is later transitioned to the "Init" state before
2549517SBill.Taylor@Sun.COM 	 * passing the QP to hardware.  If we fail here, we must undo all
2559517SBill.Taylor@Sun.COM 	 * the reference count (CQ and PD).
2569517SBill.Taylor@Sun.COM 	 */
257*12965SWilliam.Taylor@Oracle.COM 	status = hermon_rsrc_alloc(state, rsrc_type, 1, sleepflag, &qpc);
2589517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
2599517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
2609517SBill.Taylor@Sun.COM 		goto qpalloc_fail3;
2619517SBill.Taylor@Sun.COM 	}
2629517SBill.Taylor@Sun.COM 
2639517SBill.Taylor@Sun.COM 	/*
2649517SBill.Taylor@Sun.COM 	 * Allocate the software structure for tracking the queue pair
2659517SBill.Taylor@Sun.COM 	 * (i.e. the Hermon Queue Pair handle).  If we fail here, we must
2669517SBill.Taylor@Sun.COM 	 * undo the reference counts and the previous resource allocation.
2679517SBill.Taylor@Sun.COM 	 */
2689517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_QPHDL, 1, sleepflag, &rsrc);
2699517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
2709517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
2719517SBill.Taylor@Sun.COM 		goto qpalloc_fail4;
2729517SBill.Taylor@Sun.COM 	}
2739517SBill.Taylor@Sun.COM 	qp = (hermon_qphdl_t)rsrc->hr_addr;
2749517SBill.Taylor@Sun.COM 	bzero(qp, sizeof (struct hermon_sw_qp_s));
2759517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp))
2769517SBill.Taylor@Sun.COM 
277*12965SWilliam.Taylor@Oracle.COM 	qp->qp_alloc_flags = alloc_flags;
278*12965SWilliam.Taylor@Oracle.COM 
2799517SBill.Taylor@Sun.COM 	/*
2809517SBill.Taylor@Sun.COM 	 * Calculate the QP number from QPC index.  This routine handles
2819517SBill.Taylor@Sun.COM 	 * all of the operations necessary to keep track of used, unused,
2829517SBill.Taylor@Sun.COM 	 * and released QP numbers.
2839517SBill.Taylor@Sun.COM 	 */
284*12965SWilliam.Taylor@Oracle.COM 	if (type == IBT_UD_RQP) {
285*12965SWilliam.Taylor@Oracle.COM 		qp->qp_qpnum = qpc->hr_indx;
286*12965SWilliam.Taylor@Oracle.COM 		qp->qp_ring = qp->qp_qpnum << 8;
287*12965SWilliam.Taylor@Oracle.COM 		qp->qp_qpn_hdl = NULL;
288*12965SWilliam.Taylor@Oracle.COM 	} else {
289*12965SWilliam.Taylor@Oracle.COM 		status = hermon_qp_create_qpn(state, qp, qpc);
290*12965SWilliam.Taylor@Oracle.COM 		if (status != DDI_SUCCESS) {
291*12965SWilliam.Taylor@Oracle.COM 			status = IBT_INSUFF_RESOURCE;
292*12965SWilliam.Taylor@Oracle.COM 			goto qpalloc_fail5;
293*12965SWilliam.Taylor@Oracle.COM 		}
2949517SBill.Taylor@Sun.COM 	}
2959517SBill.Taylor@Sun.COM 
2969517SBill.Taylor@Sun.COM 	/*
2979517SBill.Taylor@Sun.COM 	 * If this will be a user-mappable QP, then allocate an entry for
2989517SBill.Taylor@Sun.COM 	 * the "userland resources database".  This will later be added to
2999517SBill.Taylor@Sun.COM 	 * the database (after all further QP operations are successful).
3009517SBill.Taylor@Sun.COM 	 * If we fail here, we must undo the reference counts and the
3019517SBill.Taylor@Sun.COM 	 * previous resource allocation.
3029517SBill.Taylor@Sun.COM 	 */
3039517SBill.Taylor@Sun.COM 	if (qp_is_umap) {
3049517SBill.Taylor@Sun.COM 		umapdb = hermon_umap_db_alloc(state->hs_instance, qp->qp_qpnum,
3059517SBill.Taylor@Sun.COM 		    MLNX_UMAP_QPMEM_RSRC, (uint64_t)(uintptr_t)rsrc);
3069517SBill.Taylor@Sun.COM 		if (umapdb == NULL) {
3079517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
3089517SBill.Taylor@Sun.COM 			goto qpalloc_fail6;
3099517SBill.Taylor@Sun.COM 		}
3109517SBill.Taylor@Sun.COM 	}
3119517SBill.Taylor@Sun.COM 
3129517SBill.Taylor@Sun.COM 	/*
3139517SBill.Taylor@Sun.COM 	 * Allocate the doorbell record.  Hermon just needs one for the RQ,
3149517SBill.Taylor@Sun.COM 	 * if the QP is not associated with an SRQ, and use uarpg (above) as
3159517SBill.Taylor@Sun.COM 	 * the uar index
3169517SBill.Taylor@Sun.COM 	 */
3179517SBill.Taylor@Sun.COM 
3189517SBill.Taylor@Sun.COM 	if (!qp_srq_en) {
3199517SBill.Taylor@Sun.COM 		status = hermon_dbr_alloc(state, uarpg, &qp->qp_rq_dbr_acchdl,
3209517SBill.Taylor@Sun.COM 		    &qp->qp_rq_vdbr, &qp->qp_rq_pdbr, &qp->qp_rdbr_mapoffset);
3219517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
3229517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
3239517SBill.Taylor@Sun.COM 			goto qpalloc_fail6;
3249517SBill.Taylor@Sun.COM 		}
3259517SBill.Taylor@Sun.COM 	}
3269517SBill.Taylor@Sun.COM 
3279517SBill.Taylor@Sun.COM 	qp->qp_uses_lso = (attr_p->qp_flags & IBT_USES_LSO);
3289517SBill.Taylor@Sun.COM 
3299517SBill.Taylor@Sun.COM 	/*
3309517SBill.Taylor@Sun.COM 	 * We verify that the requested number of SGL is valid (i.e.
3319517SBill.Taylor@Sun.COM 	 * consistent with the device limits and/or software-configured
3329517SBill.Taylor@Sun.COM 	 * limits).  If not, then obviously the same cleanup needs to be done.
3339517SBill.Taylor@Sun.COM 	 */
3349517SBill.Taylor@Sun.COM 	if (type == IBT_UD_RQP) {
3359517SBill.Taylor@Sun.COM 		max_sgl = state->hs_ibtfinfo.hca_attr->hca_ud_send_sgl_sz;
3369517SBill.Taylor@Sun.COM 		swq_type = HERMON_QP_WQ_TYPE_SENDQ_UD;
3379517SBill.Taylor@Sun.COM 	} else {
3389517SBill.Taylor@Sun.COM 		max_sgl = state->hs_ibtfinfo.hca_attr->hca_conn_send_sgl_sz;
3399517SBill.Taylor@Sun.COM 		swq_type = HERMON_QP_WQ_TYPE_SENDQ_CONN;
3409517SBill.Taylor@Sun.COM 	}
3419517SBill.Taylor@Sun.COM 	max_recv_sgl = state->hs_ibtfinfo.hca_attr->hca_recv_sgl_sz;
3429517SBill.Taylor@Sun.COM 	if ((attr_p->qp_sizes.cs_sq_sgl > max_sgl) ||
3439517SBill.Taylor@Sun.COM 	    (!qp_srq_en && (attr_p->qp_sizes.cs_rq_sgl > max_recv_sgl))) {
3449517SBill.Taylor@Sun.COM 		status = IBT_HCA_SGL_EXCEEDED;
3459517SBill.Taylor@Sun.COM 		goto qpalloc_fail7;
3469517SBill.Taylor@Sun.COM 	}
3479517SBill.Taylor@Sun.COM 
3489517SBill.Taylor@Sun.COM 	/*
3499517SBill.Taylor@Sun.COM 	 * Determine this QP's WQE stride (for both the Send and Recv WQEs).
3509517SBill.Taylor@Sun.COM 	 * This will depend on the requested number of SGLs.  Note: this
3519517SBill.Taylor@Sun.COM 	 * has the side-effect of also calculating the real number of SGLs
3529517SBill.Taylor@Sun.COM 	 * (for the calculated WQE size).
3539517SBill.Taylor@Sun.COM 	 *
3549517SBill.Taylor@Sun.COM 	 * For QP's on an SRQ, we set these to 0.
3559517SBill.Taylor@Sun.COM 	 */
3569517SBill.Taylor@Sun.COM 	if (qp_srq_en) {
3579517SBill.Taylor@Sun.COM 		qp->qp_rq_log_wqesz = 0;
3589517SBill.Taylor@Sun.COM 		qp->qp_rq_sgl = 0;
3599517SBill.Taylor@Sun.COM 	} else {
3609517SBill.Taylor@Sun.COM 		hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_rq_sgl,
3619517SBill.Taylor@Sun.COM 		    max_recv_sgl, HERMON_QP_WQ_TYPE_RECVQ,
3629517SBill.Taylor@Sun.COM 		    &qp->qp_rq_log_wqesz, &qp->qp_rq_sgl);
3639517SBill.Taylor@Sun.COM 	}
3649517SBill.Taylor@Sun.COM 	hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_sq_sgl,
3659517SBill.Taylor@Sun.COM 	    max_sgl, swq_type, &qp->qp_sq_log_wqesz, &qp->qp_sq_sgl);
3669517SBill.Taylor@Sun.COM 
3679517SBill.Taylor@Sun.COM 	sq_wqe_size = 1 << qp->qp_sq_log_wqesz;
3689517SBill.Taylor@Sun.COM 
3699517SBill.Taylor@Sun.COM 	/* NOTE: currently policy in driver, later maybe IBTF interface */
3709517SBill.Taylor@Sun.COM 	qp->qp_no_prefetch = 0;
3719517SBill.Taylor@Sun.COM 
3729517SBill.Taylor@Sun.COM 	/*
3739517SBill.Taylor@Sun.COM 	 * for prefetching, we need to add the number of wqes in
3749517SBill.Taylor@Sun.COM 	 * the 2k area plus one to the number requested, but
3759517SBill.Taylor@Sun.COM 	 * ONLY for send queue.  If no_prefetch == 1 (prefetch off)
3769517SBill.Taylor@Sun.COM 	 * it's exactly TWO wqes for the headroom
3779517SBill.Taylor@Sun.COM 	 */
3789517SBill.Taylor@Sun.COM 	if (qp->qp_no_prefetch)
3799517SBill.Taylor@Sun.COM 		qp->qp_sq_headroom = 2 * sq_wqe_size;
3809517SBill.Taylor@Sun.COM 	else
3819517SBill.Taylor@Sun.COM 		qp->qp_sq_headroom = sq_wqe_size + HERMON_QP_OH_SIZE;
3829517SBill.Taylor@Sun.COM 	/*
3839517SBill.Taylor@Sun.COM 	 * hdrm wqes must be integral since both sq_wqe_size &
3849517SBill.Taylor@Sun.COM 	 * HERMON_QP_OH_SIZE are power of 2
3859517SBill.Taylor@Sun.COM 	 */
3869517SBill.Taylor@Sun.COM 	qp->qp_sq_hdrmwqes = (qp->qp_sq_headroom / sq_wqe_size);
3879517SBill.Taylor@Sun.COM 
3889517SBill.Taylor@Sun.COM 
3899517SBill.Taylor@Sun.COM 	/*
3909517SBill.Taylor@Sun.COM 	 * Calculate the appropriate size for the work queues.
3919517SBill.Taylor@Sun.COM 	 * For send queue, add in the headroom wqes to the calculation.
3929517SBill.Taylor@Sun.COM 	 * Note:  All Hermon QP work queues must be a power-of-2 in size.  Also
3939517SBill.Taylor@Sun.COM 	 * they may not be any smaller than HERMON_QP_MIN_SIZE.  This step is
3949517SBill.Taylor@Sun.COM 	 * to round the requested size up to the next highest power-of-2
3959517SBill.Taylor@Sun.COM 	 */
3969517SBill.Taylor@Sun.COM 	/* first, adjust to a minimum and tell the caller the change */
3979517SBill.Taylor@Sun.COM 	attr_p->qp_sizes.cs_sq = max(attr_p->qp_sizes.cs_sq,
3989517SBill.Taylor@Sun.COM 	    HERMON_QP_MIN_SIZE);
3999517SBill.Taylor@Sun.COM 	attr_p->qp_sizes.cs_rq = max(attr_p->qp_sizes.cs_rq,
4009517SBill.Taylor@Sun.COM 	    HERMON_QP_MIN_SIZE);
4019517SBill.Taylor@Sun.COM 	/*
4029517SBill.Taylor@Sun.COM 	 * now, calculate the alloc size, taking into account
4039517SBill.Taylor@Sun.COM 	 * the headroom for the sq
4049517SBill.Taylor@Sun.COM 	 */
4059517SBill.Taylor@Sun.COM 	log_qp_sq_size = highbit(attr_p->qp_sizes.cs_sq + qp->qp_sq_hdrmwqes);
4069517SBill.Taylor@Sun.COM 	/* if the total is a power of two, reduce it */
4079517SBill.Taylor@Sun.COM 	if (((attr_p->qp_sizes.cs_sq + qp->qp_sq_hdrmwqes)  &
4089517SBill.Taylor@Sun.COM 	    (attr_p->qp_sizes.cs_sq + qp->qp_sq_hdrmwqes - 1)) == 0)	{
4099517SBill.Taylor@Sun.COM 		log_qp_sq_size = log_qp_sq_size - 1;
4109517SBill.Taylor@Sun.COM 	}
4119517SBill.Taylor@Sun.COM 
4129517SBill.Taylor@Sun.COM 	log_qp_rq_size = highbit(attr_p->qp_sizes.cs_rq);
4139517SBill.Taylor@Sun.COM 	if ((attr_p->qp_sizes.cs_rq & (attr_p->qp_sizes.cs_rq - 1)) == 0) {
4149517SBill.Taylor@Sun.COM 		log_qp_rq_size = log_qp_rq_size - 1;
4159517SBill.Taylor@Sun.COM 	}
4169517SBill.Taylor@Sun.COM 
4179517SBill.Taylor@Sun.COM 	/*
4189517SBill.Taylor@Sun.COM 	 * Next we verify that the rounded-up size is valid (i.e. consistent
4199517SBill.Taylor@Sun.COM 	 * with the device limits and/or software-configured limits).  If not,
4209517SBill.Taylor@Sun.COM 	 * then obviously we have a lot of cleanup to do before returning.
4219517SBill.Taylor@Sun.COM 	 *
4229517SBill.Taylor@Sun.COM 	 * NOTE: the first condition deals with the (test) case of cs_sq
4239517SBill.Taylor@Sun.COM 	 * being just less than 2^32.  In this case, the headroom addition
4249517SBill.Taylor@Sun.COM 	 * to the requested cs_sq will pass the test when it should not.
4259517SBill.Taylor@Sun.COM 	 * This test no longer lets that case slip through the check.
4269517SBill.Taylor@Sun.COM 	 */
4279517SBill.Taylor@Sun.COM 	if ((attr_p->qp_sizes.cs_sq >
4289517SBill.Taylor@Sun.COM 	    (1 << state->hs_cfg_profile->cp_log_max_qp_sz)) ||
4299517SBill.Taylor@Sun.COM 	    (log_qp_sq_size > state->hs_cfg_profile->cp_log_max_qp_sz) ||
4309517SBill.Taylor@Sun.COM 	    (!qp_srq_en && (log_qp_rq_size >
4319517SBill.Taylor@Sun.COM 	    state->hs_cfg_profile->cp_log_max_qp_sz))) {
4329517SBill.Taylor@Sun.COM 		status = IBT_HCA_WR_EXCEEDED;
4339517SBill.Taylor@Sun.COM 		goto qpalloc_fail7;
4349517SBill.Taylor@Sun.COM 	}
4359517SBill.Taylor@Sun.COM 
4369517SBill.Taylor@Sun.COM 	/*
4379517SBill.Taylor@Sun.COM 	 * Allocate the memory for QP work queues. Since Hermon work queues
4389517SBill.Taylor@Sun.COM 	 * are not allowed to cross a 32-bit (4GB) boundary, the alignment of
4399517SBill.Taylor@Sun.COM 	 * the work queue memory is very important.  We used to allocate
4409517SBill.Taylor@Sun.COM 	 * work queues (the combined receive and send queues) so that they
4419517SBill.Taylor@Sun.COM 	 * would be aligned on their combined size.  That alignment guaranteed
4429517SBill.Taylor@Sun.COM 	 * that they would never cross the 4GB boundary (Hermon work queues
4439517SBill.Taylor@Sun.COM 	 * are on the order of MBs at maximum).  Now we are able to relax
4449517SBill.Taylor@Sun.COM 	 * this alignment constraint by ensuring that the IB address assigned
4459517SBill.Taylor@Sun.COM 	 * to the queue memory (as a result of the hermon_mr_register() call)
4469517SBill.Taylor@Sun.COM 	 * is offset from zero.
4479517SBill.Taylor@Sun.COM 	 * Previously, we had wanted to use the ddi_dma_mem_alloc() routine to
4489517SBill.Taylor@Sun.COM 	 * guarantee the alignment, but when attempting to use IOMMU bypass
4499517SBill.Taylor@Sun.COM 	 * mode we found that we were not allowed to specify any alignment
4509517SBill.Taylor@Sun.COM 	 * that was more restrictive than the system page size.
4519517SBill.Taylor@Sun.COM 	 * So we avoided this constraint by passing two alignment values,
4529517SBill.Taylor@Sun.COM 	 * one for the memory allocation itself and the other for the DMA
4539517SBill.Taylor@Sun.COM 	 * handle (for later bind).  This used to cause more memory than
4549517SBill.Taylor@Sun.COM 	 * necessary to be allocated (in order to guarantee the more
4559517SBill.Taylor@Sun.COM 	 * restrictive alignment contraint).  But by guaranteeing the
4569517SBill.Taylor@Sun.COM 	 * zero-based IB virtual address for the queue, we are able to
4579517SBill.Taylor@Sun.COM 	 * conserve this memory.
4589517SBill.Taylor@Sun.COM 	 */
4599517SBill.Taylor@Sun.COM 	sq_wqe_size = 1 << qp->qp_sq_log_wqesz;
4609517SBill.Taylor@Sun.COM 	sq_depth    = 1 << log_qp_sq_size;
4619517SBill.Taylor@Sun.COM 	sq_size	    = sq_depth * sq_wqe_size;
4629517SBill.Taylor@Sun.COM 
4639517SBill.Taylor@Sun.COM 	/* QP on SRQ sets these to 0 */
4649517SBill.Taylor@Sun.COM 	if (qp_srq_en) {
4659517SBill.Taylor@Sun.COM 		rq_wqe_size = 0;
4669517SBill.Taylor@Sun.COM 		rq_size	    = 0;
4679517SBill.Taylor@Sun.COM 	} else {
4689517SBill.Taylor@Sun.COM 		rq_wqe_size = 1 << qp->qp_rq_log_wqesz;
4699517SBill.Taylor@Sun.COM 		rq_depth    = 1 << log_qp_rq_size;
4709517SBill.Taylor@Sun.COM 		rq_size	    = rq_depth * rq_wqe_size;
4719517SBill.Taylor@Sun.COM 	}
4729517SBill.Taylor@Sun.COM 
4739517SBill.Taylor@Sun.COM 	qp->qp_wqinfo.qa_size = sq_size + rq_size;
4749517SBill.Taylor@Sun.COM 
4759517SBill.Taylor@Sun.COM 	qp->qp_wqinfo.qa_alloc_align = PAGESIZE;
4769517SBill.Taylor@Sun.COM 	qp->qp_wqinfo.qa_bind_align  = PAGESIZE;
4779517SBill.Taylor@Sun.COM 
4789517SBill.Taylor@Sun.COM 	if (qp_is_umap) {
4799517SBill.Taylor@Sun.COM 		qp->qp_wqinfo.qa_location = HERMON_QUEUE_LOCATION_USERLAND;
4809517SBill.Taylor@Sun.COM 	} else {
4819517SBill.Taylor@Sun.COM 		qp->qp_wqinfo.qa_location = HERMON_QUEUE_LOCATION_NORMAL;
4829517SBill.Taylor@Sun.COM 	}
4839517SBill.Taylor@Sun.COM 	status = hermon_queue_alloc(state, &qp->qp_wqinfo, sleepflag);
4849517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
4859517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
4869517SBill.Taylor@Sun.COM 		goto qpalloc_fail7;
4879517SBill.Taylor@Sun.COM 	}
4889517SBill.Taylor@Sun.COM 
4899517SBill.Taylor@Sun.COM 	/*
4909517SBill.Taylor@Sun.COM 	 * Sort WQs in memory according to stride (*q_wqe_size), largest first
4919517SBill.Taylor@Sun.COM 	 * If they are equal, still put the SQ first
4929517SBill.Taylor@Sun.COM 	 */
4939517SBill.Taylor@Sun.COM 	qp->qp_sq_baseaddr = 0;
4949517SBill.Taylor@Sun.COM 	qp->qp_rq_baseaddr = 0;
4959517SBill.Taylor@Sun.COM 	if ((sq_wqe_size > rq_wqe_size) || (sq_wqe_size == rq_wqe_size)) {
4969517SBill.Taylor@Sun.COM 		sq_buf = qp->qp_wqinfo.qa_buf_aligned;
4979517SBill.Taylor@Sun.COM 
4989517SBill.Taylor@Sun.COM 		/* if this QP is on an SRQ, set the rq_buf to NULL */
4999517SBill.Taylor@Sun.COM 		if (qp_srq_en) {
5009517SBill.Taylor@Sun.COM 			rq_buf = NULL;
5019517SBill.Taylor@Sun.COM 		} else {
5029517SBill.Taylor@Sun.COM 			rq_buf = (uint32_t *)((uintptr_t)sq_buf + sq_size);
5039517SBill.Taylor@Sun.COM 			qp->qp_rq_baseaddr = sq_size;
5049517SBill.Taylor@Sun.COM 		}
5059517SBill.Taylor@Sun.COM 	} else {
5069517SBill.Taylor@Sun.COM 		rq_buf = qp->qp_wqinfo.qa_buf_aligned;
5079517SBill.Taylor@Sun.COM 		sq_buf = (uint32_t *)((uintptr_t)rq_buf + rq_size);
5089517SBill.Taylor@Sun.COM 		qp->qp_sq_baseaddr = rq_size;
5099517SBill.Taylor@Sun.COM 	}
5109517SBill.Taylor@Sun.COM 
5119517SBill.Taylor@Sun.COM 	if (qp_is_umap == 0) {
5129517SBill.Taylor@Sun.COM 		qp->qp_sq_wqhdr = hermon_wrid_wqhdr_create(sq_depth);
5139517SBill.Taylor@Sun.COM 		if (qp->qp_sq_wqhdr == NULL) {
5149517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
5159517SBill.Taylor@Sun.COM 			goto qpalloc_fail8;
5169517SBill.Taylor@Sun.COM 		}
5179517SBill.Taylor@Sun.COM 		if (qp_srq_en) {
5189517SBill.Taylor@Sun.COM 			qp->qp_rq_wqavl.wqa_wq = srq->srq_wq_wqhdr;
5199517SBill.Taylor@Sun.COM 			qp->qp_rq_wqavl.wqa_srq_en = 1;
5209517SBill.Taylor@Sun.COM 			qp->qp_rq_wqavl.wqa_srq = srq;
5219517SBill.Taylor@Sun.COM 		} else {
5229517SBill.Taylor@Sun.COM 			qp->qp_rq_wqhdr = hermon_wrid_wqhdr_create(rq_depth);
5239517SBill.Taylor@Sun.COM 			if (qp->qp_rq_wqhdr == NULL) {
5249517SBill.Taylor@Sun.COM 				status = IBT_INSUFF_RESOURCE;
5259517SBill.Taylor@Sun.COM 				goto qpalloc_fail8;
5269517SBill.Taylor@Sun.COM 			}
5279517SBill.Taylor@Sun.COM 			qp->qp_rq_wqavl.wqa_wq = qp->qp_rq_wqhdr;
5289517SBill.Taylor@Sun.COM 		}
5299517SBill.Taylor@Sun.COM 		qp->qp_sq_wqavl.wqa_qpn = qp->qp_qpnum;
5309517SBill.Taylor@Sun.COM 		qp->qp_sq_wqavl.wqa_type = HERMON_WR_SEND;
5319517SBill.Taylor@Sun.COM 		qp->qp_sq_wqavl.wqa_wq = qp->qp_sq_wqhdr;
5329517SBill.Taylor@Sun.COM 		qp->qp_rq_wqavl.wqa_qpn = qp->qp_qpnum;
5339517SBill.Taylor@Sun.COM 		qp->qp_rq_wqavl.wqa_type = HERMON_WR_RECV;
5349517SBill.Taylor@Sun.COM 	}
5359517SBill.Taylor@Sun.COM 
5369517SBill.Taylor@Sun.COM 	/*
5379517SBill.Taylor@Sun.COM 	 * Register the memory for the QP work queues.  The memory for the
5389517SBill.Taylor@Sun.COM 	 * QP must be registered in the Hermon cMPT tables.  This gives us the
5399517SBill.Taylor@Sun.COM 	 * LKey to specify in the QP context later.  Note: The memory for
5409517SBill.Taylor@Sun.COM 	 * Hermon work queues (both Send and Recv) must be contiguous and
5419517SBill.Taylor@Sun.COM 	 * registered as a single memory region.  Note: If the QP memory is
5429517SBill.Taylor@Sun.COM 	 * user-mappable, force DDI_DMA_CONSISTENT mapping. Also, in order to
5439517SBill.Taylor@Sun.COM 	 * meet the alignment restriction, we pass the "mro_bind_override_addr"
5449517SBill.Taylor@Sun.COM 	 * flag in the call to hermon_mr_register(). This guarantees that the
5459517SBill.Taylor@Sun.COM 	 * resulting IB vaddr will be zero-based (modulo the offset into the
5469517SBill.Taylor@Sun.COM 	 * first page). If we fail here, we still have the bunch of resource
5479517SBill.Taylor@Sun.COM 	 * and reference count cleanup to do.
5489517SBill.Taylor@Sun.COM 	 */
5499517SBill.Taylor@Sun.COM 	flag = (sleepflag == HERMON_SLEEP) ? IBT_MR_SLEEP :
5509517SBill.Taylor@Sun.COM 	    IBT_MR_NOSLEEP;
5519517SBill.Taylor@Sun.COM 	mr_attr.mr_vaddr    = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
5529517SBill.Taylor@Sun.COM 	mr_attr.mr_len	    = qp->qp_wqinfo.qa_size;
5539517SBill.Taylor@Sun.COM 	mr_attr.mr_as	    = NULL;
5549517SBill.Taylor@Sun.COM 	mr_attr.mr_flags    = flag;
5559517SBill.Taylor@Sun.COM 	if (qp_is_umap) {
5569517SBill.Taylor@Sun.COM 		mr_op.mro_bind_type = state->hs_cfg_profile->cp_iommu_bypass;
5579517SBill.Taylor@Sun.COM 	} else {
5589517SBill.Taylor@Sun.COM 		/* HERMON_QUEUE_LOCATION_NORMAL */
5599517SBill.Taylor@Sun.COM 		mr_op.mro_bind_type =
5609517SBill.Taylor@Sun.COM 		    state->hs_cfg_profile->cp_iommu_bypass;
5619517SBill.Taylor@Sun.COM 	}
5629517SBill.Taylor@Sun.COM 	mr_op.mro_bind_dmahdl = qp->qp_wqinfo.qa_dmahdl;
5639517SBill.Taylor@Sun.COM 	mr_op.mro_bind_override_addr = 1;
5649517SBill.Taylor@Sun.COM 	status = hermon_mr_register(state, pd, &mr_attr, &mr,
5659517SBill.Taylor@Sun.COM 	    &mr_op, HERMON_QP_CMPT);
5669517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
5679517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
5689517SBill.Taylor@Sun.COM 		goto qpalloc_fail9;
5699517SBill.Taylor@Sun.COM 	}
5709517SBill.Taylor@Sun.COM 
5719517SBill.Taylor@Sun.COM 	/*
5729517SBill.Taylor@Sun.COM 	 * Calculate the offset between the kernel virtual address space
5739517SBill.Taylor@Sun.COM 	 * and the IB virtual address space.  This will be used when
5749517SBill.Taylor@Sun.COM 	 * posting work requests to properly initialize each WQE.
5759517SBill.Taylor@Sun.COM 	 */
5769517SBill.Taylor@Sun.COM 	qp_desc_off = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
5779517SBill.Taylor@Sun.COM 	    (uint64_t)mr->mr_bindinfo.bi_addr;
5789517SBill.Taylor@Sun.COM 
5799517SBill.Taylor@Sun.COM 	/*
5809517SBill.Taylor@Sun.COM 	 * Fill in all the return arguments (if necessary).  This includes
5819517SBill.Taylor@Sun.COM 	 * real work queue sizes (in wqes), real SGLs, and QP number
5829517SBill.Taylor@Sun.COM 	 */
5839517SBill.Taylor@Sun.COM 	if (queuesz_p != NULL) {
5849517SBill.Taylor@Sun.COM 		queuesz_p->cs_sq 	=
5859517SBill.Taylor@Sun.COM 		    (1 << log_qp_sq_size) - qp->qp_sq_hdrmwqes;
5869517SBill.Taylor@Sun.COM 		queuesz_p->cs_sq_sgl	= qp->qp_sq_sgl;
5879517SBill.Taylor@Sun.COM 
5889517SBill.Taylor@Sun.COM 		/* if this QP is on an SRQ, set these to 0 */
5899517SBill.Taylor@Sun.COM 		if (qp_srq_en) {
5909517SBill.Taylor@Sun.COM 			queuesz_p->cs_rq	= 0;
5919517SBill.Taylor@Sun.COM 			queuesz_p->cs_rq_sgl	= 0;
5929517SBill.Taylor@Sun.COM 		} else {
5939517SBill.Taylor@Sun.COM 			queuesz_p->cs_rq	= (1 << log_qp_rq_size);
5949517SBill.Taylor@Sun.COM 			queuesz_p->cs_rq_sgl	= qp->qp_rq_sgl;
5959517SBill.Taylor@Sun.COM 		}
5969517SBill.Taylor@Sun.COM 	}
5979517SBill.Taylor@Sun.COM 	if (qpn != NULL) {
5989517SBill.Taylor@Sun.COM 		*qpn = (ib_qpn_t)qp->qp_qpnum;
5999517SBill.Taylor@Sun.COM 	}
6009517SBill.Taylor@Sun.COM 
6019517SBill.Taylor@Sun.COM 	/*
6029517SBill.Taylor@Sun.COM 	 * Fill in the rest of the Hermon Queue Pair handle.
6039517SBill.Taylor@Sun.COM 	 */
6049517SBill.Taylor@Sun.COM 	qp->qp_qpcrsrcp		= qpc;
6059517SBill.Taylor@Sun.COM 	qp->qp_rsrcp		= rsrc;
6069517SBill.Taylor@Sun.COM 	qp->qp_state		= HERMON_QP_RESET;
607*12965SWilliam.Taylor@Oracle.COM 	HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
6089517SBill.Taylor@Sun.COM 	qp->qp_pdhdl		= pd;
6099517SBill.Taylor@Sun.COM 	qp->qp_mrhdl		= mr;
6109517SBill.Taylor@Sun.COM 	qp->qp_sq_sigtype	= (attr_p->qp_flags & IBT_WR_SIGNALED) ?
6119517SBill.Taylor@Sun.COM 	    HERMON_QP_SQ_WR_SIGNALED : HERMON_QP_SQ_ALL_SIGNALED;
6129517SBill.Taylor@Sun.COM 	qp->qp_is_special	= 0;
6139517SBill.Taylor@Sun.COM 	qp->qp_uarpg		= uarpg;
6149517SBill.Taylor@Sun.COM 	qp->qp_umap_dhp		= (devmap_cookie_t)NULL;
6159517SBill.Taylor@Sun.COM 	qp->qp_sq_cqhdl		= sq_cq;
6169517SBill.Taylor@Sun.COM 	qp->qp_sq_bufsz		= (1 << log_qp_sq_size);
6179517SBill.Taylor@Sun.COM 	qp->qp_sq_logqsz	= log_qp_sq_size;
6189517SBill.Taylor@Sun.COM 	qp->qp_sq_buf		= sq_buf;
6199517SBill.Taylor@Sun.COM 	qp->qp_desc_off		= qp_desc_off;
6209517SBill.Taylor@Sun.COM 	qp->qp_rq_cqhdl		= rq_cq;
6219517SBill.Taylor@Sun.COM 	qp->qp_rq_buf		= rq_buf;
6229517SBill.Taylor@Sun.COM 	qp->qp_rlky		= (attr_p->qp_flags & IBT_FAST_REG_RES_LKEY) !=
6239517SBill.Taylor@Sun.COM 	    0;
6249517SBill.Taylor@Sun.COM 
6259517SBill.Taylor@Sun.COM 	/* if this QP is on an SRQ, set rq_bufsz to 0 */
6269517SBill.Taylor@Sun.COM 	if (qp_srq_en) {
6279517SBill.Taylor@Sun.COM 		qp->qp_rq_bufsz		= 0;
6289517SBill.Taylor@Sun.COM 		qp->qp_rq_logqsz	= 0;
6299517SBill.Taylor@Sun.COM 	} else {
6309517SBill.Taylor@Sun.COM 		qp->qp_rq_bufsz		= (1 << log_qp_rq_size);
6319517SBill.Taylor@Sun.COM 		qp->qp_rq_logqsz	= log_qp_rq_size;
6329517SBill.Taylor@Sun.COM 	}
6339517SBill.Taylor@Sun.COM 
6349517SBill.Taylor@Sun.COM 	qp->qp_forward_sqd_event  = 0;
6359517SBill.Taylor@Sun.COM 	qp->qp_sqd_still_draining = 0;
6369517SBill.Taylor@Sun.COM 	qp->qp_hdlrarg		= (void *)ibt_qphdl;
6379517SBill.Taylor@Sun.COM 	qp->qp_mcg_refcnt	= 0;
6389517SBill.Taylor@Sun.COM 
6399517SBill.Taylor@Sun.COM 	/*
6409517SBill.Taylor@Sun.COM 	 * If this QP is to be associated with an SRQ, set the SRQ handle
6419517SBill.Taylor@Sun.COM 	 */
6429517SBill.Taylor@Sun.COM 	if (qp_srq_en) {
6439517SBill.Taylor@Sun.COM 		qp->qp_srqhdl = srq;
6449517SBill.Taylor@Sun.COM 		hermon_srq_refcnt_inc(qp->qp_srqhdl);
6459517SBill.Taylor@Sun.COM 	} else {
6469517SBill.Taylor@Sun.COM 		qp->qp_srqhdl = NULL;
6479517SBill.Taylor@Sun.COM 	}
6489517SBill.Taylor@Sun.COM 
6499517SBill.Taylor@Sun.COM 	/* Determine the QP service type */
650*12965SWilliam.Taylor@Oracle.COM 	qp->qp_type = type;
6519517SBill.Taylor@Sun.COM 	if (type == IBT_RC_RQP) {
6529517SBill.Taylor@Sun.COM 		qp->qp_serv_type = HERMON_QP_RC;
6539517SBill.Taylor@Sun.COM 	} else if (type == IBT_UD_RQP) {
654*12965SWilliam.Taylor@Oracle.COM 		if (alloc_flags & IBT_QP_USES_RFCI)
655*12965SWilliam.Taylor@Oracle.COM 			qp->qp_serv_type = HERMON_QP_RFCI;
656*12965SWilliam.Taylor@Oracle.COM 		else if (alloc_flags & IBT_QP_USES_FCMD)
657*12965SWilliam.Taylor@Oracle.COM 			qp->qp_serv_type = HERMON_QP_FCMND;
658*12965SWilliam.Taylor@Oracle.COM 		else
659*12965SWilliam.Taylor@Oracle.COM 			qp->qp_serv_type = HERMON_QP_UD;
6609517SBill.Taylor@Sun.COM 	} else {
6619517SBill.Taylor@Sun.COM 		qp->qp_serv_type = HERMON_QP_UC;
6629517SBill.Taylor@Sun.COM 	}
6639517SBill.Taylor@Sun.COM 
6649517SBill.Taylor@Sun.COM 	/*
6659517SBill.Taylor@Sun.COM 	 * Initialize the RQ WQEs - unlike Arbel, no Rcv init is needed
6669517SBill.Taylor@Sun.COM 	 */
6679517SBill.Taylor@Sun.COM 
6689517SBill.Taylor@Sun.COM 	/*
6699517SBill.Taylor@Sun.COM 	 * Initialize the SQ WQEs - all that needs to be done is every 64 bytes
6709517SBill.Taylor@Sun.COM 	 * set the quadword to all F's - high-order bit is owner (init to one)
6719517SBill.Taylor@Sun.COM 	 * and the rest for the headroom definition of prefetching
6729517SBill.Taylor@Sun.COM 	 *
6739517SBill.Taylor@Sun.COM 	 */
6749517SBill.Taylor@Sun.COM 	wqesz_shift = qp->qp_sq_log_wqesz;
6759517SBill.Taylor@Sun.COM 	thewqesz    = 1 << wqesz_shift;
6769517SBill.Taylor@Sun.COM 	thewqe = (uint64_t *)(void *)(qp->qp_sq_buf);
6779517SBill.Taylor@Sun.COM 	if (qp_is_umap == 0) {
6789517SBill.Taylor@Sun.COM 		for (i = 0; i < sq_depth; i++) {
6799517SBill.Taylor@Sun.COM 			/*
6809517SBill.Taylor@Sun.COM 			 * for each stride, go through and every 64 bytes
6819517SBill.Taylor@Sun.COM 			 * write the init value - having set the address
6829517SBill.Taylor@Sun.COM 			 * once, just keep incrementing it
6839517SBill.Taylor@Sun.COM 			 */
6849517SBill.Taylor@Sun.COM 			for (j = 0; j < thewqesz; j += 64, thewqe += 8) {
6859517SBill.Taylor@Sun.COM 				*(uint32_t *)thewqe = 0xFFFFFFFF;
6869517SBill.Taylor@Sun.COM 			}
6879517SBill.Taylor@Sun.COM 		}
6889517SBill.Taylor@Sun.COM 	}
6899517SBill.Taylor@Sun.COM 
6909517SBill.Taylor@Sun.COM 	/* Zero out the QP context */
6919517SBill.Taylor@Sun.COM 	bzero(&qp->qpc, sizeof (hermon_hw_qpc_t));
6929517SBill.Taylor@Sun.COM 
6939517SBill.Taylor@Sun.COM 	/*
6949517SBill.Taylor@Sun.COM 	 * Put QP handle in Hermon QPNum-to-QPHdl list.  Then fill in the
6959517SBill.Taylor@Sun.COM 	 * "qphdl" and return success
6969517SBill.Taylor@Sun.COM 	 */
697*12965SWilliam.Taylor@Oracle.COM 	hermon_icm_set_num_to_hdl(state, HERMON_QPC, qpc->hr_indx, qp);
6989517SBill.Taylor@Sun.COM 
6999517SBill.Taylor@Sun.COM 	/*
7009517SBill.Taylor@Sun.COM 	 * If this is a user-mappable QP, then we need to insert the previously
7019517SBill.Taylor@Sun.COM 	 * allocated entry into the "userland resources database".  This will
7029517SBill.Taylor@Sun.COM 	 * allow for later lookup during devmap() (i.e. mmap()) calls.
7039517SBill.Taylor@Sun.COM 	 */
7049517SBill.Taylor@Sun.COM 	if (qp_is_umap) {
7059517SBill.Taylor@Sun.COM 		hermon_umap_db_add(umapdb);
7069517SBill.Taylor@Sun.COM 	}
7079517SBill.Taylor@Sun.COM 	mutex_init(&qp->qp_sq_lock, NULL, MUTEX_DRIVER,
7089517SBill.Taylor@Sun.COM 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
7099517SBill.Taylor@Sun.COM 
7109517SBill.Taylor@Sun.COM 	*qphdl = qp;
7119517SBill.Taylor@Sun.COM 
7129517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
7139517SBill.Taylor@Sun.COM 
7149517SBill.Taylor@Sun.COM /*
7159517SBill.Taylor@Sun.COM  * The following is cleanup for all possible failure cases in this routine
7169517SBill.Taylor@Sun.COM  */
7179517SBill.Taylor@Sun.COM qpalloc_fail9:
7189517SBill.Taylor@Sun.COM 	hermon_queue_free(&qp->qp_wqinfo);
7199517SBill.Taylor@Sun.COM qpalloc_fail8:
7209517SBill.Taylor@Sun.COM 	if (qp->qp_sq_wqhdr)
7219517SBill.Taylor@Sun.COM 		hermon_wrid_wqhdr_destroy(qp->qp_sq_wqhdr);
7229517SBill.Taylor@Sun.COM 	if (qp->qp_rq_wqhdr)
7239517SBill.Taylor@Sun.COM 		hermon_wrid_wqhdr_destroy(qp->qp_rq_wqhdr);
7249517SBill.Taylor@Sun.COM qpalloc_fail7:
7259517SBill.Taylor@Sun.COM 	if (qp_is_umap) {
7269517SBill.Taylor@Sun.COM 		hermon_umap_db_free(umapdb);
7279517SBill.Taylor@Sun.COM 	}
7289517SBill.Taylor@Sun.COM 	if (!qp_srq_en) {
7299517SBill.Taylor@Sun.COM 		hermon_dbr_free(state, uarpg, qp->qp_rq_vdbr);
7309517SBill.Taylor@Sun.COM 	}
7319517SBill.Taylor@Sun.COM 
7329517SBill.Taylor@Sun.COM qpalloc_fail6:
7339517SBill.Taylor@Sun.COM 	/*
7349517SBill.Taylor@Sun.COM 	 * Releasing the QPN will also free up the QPC context.  Update
7359517SBill.Taylor@Sun.COM 	 * the QPC context pointer to indicate this.
7369517SBill.Taylor@Sun.COM 	 */
737*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_qpn_hdl) {
738*12965SWilliam.Taylor@Oracle.COM 		hermon_qp_release_qpn(state, qp->qp_qpn_hdl,
739*12965SWilliam.Taylor@Oracle.COM 		    HERMON_QPN_RELEASE);
740*12965SWilliam.Taylor@Oracle.COM 	} else {
741*12965SWilliam.Taylor@Oracle.COM 		hermon_rsrc_free(state, &qpc);
742*12965SWilliam.Taylor@Oracle.COM 	}
7439517SBill.Taylor@Sun.COM 	qpc = NULL;
7449517SBill.Taylor@Sun.COM qpalloc_fail5:
7459517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
7469517SBill.Taylor@Sun.COM qpalloc_fail4:
7479517SBill.Taylor@Sun.COM 	if (qpc) {
7489517SBill.Taylor@Sun.COM 		hermon_rsrc_free(state, &qpc);
7499517SBill.Taylor@Sun.COM 	}
7509517SBill.Taylor@Sun.COM qpalloc_fail3:
7519517SBill.Taylor@Sun.COM 	hermon_cq_refcnt_dec(rq_cq);
7529517SBill.Taylor@Sun.COM qpalloc_fail2:
7539517SBill.Taylor@Sun.COM 	hermon_cq_refcnt_dec(sq_cq);
7549517SBill.Taylor@Sun.COM qpalloc_fail1:
7559517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
7569517SBill.Taylor@Sun.COM qpalloc_fail:
7579517SBill.Taylor@Sun.COM 	return (status);
7589517SBill.Taylor@Sun.COM }
7599517SBill.Taylor@Sun.COM 
7609517SBill.Taylor@Sun.COM 
7619517SBill.Taylor@Sun.COM 
7629517SBill.Taylor@Sun.COM /*
7639517SBill.Taylor@Sun.COM  * hermon_special_qp_alloc()
7649517SBill.Taylor@Sun.COM  *    Context: Can be called only from user or kernel context.
7659517SBill.Taylor@Sun.COM  */
7669517SBill.Taylor@Sun.COM int
hermon_special_qp_alloc(hermon_state_t * state,hermon_qp_info_t * qpinfo,uint_t sleepflag)7679517SBill.Taylor@Sun.COM hermon_special_qp_alloc(hermon_state_t *state, hermon_qp_info_t *qpinfo,
7689517SBill.Taylor@Sun.COM     uint_t sleepflag)
7699517SBill.Taylor@Sun.COM {
7709517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*qpc, *rsrc;
7719517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
7729517SBill.Taylor@Sun.COM 	ibt_qp_alloc_attr_t	*attr_p;
7739517SBill.Taylor@Sun.COM 	ibt_sqp_type_t		type;
7749517SBill.Taylor@Sun.COM 	uint8_t			port;
7759517SBill.Taylor@Sun.COM 	ibtl_qp_hdl_t		ibt_qphdl;
7769517SBill.Taylor@Sun.COM 	ibt_chan_sizes_t	*queuesz_p;
7779517SBill.Taylor@Sun.COM 	hermon_qphdl_t		*qphdl;
7789517SBill.Taylor@Sun.COM 	ibt_mr_attr_t		mr_attr;
7799517SBill.Taylor@Sun.COM 	hermon_mr_options_t	mr_op;
7809517SBill.Taylor@Sun.COM 	hermon_pdhdl_t		pd;
7819517SBill.Taylor@Sun.COM 	hermon_cqhdl_t		sq_cq, rq_cq;
7829517SBill.Taylor@Sun.COM 	hermon_mrhdl_t		mr;
7839517SBill.Taylor@Sun.COM 	uint64_t		qp_desc_off;
7849517SBill.Taylor@Sun.COM 	uint64_t		*thewqe, thewqesz;
7859517SBill.Taylor@Sun.COM 	uint32_t		*sq_buf, *rq_buf;
7869517SBill.Taylor@Sun.COM 	uint32_t		log_qp_sq_size, log_qp_rq_size;
7879517SBill.Taylor@Sun.COM 	uint32_t		sq_size, rq_size, max_sgl;
7889517SBill.Taylor@Sun.COM 	uint32_t		uarpg;
7899517SBill.Taylor@Sun.COM 	uint32_t		sq_depth;
7909517SBill.Taylor@Sun.COM 	uint32_t		sq_wqe_size, rq_wqe_size, wqesz_shift;
7919517SBill.Taylor@Sun.COM 	int			status, flag, i, j;
7929517SBill.Taylor@Sun.COM 
7939517SBill.Taylor@Sun.COM 	/*
7949517SBill.Taylor@Sun.COM 	 * Extract the necessary info from the hermon_qp_info_t structure
7959517SBill.Taylor@Sun.COM 	 */
7969517SBill.Taylor@Sun.COM 	attr_p	  = qpinfo->qpi_attrp;
7979517SBill.Taylor@Sun.COM 	type	  = qpinfo->qpi_type;
7989517SBill.Taylor@Sun.COM 	port	  = qpinfo->qpi_port;
7999517SBill.Taylor@Sun.COM 	ibt_qphdl = qpinfo->qpi_ibt_qphdl;
8009517SBill.Taylor@Sun.COM 	queuesz_p = qpinfo->qpi_queueszp;
8019517SBill.Taylor@Sun.COM 	qphdl	  = &qpinfo->qpi_qphdl;
8029517SBill.Taylor@Sun.COM 
8039517SBill.Taylor@Sun.COM 	/*
8049517SBill.Taylor@Sun.COM 	 * Check for valid special QP type (only SMI & GSI supported)
8059517SBill.Taylor@Sun.COM 	 */
8069517SBill.Taylor@Sun.COM 	if ((type != IBT_SMI_SQP) && (type != IBT_GSI_SQP)) {
8079517SBill.Taylor@Sun.COM 		status = IBT_QP_SPECIAL_TYPE_INVALID;
8089517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail;
8099517SBill.Taylor@Sun.COM 	}
8109517SBill.Taylor@Sun.COM 
8119517SBill.Taylor@Sun.COM 	/*
8129517SBill.Taylor@Sun.COM 	 * Check for valid port number
8139517SBill.Taylor@Sun.COM 	 */
8149517SBill.Taylor@Sun.COM 	if (!hermon_portnum_is_valid(state, port)) {
8159517SBill.Taylor@Sun.COM 		status = IBT_HCA_PORT_INVALID;
8169517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail;
8179517SBill.Taylor@Sun.COM 	}
8189517SBill.Taylor@Sun.COM 	port = port - 1;
8199517SBill.Taylor@Sun.COM 
8209517SBill.Taylor@Sun.COM 	/*
8219517SBill.Taylor@Sun.COM 	 * Check for valid PD handle pointer
8229517SBill.Taylor@Sun.COM 	 */
8239517SBill.Taylor@Sun.COM 	if (attr_p->qp_pd_hdl == NULL) {
8249517SBill.Taylor@Sun.COM 		status = IBT_PD_HDL_INVALID;
8259517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail;
8269517SBill.Taylor@Sun.COM 	}
8279517SBill.Taylor@Sun.COM 	pd = (hermon_pdhdl_t)attr_p->qp_pd_hdl;
8289517SBill.Taylor@Sun.COM 
8299517SBill.Taylor@Sun.COM 	/* Increment the reference count on the PD */
8309517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_inc(pd);
8319517SBill.Taylor@Sun.COM 
8329517SBill.Taylor@Sun.COM 	/*
8339517SBill.Taylor@Sun.COM 	 * Check for valid CQ handle pointers
8349517SBill.Taylor@Sun.COM 	 */
8359517SBill.Taylor@Sun.COM 	if ((attr_p->qp_ibc_scq_hdl == NULL) ||
8369517SBill.Taylor@Sun.COM 	    (attr_p->qp_ibc_rcq_hdl == NULL)) {
8379517SBill.Taylor@Sun.COM 		status = IBT_CQ_HDL_INVALID;
8389517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail1;
8399517SBill.Taylor@Sun.COM 	}
8409517SBill.Taylor@Sun.COM 	sq_cq = (hermon_cqhdl_t)attr_p->qp_ibc_scq_hdl;
8419517SBill.Taylor@Sun.COM 	rq_cq = (hermon_cqhdl_t)attr_p->qp_ibc_rcq_hdl;
8429517SBill.Taylor@Sun.COM 
8439517SBill.Taylor@Sun.COM 	/*
8449517SBill.Taylor@Sun.COM 	 * Increment the reference count on the CQs.  One or both of these
8459517SBill.Taylor@Sun.COM 	 * could return error if we determine that the given CQ is already
8469517SBill.Taylor@Sun.COM 	 * being used with a non-special QP (i.e. a normal QP).
8479517SBill.Taylor@Sun.COM 	 */
8489517SBill.Taylor@Sun.COM 	status = hermon_cq_refcnt_inc(sq_cq, HERMON_CQ_IS_SPECIAL);
8499517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
8509517SBill.Taylor@Sun.COM 		status = IBT_CQ_HDL_INVALID;
8519517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail1;
8529517SBill.Taylor@Sun.COM 	}
8539517SBill.Taylor@Sun.COM 	status = hermon_cq_refcnt_inc(rq_cq, HERMON_CQ_IS_SPECIAL);
8549517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
8559517SBill.Taylor@Sun.COM 		status = IBT_CQ_HDL_INVALID;
8569517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail2;
8579517SBill.Taylor@Sun.COM 	}
8589517SBill.Taylor@Sun.COM 
8599517SBill.Taylor@Sun.COM 	/*
8609517SBill.Taylor@Sun.COM 	 * Allocate the special QP resources.  Essentially, this allocation
8619517SBill.Taylor@Sun.COM 	 * amounts to checking if the request special QP has already been
8629517SBill.Taylor@Sun.COM 	 * allocated.  If successful, the QP context return is an actual
8639517SBill.Taylor@Sun.COM 	 * QP context that has been "aliased" to act as a special QP of the
8649517SBill.Taylor@Sun.COM 	 * appropriate type (and for the appropriate port).  Just as in
8659517SBill.Taylor@Sun.COM 	 * hermon_qp_alloc() above, ownership for this QP context is not
8669517SBill.Taylor@Sun.COM 	 * immediately given to hardware in the final step here.  Instead, we
8679517SBill.Taylor@Sun.COM 	 * wait until the QP is later transitioned to the "Init" state before
8689517SBill.Taylor@Sun.COM 	 * passing the QP to hardware.  If we fail here, we must undo all
8699517SBill.Taylor@Sun.COM 	 * the reference count (CQ and PD).
8709517SBill.Taylor@Sun.COM 	 */
8719517SBill.Taylor@Sun.COM 	status = hermon_special_qp_rsrc_alloc(state, type, port, &qpc);
8729517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
8739517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail3;
8749517SBill.Taylor@Sun.COM 	}
8759517SBill.Taylor@Sun.COM 
8769517SBill.Taylor@Sun.COM 	/*
8779517SBill.Taylor@Sun.COM 	 * Allocate the software structure for tracking the special queue
8789517SBill.Taylor@Sun.COM 	 * pair (i.e. the Hermon Queue Pair handle).  If we fail here, we
8799517SBill.Taylor@Sun.COM 	 * must undo the reference counts and the previous resource allocation.
8809517SBill.Taylor@Sun.COM 	 */
8819517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_QPHDL, 1, sleepflag, &rsrc);
8829517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
8839517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
8849517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail4;
8859517SBill.Taylor@Sun.COM 	}
8869517SBill.Taylor@Sun.COM 	qp = (hermon_qphdl_t)rsrc->hr_addr;
8879517SBill.Taylor@Sun.COM 
8889517SBill.Taylor@Sun.COM 	bzero(qp, sizeof (struct hermon_sw_qp_s));
8899517SBill.Taylor@Sun.COM 
8909517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp))
891*12965SWilliam.Taylor@Oracle.COM 	qp->qp_alloc_flags = attr_p->qp_alloc_flags;
8929517SBill.Taylor@Sun.COM 
8939517SBill.Taylor@Sun.COM 	/*
8949517SBill.Taylor@Sun.COM 	 * Actual QP number is a combination of the index of the QPC and
8959517SBill.Taylor@Sun.COM 	 * the port number.  This is because the special QP contexts must
8969517SBill.Taylor@Sun.COM 	 * be allocated two-at-a-time.
8979517SBill.Taylor@Sun.COM 	 */
8989517SBill.Taylor@Sun.COM 	qp->qp_qpnum = qpc->hr_indx + port;
8999517SBill.Taylor@Sun.COM 	qp->qp_ring = qp->qp_qpnum << 8;
9009517SBill.Taylor@Sun.COM 
9019517SBill.Taylor@Sun.COM 	uarpg = state->hs_kernel_uar_index; /* must be for spec qp */
9029517SBill.Taylor@Sun.COM 	/*
9039517SBill.Taylor@Sun.COM 	 * Allocate the doorbell record.  Hermon uses only one for the RQ so
9049517SBill.Taylor@Sun.COM 	 * alloc a qp doorbell, using uarpg (above) as the uar index
9059517SBill.Taylor@Sun.COM 	 */
9069517SBill.Taylor@Sun.COM 
9079517SBill.Taylor@Sun.COM 	status = hermon_dbr_alloc(state, uarpg, &qp->qp_rq_dbr_acchdl,
9089517SBill.Taylor@Sun.COM 	    &qp->qp_rq_vdbr, &qp->qp_rq_pdbr, &qp->qp_rdbr_mapoffset);
9099517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
9109517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
9119517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail5;
9129517SBill.Taylor@Sun.COM 	}
9139517SBill.Taylor@Sun.COM 	/*
9149517SBill.Taylor@Sun.COM 	 * Calculate the appropriate size for the work queues.
9159517SBill.Taylor@Sun.COM 	 * Note:  All Hermon QP work queues must be a power-of-2 in size.  Also
9169517SBill.Taylor@Sun.COM 	 * they may not be any smaller than HERMON_QP_MIN_SIZE.  This step is
9179517SBill.Taylor@Sun.COM 	 * to round the requested size up to the next highest power-of-2
9189517SBill.Taylor@Sun.COM 	 */
9199517SBill.Taylor@Sun.COM 	attr_p->qp_sizes.cs_sq =
9209517SBill.Taylor@Sun.COM 	    max(attr_p->qp_sizes.cs_sq, HERMON_QP_MIN_SIZE);
9219517SBill.Taylor@Sun.COM 	attr_p->qp_sizes.cs_rq =
9229517SBill.Taylor@Sun.COM 	    max(attr_p->qp_sizes.cs_rq, HERMON_QP_MIN_SIZE);
9239517SBill.Taylor@Sun.COM 	log_qp_sq_size = highbit(attr_p->qp_sizes.cs_sq);
9249517SBill.Taylor@Sun.COM 	if ((attr_p->qp_sizes.cs_sq & (attr_p->qp_sizes.cs_sq - 1)) == 0) {
9259517SBill.Taylor@Sun.COM 		log_qp_sq_size = log_qp_sq_size - 1;
9269517SBill.Taylor@Sun.COM 	}
9279517SBill.Taylor@Sun.COM 	log_qp_rq_size = highbit(attr_p->qp_sizes.cs_rq);
9289517SBill.Taylor@Sun.COM 	if ((attr_p->qp_sizes.cs_rq & (attr_p->qp_sizes.cs_rq - 1)) == 0) {
9299517SBill.Taylor@Sun.COM 		log_qp_rq_size = log_qp_rq_size - 1;
9309517SBill.Taylor@Sun.COM 	}
9319517SBill.Taylor@Sun.COM 
9329517SBill.Taylor@Sun.COM 	/*
9339517SBill.Taylor@Sun.COM 	 * Next we verify that the rounded-up size is valid (i.e. consistent
9349517SBill.Taylor@Sun.COM 	 * with the device limits and/or software-configured limits).  If not,
9359517SBill.Taylor@Sun.COM 	 * then obviously we have a bit of cleanup to do before returning.
9369517SBill.Taylor@Sun.COM 	 */
9379517SBill.Taylor@Sun.COM 	if ((log_qp_sq_size > state->hs_cfg_profile->cp_log_max_qp_sz) ||
9389517SBill.Taylor@Sun.COM 	    (log_qp_rq_size > state->hs_cfg_profile->cp_log_max_qp_sz)) {
9399517SBill.Taylor@Sun.COM 		status = IBT_HCA_WR_EXCEEDED;
9409517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail5a;
9419517SBill.Taylor@Sun.COM 	}
9429517SBill.Taylor@Sun.COM 
9439517SBill.Taylor@Sun.COM 	/*
9449517SBill.Taylor@Sun.COM 	 * Next we verify that the requested number of SGL is valid (i.e.
9459517SBill.Taylor@Sun.COM 	 * consistent with the device limits and/or software-configured
9469517SBill.Taylor@Sun.COM 	 * limits).  If not, then obviously the same cleanup needs to be done.
9479517SBill.Taylor@Sun.COM 	 */
9489517SBill.Taylor@Sun.COM 	max_sgl = state->hs_cfg_profile->cp_wqe_real_max_sgl;
9499517SBill.Taylor@Sun.COM 	if ((attr_p->qp_sizes.cs_sq_sgl > max_sgl) ||
9509517SBill.Taylor@Sun.COM 	    (attr_p->qp_sizes.cs_rq_sgl > max_sgl)) {
9519517SBill.Taylor@Sun.COM 		status = IBT_HCA_SGL_EXCEEDED;
9529517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail5a;
9539517SBill.Taylor@Sun.COM 	}
9549517SBill.Taylor@Sun.COM 
9559517SBill.Taylor@Sun.COM 	/*
9569517SBill.Taylor@Sun.COM 	 * Determine this QP's WQE stride (for both the Send and Recv WQEs).
9579517SBill.Taylor@Sun.COM 	 * This will depend on the requested number of SGLs.  Note: this
9589517SBill.Taylor@Sun.COM 	 * has the side-effect of also calculating the real number of SGLs
9599517SBill.Taylor@Sun.COM 	 * (for the calculated WQE size).
9609517SBill.Taylor@Sun.COM 	 */
9619517SBill.Taylor@Sun.COM 	hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_rq_sgl,
9629517SBill.Taylor@Sun.COM 	    max_sgl, HERMON_QP_WQ_TYPE_RECVQ,
9639517SBill.Taylor@Sun.COM 	    &qp->qp_rq_log_wqesz, &qp->qp_rq_sgl);
9649517SBill.Taylor@Sun.COM 	if (type == IBT_SMI_SQP) {
9659517SBill.Taylor@Sun.COM 		hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_sq_sgl,
9669517SBill.Taylor@Sun.COM 		    max_sgl, HERMON_QP_WQ_TYPE_SENDMLX_QP0,
9679517SBill.Taylor@Sun.COM 		    &qp->qp_sq_log_wqesz, &qp->qp_sq_sgl);
9689517SBill.Taylor@Sun.COM 	} else {
9699517SBill.Taylor@Sun.COM 		hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_sq_sgl,
9709517SBill.Taylor@Sun.COM 		    max_sgl, HERMON_QP_WQ_TYPE_SENDMLX_QP1,
9719517SBill.Taylor@Sun.COM 		    &qp->qp_sq_log_wqesz, &qp->qp_sq_sgl);
9729517SBill.Taylor@Sun.COM 	}
9739517SBill.Taylor@Sun.COM 
9749517SBill.Taylor@Sun.COM 	/*
9759517SBill.Taylor@Sun.COM 	 * Allocate the memory for QP work queues. Since Hermon work queues
9769517SBill.Taylor@Sun.COM 	 * are not allowed to cross a 32-bit (4GB) boundary, the alignment of
9779517SBill.Taylor@Sun.COM 	 * the work queue memory is very important.  We used to allocate
9789517SBill.Taylor@Sun.COM 	 * work queues (the combined receive and send queues) so that they
9799517SBill.Taylor@Sun.COM 	 * would be aligned on their combined size.  That alignment guaranteed
9809517SBill.Taylor@Sun.COM 	 * that they would never cross the 4GB boundary (Hermon work queues
9819517SBill.Taylor@Sun.COM 	 * are on the order of MBs at maximum).  Now we are able to relax
9829517SBill.Taylor@Sun.COM 	 * this alignment constraint by ensuring that the IB address assigned
9839517SBill.Taylor@Sun.COM 	 * to the queue memory (as a result of the hermon_mr_register() call)
9849517SBill.Taylor@Sun.COM 	 * is offset from zero.
9859517SBill.Taylor@Sun.COM 	 * Previously, we had wanted to use the ddi_dma_mem_alloc() routine to
9869517SBill.Taylor@Sun.COM 	 * guarantee the alignment, but when attempting to use IOMMU bypass
9879517SBill.Taylor@Sun.COM 	 * mode we found that we were not allowed to specify any alignment
9889517SBill.Taylor@Sun.COM 	 * that was more restrictive than the system page size.
9899517SBill.Taylor@Sun.COM 	 * So we avoided this constraint by passing two alignment values,
9909517SBill.Taylor@Sun.COM 	 * one for the memory allocation itself and the other for the DMA
9919517SBill.Taylor@Sun.COM 	 * handle (for later bind).  This used to cause more memory than
9929517SBill.Taylor@Sun.COM 	 * necessary to be allocated (in order to guarantee the more
9939517SBill.Taylor@Sun.COM 	 * restrictive alignment contraint).  But by guaranteeing the
9949517SBill.Taylor@Sun.COM 	 * zero-based IB virtual address for the queue, we are able to
9959517SBill.Taylor@Sun.COM 	 * conserve this memory.
9969517SBill.Taylor@Sun.COM 	 */
9979517SBill.Taylor@Sun.COM 	sq_wqe_size = 1 << qp->qp_sq_log_wqesz;
9989517SBill.Taylor@Sun.COM 	sq_depth    = 1 << log_qp_sq_size;
9999517SBill.Taylor@Sun.COM 	sq_size	    = (1 << log_qp_sq_size) * sq_wqe_size;
10009517SBill.Taylor@Sun.COM 
10019517SBill.Taylor@Sun.COM 	rq_wqe_size = 1 << qp->qp_rq_log_wqesz;
10029517SBill.Taylor@Sun.COM 	rq_size	    = (1 << log_qp_rq_size) * rq_wqe_size;
10039517SBill.Taylor@Sun.COM 
10049517SBill.Taylor@Sun.COM 	qp->qp_wqinfo.qa_size	  = sq_size + rq_size;
10059517SBill.Taylor@Sun.COM 
10069517SBill.Taylor@Sun.COM 	qp->qp_wqinfo.qa_alloc_align = PAGESIZE;
10079517SBill.Taylor@Sun.COM 	qp->qp_wqinfo.qa_bind_align  = PAGESIZE;
10089517SBill.Taylor@Sun.COM 	qp->qp_wqinfo.qa_location = HERMON_QUEUE_LOCATION_NORMAL;
10099517SBill.Taylor@Sun.COM 
10109517SBill.Taylor@Sun.COM 	status = hermon_queue_alloc(state, &qp->qp_wqinfo, sleepflag);
10119517SBill.Taylor@Sun.COM 	if (status != NULL) {
10129517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
10139517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail5a;
10149517SBill.Taylor@Sun.COM 	}
10159517SBill.Taylor@Sun.COM 
10169517SBill.Taylor@Sun.COM 	/*
10179517SBill.Taylor@Sun.COM 	 * Sort WQs in memory according to depth, stride (*q_wqe_size),
10189517SBill.Taylor@Sun.COM 	 * biggest first. If equal, the Send Queue still goes first
10199517SBill.Taylor@Sun.COM 	 */
10209517SBill.Taylor@Sun.COM 	qp->qp_sq_baseaddr = 0;
10219517SBill.Taylor@Sun.COM 	qp->qp_rq_baseaddr = 0;
10229517SBill.Taylor@Sun.COM 	if ((sq_wqe_size > rq_wqe_size) || (sq_wqe_size == rq_wqe_size)) {
10239517SBill.Taylor@Sun.COM 		sq_buf = qp->qp_wqinfo.qa_buf_aligned;
10249517SBill.Taylor@Sun.COM 		rq_buf = (uint32_t *)((uintptr_t)sq_buf + sq_size);
10259517SBill.Taylor@Sun.COM 		qp->qp_rq_baseaddr = sq_size;
10269517SBill.Taylor@Sun.COM 	} else {
10279517SBill.Taylor@Sun.COM 		rq_buf = qp->qp_wqinfo.qa_buf_aligned;
10289517SBill.Taylor@Sun.COM 		sq_buf = (uint32_t *)((uintptr_t)rq_buf + rq_size);
10299517SBill.Taylor@Sun.COM 		qp->qp_sq_baseaddr = rq_size;
10309517SBill.Taylor@Sun.COM 	}
10319517SBill.Taylor@Sun.COM 
10329517SBill.Taylor@Sun.COM 	qp->qp_sq_wqhdr = hermon_wrid_wqhdr_create(sq_depth);
10339517SBill.Taylor@Sun.COM 	if (qp->qp_sq_wqhdr == NULL) {
10349517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
10359517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail6;
10369517SBill.Taylor@Sun.COM 	}
10379517SBill.Taylor@Sun.COM 	qp->qp_rq_wqhdr = hermon_wrid_wqhdr_create(1 << log_qp_rq_size);
10389517SBill.Taylor@Sun.COM 	if (qp->qp_rq_wqhdr == NULL) {
10399517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
10409517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail6;
10419517SBill.Taylor@Sun.COM 	}
10429517SBill.Taylor@Sun.COM 	qp->qp_sq_wqavl.wqa_qpn = qp->qp_qpnum;
10439517SBill.Taylor@Sun.COM 	qp->qp_sq_wqavl.wqa_type = HERMON_WR_SEND;
10449517SBill.Taylor@Sun.COM 	qp->qp_sq_wqavl.wqa_wq = qp->qp_sq_wqhdr;
10459517SBill.Taylor@Sun.COM 	qp->qp_rq_wqavl.wqa_qpn = qp->qp_qpnum;
10469517SBill.Taylor@Sun.COM 	qp->qp_rq_wqavl.wqa_type = HERMON_WR_RECV;
10479517SBill.Taylor@Sun.COM 	qp->qp_rq_wqavl.wqa_wq = qp->qp_rq_wqhdr;
10489517SBill.Taylor@Sun.COM 
10499517SBill.Taylor@Sun.COM 	/*
10509517SBill.Taylor@Sun.COM 	 * Register the memory for the special QP work queues.  The memory for
10519517SBill.Taylor@Sun.COM 	 * the special QP must be registered in the Hermon cMPT tables.  This
10529517SBill.Taylor@Sun.COM 	 * gives us the LKey to specify in the QP context later.  Note: The
10539517SBill.Taylor@Sun.COM 	 * memory for Hermon work queues (both Send and Recv) must be contiguous
10549517SBill.Taylor@Sun.COM 	 * and registered as a single memory region. Also, in order to meet the
10559517SBill.Taylor@Sun.COM 	 * alignment restriction, we pass the "mro_bind_override_addr" flag in
10569517SBill.Taylor@Sun.COM 	 * the call to hermon_mr_register(). This guarantees that the resulting
10579517SBill.Taylor@Sun.COM 	 * IB vaddr will be zero-based (modulo the offset into the first page).
10589517SBill.Taylor@Sun.COM 	 * If we fail here, we have a bunch of resource and reference count
10599517SBill.Taylor@Sun.COM 	 * cleanup to do.
10609517SBill.Taylor@Sun.COM 	 */
10619517SBill.Taylor@Sun.COM 	flag = (sleepflag == HERMON_SLEEP) ? IBT_MR_SLEEP :
10629517SBill.Taylor@Sun.COM 	    IBT_MR_NOSLEEP;
10639517SBill.Taylor@Sun.COM 	mr_attr.mr_vaddr    = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
10649517SBill.Taylor@Sun.COM 	mr_attr.mr_len	    = qp->qp_wqinfo.qa_size;
10659517SBill.Taylor@Sun.COM 	mr_attr.mr_as	    = NULL;
10669517SBill.Taylor@Sun.COM 	mr_attr.mr_flags    = flag;
10679517SBill.Taylor@Sun.COM 
10689517SBill.Taylor@Sun.COM 	mr_op.mro_bind_type = state->hs_cfg_profile->cp_iommu_bypass;
10699517SBill.Taylor@Sun.COM 	mr_op.mro_bind_dmahdl = qp->qp_wqinfo.qa_dmahdl;
10709517SBill.Taylor@Sun.COM 	mr_op.mro_bind_override_addr = 1;
10719517SBill.Taylor@Sun.COM 
10729517SBill.Taylor@Sun.COM 	status = hermon_mr_register(state, pd, &mr_attr, &mr, &mr_op,
10739517SBill.Taylor@Sun.COM 	    HERMON_QP_CMPT);
10749517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
10759517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
10769517SBill.Taylor@Sun.COM 		goto spec_qpalloc_fail6;
10779517SBill.Taylor@Sun.COM 	}
10789517SBill.Taylor@Sun.COM 
10799517SBill.Taylor@Sun.COM 	/*
10809517SBill.Taylor@Sun.COM 	 * Calculate the offset between the kernel virtual address space
10819517SBill.Taylor@Sun.COM 	 * and the IB virtual address space.  This will be used when
10829517SBill.Taylor@Sun.COM 	 * posting work requests to properly initialize each WQE.
10839517SBill.Taylor@Sun.COM 	 */
10849517SBill.Taylor@Sun.COM 	qp_desc_off = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
10859517SBill.Taylor@Sun.COM 	    (uint64_t)mr->mr_bindinfo.bi_addr;
10869517SBill.Taylor@Sun.COM 
10879517SBill.Taylor@Sun.COM 	/* set the prefetch - initially, not prefetching */
10889517SBill.Taylor@Sun.COM 	qp->qp_no_prefetch = 1;
10899517SBill.Taylor@Sun.COM 
10909517SBill.Taylor@Sun.COM 	if (qp->qp_no_prefetch)
10919517SBill.Taylor@Sun.COM 		qp->qp_sq_headroom = 2 * sq_wqe_size;
10929517SBill.Taylor@Sun.COM 	else
10939517SBill.Taylor@Sun.COM 		qp->qp_sq_headroom = sq_wqe_size + HERMON_QP_OH_SIZE;
10949517SBill.Taylor@Sun.COM 	/*
10959517SBill.Taylor@Sun.COM 	 * hdrm wqes must be integral since both sq_wqe_size &
10969517SBill.Taylor@Sun.COM 	 * HERMON_QP_OH_SIZE are power of 2
10979517SBill.Taylor@Sun.COM 	 */
10989517SBill.Taylor@Sun.COM 	qp->qp_sq_hdrmwqes = (qp->qp_sq_headroom / sq_wqe_size);
10999517SBill.Taylor@Sun.COM 	/*
11009517SBill.Taylor@Sun.COM 	 * Fill in all the return arguments (if necessary).  This includes
11019517SBill.Taylor@Sun.COM 	 * real work queue sizes, real SGLs, and QP number (which will be
11029517SBill.Taylor@Sun.COM 	 * either zero or one, depending on the special QP type)
11039517SBill.Taylor@Sun.COM 	 */
11049517SBill.Taylor@Sun.COM 	if (queuesz_p != NULL) {
11059517SBill.Taylor@Sun.COM 		queuesz_p->cs_sq	=
11069517SBill.Taylor@Sun.COM 		    (1 << log_qp_sq_size) - qp->qp_sq_hdrmwqes;
11079517SBill.Taylor@Sun.COM 		queuesz_p->cs_sq_sgl	= qp->qp_sq_sgl;
11089517SBill.Taylor@Sun.COM 		queuesz_p->cs_rq	= (1 << log_qp_rq_size);
11099517SBill.Taylor@Sun.COM 		queuesz_p->cs_rq_sgl	= qp->qp_rq_sgl;
11109517SBill.Taylor@Sun.COM 	}
11119517SBill.Taylor@Sun.COM 
11129517SBill.Taylor@Sun.COM 	/*
11139517SBill.Taylor@Sun.COM 	 * Fill in the rest of the Hermon Queue Pair handle.  We can update
11149517SBill.Taylor@Sun.COM 	 * the following fields for use in further operations on the QP.
11159517SBill.Taylor@Sun.COM 	 */
11169517SBill.Taylor@Sun.COM 	qp->qp_qpcrsrcp		= qpc;
11179517SBill.Taylor@Sun.COM 	qp->qp_rsrcp		= rsrc;
11189517SBill.Taylor@Sun.COM 	qp->qp_state		= HERMON_QP_RESET;
1119*12965SWilliam.Taylor@Oracle.COM 	HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
11209517SBill.Taylor@Sun.COM 	qp->qp_pdhdl		= pd;
11219517SBill.Taylor@Sun.COM 	qp->qp_mrhdl		= mr;
11229517SBill.Taylor@Sun.COM 	qp->qp_sq_sigtype	= (attr_p->qp_flags & IBT_WR_SIGNALED) ?
11239517SBill.Taylor@Sun.COM 	    HERMON_QP_SQ_WR_SIGNALED : HERMON_QP_SQ_ALL_SIGNALED;
11249517SBill.Taylor@Sun.COM 	qp->qp_is_special	= (type == IBT_SMI_SQP) ?
11259517SBill.Taylor@Sun.COM 	    HERMON_QP_SMI : HERMON_QP_GSI;
11269517SBill.Taylor@Sun.COM 	qp->qp_uarpg		= uarpg;
11279517SBill.Taylor@Sun.COM 	qp->qp_umap_dhp		= (devmap_cookie_t)NULL;
11289517SBill.Taylor@Sun.COM 	qp->qp_sq_cqhdl		= sq_cq;
11299517SBill.Taylor@Sun.COM 	qp->qp_sq_bufsz		= (1 << log_qp_sq_size);
11309517SBill.Taylor@Sun.COM 	qp->qp_sq_buf		= sq_buf;
11319517SBill.Taylor@Sun.COM 	qp->qp_sq_logqsz	= log_qp_sq_size;
11329517SBill.Taylor@Sun.COM 	qp->qp_desc_off		= qp_desc_off;
11339517SBill.Taylor@Sun.COM 	qp->qp_rq_cqhdl		= rq_cq;
11349517SBill.Taylor@Sun.COM 	qp->qp_rq_bufsz		= (1 << log_qp_rq_size);
11359517SBill.Taylor@Sun.COM 	qp->qp_rq_buf		= rq_buf;
11369517SBill.Taylor@Sun.COM 	qp->qp_rq_logqsz	= log_qp_rq_size;
11379517SBill.Taylor@Sun.COM 	qp->qp_portnum		= port;
11389517SBill.Taylor@Sun.COM 	qp->qp_pkeyindx		= 0;
11399517SBill.Taylor@Sun.COM 	qp->qp_forward_sqd_event  = 0;
11409517SBill.Taylor@Sun.COM 	qp->qp_sqd_still_draining = 0;
11419517SBill.Taylor@Sun.COM 	qp->qp_hdlrarg		= (void *)ibt_qphdl;
11429517SBill.Taylor@Sun.COM 	qp->qp_mcg_refcnt	= 0;
11439517SBill.Taylor@Sun.COM 	qp->qp_srqhdl		= NULL;
11449517SBill.Taylor@Sun.COM 
11459517SBill.Taylor@Sun.COM 	/* All special QPs are UD QP service type */
1146*12965SWilliam.Taylor@Oracle.COM 	qp->qp_type = IBT_UD_RQP;
11479517SBill.Taylor@Sun.COM 	qp->qp_serv_type = HERMON_QP_UD;
11489517SBill.Taylor@Sun.COM 
11499517SBill.Taylor@Sun.COM 	/*
11509517SBill.Taylor@Sun.COM 	 * Initialize the RQ WQEs - unlike Arbel, no Rcv init is needed
11519517SBill.Taylor@Sun.COM 	 */
11529517SBill.Taylor@Sun.COM 
11539517SBill.Taylor@Sun.COM 	/*
11549517SBill.Taylor@Sun.COM 	 * Initialize the SQ WQEs - all that needs to be done is every 64 bytes
11559517SBill.Taylor@Sun.COM 	 * set the quadword to all F's - high-order bit is owner (init to one)
11569517SBill.Taylor@Sun.COM 	 * and the rest for the headroom definition of prefetching
11579517SBill.Taylor@Sun.COM 	 *
11589517SBill.Taylor@Sun.COM 	 */
11599517SBill.Taylor@Sun.COM 
11609517SBill.Taylor@Sun.COM 	wqesz_shift = qp->qp_sq_log_wqesz;
11619517SBill.Taylor@Sun.COM 	thewqesz    = 1 << wqesz_shift;
11629517SBill.Taylor@Sun.COM 	thewqe = (uint64_t *)(void *)(qp->qp_sq_buf);
11639517SBill.Taylor@Sun.COM 	for (i = 0; i < sq_depth; i++) {
11649517SBill.Taylor@Sun.COM 		/*
11659517SBill.Taylor@Sun.COM 		 * for each stride, go through and every 64 bytes write the
11669517SBill.Taylor@Sun.COM 		 * init value - having set the address once, just keep
11679517SBill.Taylor@Sun.COM 		 * incrementing it
11689517SBill.Taylor@Sun.COM 		 */
11699517SBill.Taylor@Sun.COM 		for (j = 0; j < thewqesz; j += 64, thewqe += 8) {
11709517SBill.Taylor@Sun.COM 			*(uint32_t *)thewqe = 0xFFFFFFFF;
11719517SBill.Taylor@Sun.COM 		}
11729517SBill.Taylor@Sun.COM 	}
11739517SBill.Taylor@Sun.COM 
11749517SBill.Taylor@Sun.COM 
11759517SBill.Taylor@Sun.COM 	/* Zero out the QP context */
11769517SBill.Taylor@Sun.COM 	bzero(&qp->qpc, sizeof (hermon_hw_qpc_t));
11779517SBill.Taylor@Sun.COM 
11789517SBill.Taylor@Sun.COM 	/*
11799517SBill.Taylor@Sun.COM 	 * Put QP handle in Hermon QPNum-to-QPHdl list.  Then fill in the
11809517SBill.Taylor@Sun.COM 	 * "qphdl" and return success
11819517SBill.Taylor@Sun.COM 	 */
1182*12965SWilliam.Taylor@Oracle.COM 	hermon_icm_set_num_to_hdl(state, HERMON_QPC, qpc->hr_indx + port, qp);
1183*12965SWilliam.Taylor@Oracle.COM 
1184*12965SWilliam.Taylor@Oracle.COM 	mutex_init(&qp->qp_sq_lock, NULL, MUTEX_DRIVER,
1185*12965SWilliam.Taylor@Oracle.COM 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
11869517SBill.Taylor@Sun.COM 
11879517SBill.Taylor@Sun.COM 	*qphdl = qp;
11889517SBill.Taylor@Sun.COM 
11899517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
11909517SBill.Taylor@Sun.COM 
11919517SBill.Taylor@Sun.COM /*
11929517SBill.Taylor@Sun.COM  * The following is cleanup for all possible failure cases in this routine
11939517SBill.Taylor@Sun.COM  */
11949517SBill.Taylor@Sun.COM spec_qpalloc_fail6:
11959517SBill.Taylor@Sun.COM 	hermon_queue_free(&qp->qp_wqinfo);
11969517SBill.Taylor@Sun.COM 	if (qp->qp_sq_wqhdr)
11979517SBill.Taylor@Sun.COM 		hermon_wrid_wqhdr_destroy(qp->qp_sq_wqhdr);
11989517SBill.Taylor@Sun.COM 	if (qp->qp_rq_wqhdr)
11999517SBill.Taylor@Sun.COM 		hermon_wrid_wqhdr_destroy(qp->qp_rq_wqhdr);
12009517SBill.Taylor@Sun.COM spec_qpalloc_fail5a:
12019517SBill.Taylor@Sun.COM 	hermon_dbr_free(state, uarpg, qp->qp_rq_vdbr);
12029517SBill.Taylor@Sun.COM spec_qpalloc_fail5:
12039517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
12049517SBill.Taylor@Sun.COM spec_qpalloc_fail4:
12059517SBill.Taylor@Sun.COM 	if (hermon_special_qp_rsrc_free(state, type, port) != DDI_SUCCESS) {
12069517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "failed to free special QP rsrc");
12079517SBill.Taylor@Sun.COM 	}
12089517SBill.Taylor@Sun.COM spec_qpalloc_fail3:
12099517SBill.Taylor@Sun.COM 	hermon_cq_refcnt_dec(rq_cq);
12109517SBill.Taylor@Sun.COM spec_qpalloc_fail2:
12119517SBill.Taylor@Sun.COM 	hermon_cq_refcnt_dec(sq_cq);
12129517SBill.Taylor@Sun.COM spec_qpalloc_fail1:
12139517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
12149517SBill.Taylor@Sun.COM spec_qpalloc_fail:
12159517SBill.Taylor@Sun.COM 	return (status);
12169517SBill.Taylor@Sun.COM }
12179517SBill.Taylor@Sun.COM 
12189517SBill.Taylor@Sun.COM 
12199517SBill.Taylor@Sun.COM /*
1220*12965SWilliam.Taylor@Oracle.COM  * hermon_qp_alloc_range()
1221*12965SWilliam.Taylor@Oracle.COM  *    Context: Can be called only from user or kernel context.
1222*12965SWilliam.Taylor@Oracle.COM  */
1223*12965SWilliam.Taylor@Oracle.COM int
hermon_qp_alloc_range(hermon_state_t * state,uint_t log2,hermon_qp_info_t * qpinfo,ibtl_qp_hdl_t * ibt_qphdl,ibc_cq_hdl_t * send_cq,ibc_cq_hdl_t * recv_cq,hermon_qphdl_t * qphdl,uint_t sleepflag)1224*12965SWilliam.Taylor@Oracle.COM hermon_qp_alloc_range(hermon_state_t *state, uint_t log2,
1225*12965SWilliam.Taylor@Oracle.COM     hermon_qp_info_t *qpinfo, ibtl_qp_hdl_t *ibt_qphdl,
1226*12965SWilliam.Taylor@Oracle.COM     ibc_cq_hdl_t *send_cq, ibc_cq_hdl_t *recv_cq,
1227*12965SWilliam.Taylor@Oracle.COM     hermon_qphdl_t *qphdl, uint_t sleepflag)
1228*12965SWilliam.Taylor@Oracle.COM {
1229*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_t			*qpc, *rsrc;
1230*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_type_t		rsrc_type;
1231*12965SWilliam.Taylor@Oracle.COM 	hermon_qphdl_t			qp;
1232*12965SWilliam.Taylor@Oracle.COM 	hermon_qp_range_t		*qp_range_p;
1233*12965SWilliam.Taylor@Oracle.COM 	ibt_qp_alloc_attr_t		*attr_p;
1234*12965SWilliam.Taylor@Oracle.COM 	ibt_qp_type_t			type;
1235*12965SWilliam.Taylor@Oracle.COM 	hermon_qp_wq_type_t		swq_type;
1236*12965SWilliam.Taylor@Oracle.COM 	ibt_chan_sizes_t		*queuesz_p;
1237*12965SWilliam.Taylor@Oracle.COM 	ibt_mr_attr_t			mr_attr;
1238*12965SWilliam.Taylor@Oracle.COM 	hermon_mr_options_t		mr_op;
1239*12965SWilliam.Taylor@Oracle.COM 	hermon_srqhdl_t			srq;
1240*12965SWilliam.Taylor@Oracle.COM 	hermon_pdhdl_t			pd;
1241*12965SWilliam.Taylor@Oracle.COM 	hermon_cqhdl_t			sq_cq, rq_cq;
1242*12965SWilliam.Taylor@Oracle.COM 	hermon_mrhdl_t			mr;
1243*12965SWilliam.Taylor@Oracle.COM 	uint64_t			qp_desc_off;
1244*12965SWilliam.Taylor@Oracle.COM 	uint64_t			*thewqe, thewqesz;
1245*12965SWilliam.Taylor@Oracle.COM 	uint32_t			*sq_buf, *rq_buf;
1246*12965SWilliam.Taylor@Oracle.COM 	uint32_t			log_qp_sq_size, log_qp_rq_size;
1247*12965SWilliam.Taylor@Oracle.COM 	uint32_t			sq_size, rq_size;
1248*12965SWilliam.Taylor@Oracle.COM 	uint32_t			sq_depth, rq_depth;
1249*12965SWilliam.Taylor@Oracle.COM 	uint32_t			sq_wqe_size, rq_wqe_size, wqesz_shift;
1250*12965SWilliam.Taylor@Oracle.COM 	uint32_t			max_sgl, max_recv_sgl, uarpg;
1251*12965SWilliam.Taylor@Oracle.COM 	uint_t				qp_srq_en, i, j;
1252*12965SWilliam.Taylor@Oracle.COM 	int				ii;	/* loop counter for range */
1253*12965SWilliam.Taylor@Oracle.COM 	int				status, flag;
1254*12965SWilliam.Taylor@Oracle.COM 	uint_t				serv_type;
1255*12965SWilliam.Taylor@Oracle.COM 
1256*12965SWilliam.Taylor@Oracle.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*attr_p, *queuesz_p))
1257*12965SWilliam.Taylor@Oracle.COM 
1258*12965SWilliam.Taylor@Oracle.COM 	/*
1259*12965SWilliam.Taylor@Oracle.COM 	 * Extract the necessary info from the hermon_qp_info_t structure
1260*12965SWilliam.Taylor@Oracle.COM 	 */
1261*12965SWilliam.Taylor@Oracle.COM 	attr_p	  = qpinfo->qpi_attrp;
1262*12965SWilliam.Taylor@Oracle.COM 	type	  = qpinfo->qpi_type;
1263*12965SWilliam.Taylor@Oracle.COM 	queuesz_p = qpinfo->qpi_queueszp;
1264*12965SWilliam.Taylor@Oracle.COM 
1265*12965SWilliam.Taylor@Oracle.COM 	if (attr_p->qp_alloc_flags & IBT_QP_USES_RSS) {
1266*12965SWilliam.Taylor@Oracle.COM 		if (log2 > state->hs_ibtfinfo.hca_attr->hca_rss_max_log2_table)
1267*12965SWilliam.Taylor@Oracle.COM 			return (IBT_INSUFF_RESOURCE);
1268*12965SWilliam.Taylor@Oracle.COM 		rsrc_type = HERMON_QPC;
1269*12965SWilliam.Taylor@Oracle.COM 		serv_type = HERMON_QP_UD;
1270*12965SWilliam.Taylor@Oracle.COM 	} else if (attr_p->qp_alloc_flags & IBT_QP_USES_FEXCH) {
1271*12965SWilliam.Taylor@Oracle.COM 		if (log2 > state->hs_ibtfinfo.hca_attr->hca_fexch_max_log2_qp)
1272*12965SWilliam.Taylor@Oracle.COM 			return (IBT_INSUFF_RESOURCE);
1273*12965SWilliam.Taylor@Oracle.COM 		switch (attr_p->qp_fc.fc_hca_port) {
1274*12965SWilliam.Taylor@Oracle.COM 		case 1:
1275*12965SWilliam.Taylor@Oracle.COM 			rsrc_type = HERMON_QPC_FEXCH_PORT1;
1276*12965SWilliam.Taylor@Oracle.COM 			break;
1277*12965SWilliam.Taylor@Oracle.COM 		case 2:
1278*12965SWilliam.Taylor@Oracle.COM 			rsrc_type = HERMON_QPC_FEXCH_PORT2;
1279*12965SWilliam.Taylor@Oracle.COM 			break;
1280*12965SWilliam.Taylor@Oracle.COM 		default:
1281*12965SWilliam.Taylor@Oracle.COM 			return (IBT_INVALID_PARAM);
1282*12965SWilliam.Taylor@Oracle.COM 		}
1283*12965SWilliam.Taylor@Oracle.COM 		serv_type = HERMON_QP_FEXCH;
1284*12965SWilliam.Taylor@Oracle.COM 	} else
1285*12965SWilliam.Taylor@Oracle.COM 		return (IBT_INVALID_PARAM);
1286*12965SWilliam.Taylor@Oracle.COM 
1287*12965SWilliam.Taylor@Oracle.COM 	/*
1288*12965SWilliam.Taylor@Oracle.COM 	 * Determine whether QP is being allocated for userland access or
1289*12965SWilliam.Taylor@Oracle.COM 	 * whether it is being allocated for kernel access.  If the QP is
1290*12965SWilliam.Taylor@Oracle.COM 	 * being allocated for userland access, fail (too complex for now).
1291*12965SWilliam.Taylor@Oracle.COM 	 */
1292*12965SWilliam.Taylor@Oracle.COM 	if (attr_p->qp_alloc_flags & IBT_QP_USER_MAP) {
1293*12965SWilliam.Taylor@Oracle.COM 		return (IBT_NOT_SUPPORTED);
1294*12965SWilliam.Taylor@Oracle.COM 	} else {
1295*12965SWilliam.Taylor@Oracle.COM 		uarpg = state->hs_kernel_uar_index;
1296*12965SWilliam.Taylor@Oracle.COM 	}
1297*12965SWilliam.Taylor@Oracle.COM 
1298*12965SWilliam.Taylor@Oracle.COM 	/*
1299*12965SWilliam.Taylor@Oracle.COM 	 * Determine whether QP is being associated with an SRQ
1300*12965SWilliam.Taylor@Oracle.COM 	 */
1301*12965SWilliam.Taylor@Oracle.COM 	qp_srq_en = (attr_p->qp_alloc_flags & IBT_QP_USES_SRQ) ? 1 : 0;
1302*12965SWilliam.Taylor@Oracle.COM 	if (qp_srq_en) {
1303*12965SWilliam.Taylor@Oracle.COM 		/*
1304*12965SWilliam.Taylor@Oracle.COM 		 * Check for valid SRQ handle pointers
1305*12965SWilliam.Taylor@Oracle.COM 		 */
1306*12965SWilliam.Taylor@Oracle.COM 		if (attr_p->qp_ibc_srq_hdl == NULL) {
1307*12965SWilliam.Taylor@Oracle.COM 			return (IBT_SRQ_HDL_INVALID);
1308*12965SWilliam.Taylor@Oracle.COM 		}
1309*12965SWilliam.Taylor@Oracle.COM 		srq = (hermon_srqhdl_t)attr_p->qp_ibc_srq_hdl;
1310*12965SWilliam.Taylor@Oracle.COM 	}
1311*12965SWilliam.Taylor@Oracle.COM 
1312*12965SWilliam.Taylor@Oracle.COM 	/*
1313*12965SWilliam.Taylor@Oracle.COM 	 * Check for valid QP service type (only UD supported)
1314*12965SWilliam.Taylor@Oracle.COM 	 */
1315*12965SWilliam.Taylor@Oracle.COM 	if (type != IBT_UD_RQP) {
1316*12965SWilliam.Taylor@Oracle.COM 		return (IBT_QP_SRV_TYPE_INVALID);
1317*12965SWilliam.Taylor@Oracle.COM 	}
1318*12965SWilliam.Taylor@Oracle.COM 
1319*12965SWilliam.Taylor@Oracle.COM 	/*
1320*12965SWilliam.Taylor@Oracle.COM 	 * Check for valid PD handle pointer
1321*12965SWilliam.Taylor@Oracle.COM 	 */
1322*12965SWilliam.Taylor@Oracle.COM 	if (attr_p->qp_pd_hdl == NULL) {
1323*12965SWilliam.Taylor@Oracle.COM 		return (IBT_PD_HDL_INVALID);
1324*12965SWilliam.Taylor@Oracle.COM 	}
1325*12965SWilliam.Taylor@Oracle.COM 	pd = (hermon_pdhdl_t)attr_p->qp_pd_hdl;
1326*12965SWilliam.Taylor@Oracle.COM 
1327*12965SWilliam.Taylor@Oracle.COM 	/*
1328*12965SWilliam.Taylor@Oracle.COM 	 * If on an SRQ, check to make sure the PD is the same
1329*12965SWilliam.Taylor@Oracle.COM 	 */
1330*12965SWilliam.Taylor@Oracle.COM 	if (qp_srq_en && (pd->pd_pdnum != srq->srq_pdhdl->pd_pdnum)) {
1331*12965SWilliam.Taylor@Oracle.COM 		return (IBT_PD_HDL_INVALID);
1332*12965SWilliam.Taylor@Oracle.COM 	}
1333*12965SWilliam.Taylor@Oracle.COM 
1334*12965SWilliam.Taylor@Oracle.COM 	/* set loop variable here, for freeing resources on error */
1335*12965SWilliam.Taylor@Oracle.COM 	ii = 0;
1336*12965SWilliam.Taylor@Oracle.COM 
1337*12965SWilliam.Taylor@Oracle.COM 	/*
1338*12965SWilliam.Taylor@Oracle.COM 	 * Allocate 2^log2 contiguous/aligned QP context entries.  This will
1339*12965SWilliam.Taylor@Oracle.COM 	 * be filled in with all the necessary parameters to define the
1340*12965SWilliam.Taylor@Oracle.COM 	 * Queue Pairs.  Unlike other Hermon hardware resources, ownership
1341*12965SWilliam.Taylor@Oracle.COM 	 * is not immediately given to hardware in the final step here.
1342*12965SWilliam.Taylor@Oracle.COM 	 * Instead, we must wait until the QP is later transitioned to the
1343*12965SWilliam.Taylor@Oracle.COM 	 * "Init" state before passing the QP to hardware.  If we fail here,
1344*12965SWilliam.Taylor@Oracle.COM 	 * we must undo all the reference count (CQ and PD).
1345*12965SWilliam.Taylor@Oracle.COM 	 */
1346*12965SWilliam.Taylor@Oracle.COM 	status = hermon_rsrc_alloc(state, rsrc_type, 1 << log2, sleepflag,
1347*12965SWilliam.Taylor@Oracle.COM 	    &qpc);
1348*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
1349*12965SWilliam.Taylor@Oracle.COM 		return (IBT_INSUFF_RESOURCE);
1350*12965SWilliam.Taylor@Oracle.COM 	}
1351*12965SWilliam.Taylor@Oracle.COM 
1352*12965SWilliam.Taylor@Oracle.COM 	if (attr_p->qp_alloc_flags & IBT_QP_USES_FEXCH)
1353*12965SWilliam.Taylor@Oracle.COM 		/*
1354*12965SWilliam.Taylor@Oracle.COM 		 * Need to init the MKEYs for the FEXCH QPs.
1355*12965SWilliam.Taylor@Oracle.COM 		 *
1356*12965SWilliam.Taylor@Oracle.COM 		 * For FEXCH QP subranges, we return the QPN base as
1357*12965SWilliam.Taylor@Oracle.COM 		 * "relative" to the full FEXCH QP range for the port.
1358*12965SWilliam.Taylor@Oracle.COM 		 */
1359*12965SWilliam.Taylor@Oracle.COM 		*(qpinfo->qpi_qpn) = hermon_fcoib_fexch_relative_qpn(state,
1360*12965SWilliam.Taylor@Oracle.COM 		    attr_p->qp_fc.fc_hca_port, qpc->hr_indx);
1361*12965SWilliam.Taylor@Oracle.COM 	else
1362*12965SWilliam.Taylor@Oracle.COM 		*(qpinfo->qpi_qpn) = (ib_qpn_t)qpc->hr_indx;
1363*12965SWilliam.Taylor@Oracle.COM 
1364*12965SWilliam.Taylor@Oracle.COM 	qp_range_p = kmem_alloc(sizeof (*qp_range_p),
1365*12965SWilliam.Taylor@Oracle.COM 	    (sleepflag == HERMON_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
1366*12965SWilliam.Taylor@Oracle.COM 	if (qp_range_p == NULL) {
1367*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INSUFF_RESOURCE;
1368*12965SWilliam.Taylor@Oracle.COM 		goto qpalloc_fail0;
1369*12965SWilliam.Taylor@Oracle.COM 	}
1370*12965SWilliam.Taylor@Oracle.COM 	mutex_init(&qp_range_p->hqpr_lock, NULL, MUTEX_DRIVER,
1371*12965SWilliam.Taylor@Oracle.COM 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
1372*12965SWilliam.Taylor@Oracle.COM 	mutex_enter(&qp_range_p->hqpr_lock);
1373*12965SWilliam.Taylor@Oracle.COM 	qp_range_p->hqpr_refcnt = 1 << log2;
1374*12965SWilliam.Taylor@Oracle.COM 	qp_range_p->hqpr_qpcrsrc = qpc;
1375*12965SWilliam.Taylor@Oracle.COM 	mutex_exit(&qp_range_p->hqpr_lock);
1376*12965SWilliam.Taylor@Oracle.COM 
1377*12965SWilliam.Taylor@Oracle.COM for_each_qp:
1378*12965SWilliam.Taylor@Oracle.COM 
1379*12965SWilliam.Taylor@Oracle.COM 	/* Increment the reference count on the protection domain (PD) */
1380*12965SWilliam.Taylor@Oracle.COM 	hermon_pd_refcnt_inc(pd);
1381*12965SWilliam.Taylor@Oracle.COM 
1382*12965SWilliam.Taylor@Oracle.COM 	rq_cq = (hermon_cqhdl_t)recv_cq[ii];
1383*12965SWilliam.Taylor@Oracle.COM 	sq_cq = (hermon_cqhdl_t)send_cq[ii];
1384*12965SWilliam.Taylor@Oracle.COM 	if (sq_cq == NULL) {
1385*12965SWilliam.Taylor@Oracle.COM 		if (attr_p->qp_alloc_flags & IBT_QP_USES_FEXCH) {
1386*12965SWilliam.Taylor@Oracle.COM 			/* if no send completions, just use rq_cq */
1387*12965SWilliam.Taylor@Oracle.COM 			sq_cq = rq_cq;
1388*12965SWilliam.Taylor@Oracle.COM 		} else {
1389*12965SWilliam.Taylor@Oracle.COM 			status = IBT_CQ_HDL_INVALID;
1390*12965SWilliam.Taylor@Oracle.COM 			goto qpalloc_fail1;
1391*12965SWilliam.Taylor@Oracle.COM 		}
1392*12965SWilliam.Taylor@Oracle.COM 	}
1393*12965SWilliam.Taylor@Oracle.COM 
1394*12965SWilliam.Taylor@Oracle.COM 	/*
1395*12965SWilliam.Taylor@Oracle.COM 	 * Increment the reference count on the CQs.  One or both of these
1396*12965SWilliam.Taylor@Oracle.COM 	 * could return error if we determine that the given CQ is already
1397*12965SWilliam.Taylor@Oracle.COM 	 * being used with a special (SMI/GSI) QP.
1398*12965SWilliam.Taylor@Oracle.COM 	 */
1399*12965SWilliam.Taylor@Oracle.COM 	status = hermon_cq_refcnt_inc(sq_cq, HERMON_CQ_IS_NORMAL);
1400*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
1401*12965SWilliam.Taylor@Oracle.COM 		status = IBT_CQ_HDL_INVALID;
1402*12965SWilliam.Taylor@Oracle.COM 		goto qpalloc_fail1;
1403*12965SWilliam.Taylor@Oracle.COM 	}
1404*12965SWilliam.Taylor@Oracle.COM 	status = hermon_cq_refcnt_inc(rq_cq, HERMON_CQ_IS_NORMAL);
1405*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
1406*12965SWilliam.Taylor@Oracle.COM 		status = IBT_CQ_HDL_INVALID;
1407*12965SWilliam.Taylor@Oracle.COM 		goto qpalloc_fail2;
1408*12965SWilliam.Taylor@Oracle.COM 	}
1409*12965SWilliam.Taylor@Oracle.COM 
1410*12965SWilliam.Taylor@Oracle.COM 	/*
1411*12965SWilliam.Taylor@Oracle.COM 	 * Allocate the software structure for tracking the queue pair
1412*12965SWilliam.Taylor@Oracle.COM 	 * (i.e. the Hermon Queue Pair handle).  If we fail here, we must
1413*12965SWilliam.Taylor@Oracle.COM 	 * undo the reference counts and the previous resource allocation.
1414*12965SWilliam.Taylor@Oracle.COM 	 */
1415*12965SWilliam.Taylor@Oracle.COM 	status = hermon_rsrc_alloc(state, HERMON_QPHDL, 1, sleepflag, &rsrc);
1416*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
1417*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INSUFF_RESOURCE;
1418*12965SWilliam.Taylor@Oracle.COM 		goto qpalloc_fail4;
1419*12965SWilliam.Taylor@Oracle.COM 	}
1420*12965SWilliam.Taylor@Oracle.COM 	qp = (hermon_qphdl_t)rsrc->hr_addr;
1421*12965SWilliam.Taylor@Oracle.COM 	bzero(qp, sizeof (struct hermon_sw_qp_s));
1422*12965SWilliam.Taylor@Oracle.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp))
1423*12965SWilliam.Taylor@Oracle.COM 	qp->qp_alloc_flags = attr_p->qp_alloc_flags;
1424*12965SWilliam.Taylor@Oracle.COM 
1425*12965SWilliam.Taylor@Oracle.COM 	/*
1426*12965SWilliam.Taylor@Oracle.COM 	 * Calculate the QP number from QPC index.  This routine handles
1427*12965SWilliam.Taylor@Oracle.COM 	 * all of the operations necessary to keep track of used, unused,
1428*12965SWilliam.Taylor@Oracle.COM 	 * and released QP numbers.
1429*12965SWilliam.Taylor@Oracle.COM 	 */
1430*12965SWilliam.Taylor@Oracle.COM 	qp->qp_qpnum = qpc->hr_indx + ii;
1431*12965SWilliam.Taylor@Oracle.COM 	qp->qp_ring = qp->qp_qpnum << 8;
1432*12965SWilliam.Taylor@Oracle.COM 	qp->qp_qpn_hdl = NULL;
1433*12965SWilliam.Taylor@Oracle.COM 
1434*12965SWilliam.Taylor@Oracle.COM 	/*
1435*12965SWilliam.Taylor@Oracle.COM 	 * Allocate the doorbell record.  Hermon just needs one for the RQ,
1436*12965SWilliam.Taylor@Oracle.COM 	 * if the QP is not associated with an SRQ, and use uarpg (above) as
1437*12965SWilliam.Taylor@Oracle.COM 	 * the uar index
1438*12965SWilliam.Taylor@Oracle.COM 	 */
1439*12965SWilliam.Taylor@Oracle.COM 
1440*12965SWilliam.Taylor@Oracle.COM 	if (!qp_srq_en) {
1441*12965SWilliam.Taylor@Oracle.COM 		status = hermon_dbr_alloc(state, uarpg, &qp->qp_rq_dbr_acchdl,
1442*12965SWilliam.Taylor@Oracle.COM 		    &qp->qp_rq_vdbr, &qp->qp_rq_pdbr, &qp->qp_rdbr_mapoffset);
1443*12965SWilliam.Taylor@Oracle.COM 		if (status != DDI_SUCCESS) {
1444*12965SWilliam.Taylor@Oracle.COM 			status = IBT_INSUFF_RESOURCE;
1445*12965SWilliam.Taylor@Oracle.COM 			goto qpalloc_fail6;
1446*12965SWilliam.Taylor@Oracle.COM 		}
1447*12965SWilliam.Taylor@Oracle.COM 	}
1448*12965SWilliam.Taylor@Oracle.COM 
1449*12965SWilliam.Taylor@Oracle.COM 	qp->qp_uses_lso = (attr_p->qp_flags & IBT_USES_LSO);
1450*12965SWilliam.Taylor@Oracle.COM 
1451*12965SWilliam.Taylor@Oracle.COM 	/*
1452*12965SWilliam.Taylor@Oracle.COM 	 * We verify that the requested number of SGL is valid (i.e.
1453*12965SWilliam.Taylor@Oracle.COM 	 * consistent with the device limits and/or software-configured
1454*12965SWilliam.Taylor@Oracle.COM 	 * limits).  If not, then obviously the same cleanup needs to be done.
1455*12965SWilliam.Taylor@Oracle.COM 	 */
1456*12965SWilliam.Taylor@Oracle.COM 	max_sgl = state->hs_ibtfinfo.hca_attr->hca_ud_send_sgl_sz;
1457*12965SWilliam.Taylor@Oracle.COM 	swq_type = HERMON_QP_WQ_TYPE_SENDQ_UD;
1458*12965SWilliam.Taylor@Oracle.COM 	max_recv_sgl = state->hs_ibtfinfo.hca_attr->hca_recv_sgl_sz;
1459*12965SWilliam.Taylor@Oracle.COM 	if ((attr_p->qp_sizes.cs_sq_sgl > max_sgl) ||
1460*12965SWilliam.Taylor@Oracle.COM 	    (!qp_srq_en && (attr_p->qp_sizes.cs_rq_sgl > max_recv_sgl))) {
1461*12965SWilliam.Taylor@Oracle.COM 		status = IBT_HCA_SGL_EXCEEDED;
1462*12965SWilliam.Taylor@Oracle.COM 		goto qpalloc_fail7;
1463*12965SWilliam.Taylor@Oracle.COM 	}
1464*12965SWilliam.Taylor@Oracle.COM 
1465*12965SWilliam.Taylor@Oracle.COM 	/*
1466*12965SWilliam.Taylor@Oracle.COM 	 * Determine this QP's WQE stride (for both the Send and Recv WQEs).
1467*12965SWilliam.Taylor@Oracle.COM 	 * This will depend on the requested number of SGLs.  Note: this
1468*12965SWilliam.Taylor@Oracle.COM 	 * has the side-effect of also calculating the real number of SGLs
1469*12965SWilliam.Taylor@Oracle.COM 	 * (for the calculated WQE size).
1470*12965SWilliam.Taylor@Oracle.COM 	 *
1471*12965SWilliam.Taylor@Oracle.COM 	 * For QP's on an SRQ, we set these to 0.
1472*12965SWilliam.Taylor@Oracle.COM 	 */
1473*12965SWilliam.Taylor@Oracle.COM 	if (qp_srq_en) {
1474*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rq_log_wqesz = 0;
1475*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rq_sgl = 0;
1476*12965SWilliam.Taylor@Oracle.COM 	} else {
1477*12965SWilliam.Taylor@Oracle.COM 		hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_rq_sgl,
1478*12965SWilliam.Taylor@Oracle.COM 		    max_recv_sgl, HERMON_QP_WQ_TYPE_RECVQ,
1479*12965SWilliam.Taylor@Oracle.COM 		    &qp->qp_rq_log_wqesz, &qp->qp_rq_sgl);
1480*12965SWilliam.Taylor@Oracle.COM 	}
1481*12965SWilliam.Taylor@Oracle.COM 	hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_sq_sgl,
1482*12965SWilliam.Taylor@Oracle.COM 	    max_sgl, swq_type, &qp->qp_sq_log_wqesz, &qp->qp_sq_sgl);
1483*12965SWilliam.Taylor@Oracle.COM 
1484*12965SWilliam.Taylor@Oracle.COM 	sq_wqe_size = 1 << qp->qp_sq_log_wqesz;
1485*12965SWilliam.Taylor@Oracle.COM 
1486*12965SWilliam.Taylor@Oracle.COM 	/* NOTE: currently policy in driver, later maybe IBTF interface */
1487*12965SWilliam.Taylor@Oracle.COM 	qp->qp_no_prefetch = 0;
1488*12965SWilliam.Taylor@Oracle.COM 
1489*12965SWilliam.Taylor@Oracle.COM 	/*
1490*12965SWilliam.Taylor@Oracle.COM 	 * for prefetching, we need to add the number of wqes in
1491*12965SWilliam.Taylor@Oracle.COM 	 * the 2k area plus one to the number requested, but
1492*12965SWilliam.Taylor@Oracle.COM 	 * ONLY for send queue.  If no_prefetch == 1 (prefetch off)
1493*12965SWilliam.Taylor@Oracle.COM 	 * it's exactly TWO wqes for the headroom
1494*12965SWilliam.Taylor@Oracle.COM 	 */
1495*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_no_prefetch)
1496*12965SWilliam.Taylor@Oracle.COM 		qp->qp_sq_headroom = 2 * sq_wqe_size;
1497*12965SWilliam.Taylor@Oracle.COM 	else
1498*12965SWilliam.Taylor@Oracle.COM 		qp->qp_sq_headroom = sq_wqe_size + HERMON_QP_OH_SIZE;
1499*12965SWilliam.Taylor@Oracle.COM 	/*
1500*12965SWilliam.Taylor@Oracle.COM 	 * hdrm wqes must be integral since both sq_wqe_size &
1501*12965SWilliam.Taylor@Oracle.COM 	 * HERMON_QP_OH_SIZE are power of 2
1502*12965SWilliam.Taylor@Oracle.COM 	 */
1503*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sq_hdrmwqes = (qp->qp_sq_headroom / sq_wqe_size);
1504*12965SWilliam.Taylor@Oracle.COM 
1505*12965SWilliam.Taylor@Oracle.COM 
1506*12965SWilliam.Taylor@Oracle.COM 	/*
1507*12965SWilliam.Taylor@Oracle.COM 	 * Calculate the appropriate size for the work queues.
1508*12965SWilliam.Taylor@Oracle.COM 	 * For send queue, add in the headroom wqes to the calculation.
1509*12965SWilliam.Taylor@Oracle.COM 	 * Note:  All Hermon QP work queues must be a power-of-2 in size.  Also
1510*12965SWilliam.Taylor@Oracle.COM 	 * they may not be any smaller than HERMON_QP_MIN_SIZE.  This step is
1511*12965SWilliam.Taylor@Oracle.COM 	 * to round the requested size up to the next highest power-of-2
1512*12965SWilliam.Taylor@Oracle.COM 	 */
1513*12965SWilliam.Taylor@Oracle.COM 	/* first, adjust to a minimum and tell the caller the change */
1514*12965SWilliam.Taylor@Oracle.COM 	attr_p->qp_sizes.cs_sq = max(attr_p->qp_sizes.cs_sq,
1515*12965SWilliam.Taylor@Oracle.COM 	    HERMON_QP_MIN_SIZE);
1516*12965SWilliam.Taylor@Oracle.COM 	attr_p->qp_sizes.cs_rq = max(attr_p->qp_sizes.cs_rq,
1517*12965SWilliam.Taylor@Oracle.COM 	    HERMON_QP_MIN_SIZE);
1518*12965SWilliam.Taylor@Oracle.COM 	/*
1519*12965SWilliam.Taylor@Oracle.COM 	 * now, calculate the alloc size, taking into account
1520*12965SWilliam.Taylor@Oracle.COM 	 * the headroom for the sq
1521*12965SWilliam.Taylor@Oracle.COM 	 */
1522*12965SWilliam.Taylor@Oracle.COM 	log_qp_sq_size = highbit(attr_p->qp_sizes.cs_sq + qp->qp_sq_hdrmwqes);
1523*12965SWilliam.Taylor@Oracle.COM 	/* if the total is a power of two, reduce it */
1524*12965SWilliam.Taylor@Oracle.COM 	if (((attr_p->qp_sizes.cs_sq + qp->qp_sq_hdrmwqes)  &
1525*12965SWilliam.Taylor@Oracle.COM 	    (attr_p->qp_sizes.cs_sq + qp->qp_sq_hdrmwqes - 1)) == 0)	{
1526*12965SWilliam.Taylor@Oracle.COM 		log_qp_sq_size = log_qp_sq_size - 1;
1527*12965SWilliam.Taylor@Oracle.COM 	}
1528*12965SWilliam.Taylor@Oracle.COM 
1529*12965SWilliam.Taylor@Oracle.COM 	log_qp_rq_size = highbit(attr_p->qp_sizes.cs_rq);
1530*12965SWilliam.Taylor@Oracle.COM 	if ((attr_p->qp_sizes.cs_rq & (attr_p->qp_sizes.cs_rq - 1)) == 0) {
1531*12965SWilliam.Taylor@Oracle.COM 		log_qp_rq_size = log_qp_rq_size - 1;
1532*12965SWilliam.Taylor@Oracle.COM 	}
1533*12965SWilliam.Taylor@Oracle.COM 
1534*12965SWilliam.Taylor@Oracle.COM 	/*
1535*12965SWilliam.Taylor@Oracle.COM 	 * Next we verify that the rounded-up size is valid (i.e. consistent
1536*12965SWilliam.Taylor@Oracle.COM 	 * with the device limits and/or software-configured limits).  If not,
1537*12965SWilliam.Taylor@Oracle.COM 	 * then obviously we have a lot of cleanup to do before returning.
1538*12965SWilliam.Taylor@Oracle.COM 	 *
1539*12965SWilliam.Taylor@Oracle.COM 	 * NOTE: the first condition deals with the (test) case of cs_sq
1540*12965SWilliam.Taylor@Oracle.COM 	 * being just less than 2^32.  In this case, the headroom addition
1541*12965SWilliam.Taylor@Oracle.COM 	 * to the requested cs_sq will pass the test when it should not.
1542*12965SWilliam.Taylor@Oracle.COM 	 * This test no longer lets that case slip through the check.
1543*12965SWilliam.Taylor@Oracle.COM 	 */
1544*12965SWilliam.Taylor@Oracle.COM 	if ((attr_p->qp_sizes.cs_sq >
1545*12965SWilliam.Taylor@Oracle.COM 	    (1 << state->hs_cfg_profile->cp_log_max_qp_sz)) ||
1546*12965SWilliam.Taylor@Oracle.COM 	    (log_qp_sq_size > state->hs_cfg_profile->cp_log_max_qp_sz) ||
1547*12965SWilliam.Taylor@Oracle.COM 	    (!qp_srq_en && (log_qp_rq_size >
1548*12965SWilliam.Taylor@Oracle.COM 	    state->hs_cfg_profile->cp_log_max_qp_sz))) {
1549*12965SWilliam.Taylor@Oracle.COM 		status = IBT_HCA_WR_EXCEEDED;
1550*12965SWilliam.Taylor@Oracle.COM 		goto qpalloc_fail7;
1551*12965SWilliam.Taylor@Oracle.COM 	}
1552*12965SWilliam.Taylor@Oracle.COM 
1553*12965SWilliam.Taylor@Oracle.COM 	/*
1554*12965SWilliam.Taylor@Oracle.COM 	 * Allocate the memory for QP work queues. Since Hermon work queues
1555*12965SWilliam.Taylor@Oracle.COM 	 * are not allowed to cross a 32-bit (4GB) boundary, the alignment of
1556*12965SWilliam.Taylor@Oracle.COM 	 * the work queue memory is very important.  We used to allocate
1557*12965SWilliam.Taylor@Oracle.COM 	 * work queues (the combined receive and send queues) so that they
1558*12965SWilliam.Taylor@Oracle.COM 	 * would be aligned on their combined size.  That alignment guaranteed
1559*12965SWilliam.Taylor@Oracle.COM 	 * that they would never cross the 4GB boundary (Hermon work queues
1560*12965SWilliam.Taylor@Oracle.COM 	 * are on the order of MBs at maximum).  Now we are able to relax
1561*12965SWilliam.Taylor@Oracle.COM 	 * this alignment constraint by ensuring that the IB address assigned
1562*12965SWilliam.Taylor@Oracle.COM 	 * to the queue memory (as a result of the hermon_mr_register() call)
1563*12965SWilliam.Taylor@Oracle.COM 	 * is offset from zero.
1564*12965SWilliam.Taylor@Oracle.COM 	 * Previously, we had wanted to use the ddi_dma_mem_alloc() routine to
1565*12965SWilliam.Taylor@Oracle.COM 	 * guarantee the alignment, but when attempting to use IOMMU bypass
1566*12965SWilliam.Taylor@Oracle.COM 	 * mode we found that we were not allowed to specify any alignment
1567*12965SWilliam.Taylor@Oracle.COM 	 * that was more restrictive than the system page size.
1568*12965SWilliam.Taylor@Oracle.COM 	 * So we avoided this constraint by passing two alignment values,
1569*12965SWilliam.Taylor@Oracle.COM 	 * one for the memory allocation itself and the other for the DMA
1570*12965SWilliam.Taylor@Oracle.COM 	 * handle (for later bind).  This used to cause more memory than
1571*12965SWilliam.Taylor@Oracle.COM 	 * necessary to be allocated (in order to guarantee the more
1572*12965SWilliam.Taylor@Oracle.COM 	 * restrictive alignment contraint).  But by guaranteeing the
1573*12965SWilliam.Taylor@Oracle.COM 	 * zero-based IB virtual address for the queue, we are able to
1574*12965SWilliam.Taylor@Oracle.COM 	 * conserve this memory.
1575*12965SWilliam.Taylor@Oracle.COM 	 */
1576*12965SWilliam.Taylor@Oracle.COM 	sq_wqe_size = 1 << qp->qp_sq_log_wqesz;
1577*12965SWilliam.Taylor@Oracle.COM 	sq_depth    = 1 << log_qp_sq_size;
1578*12965SWilliam.Taylor@Oracle.COM 	sq_size	    = sq_depth * sq_wqe_size;
1579*12965SWilliam.Taylor@Oracle.COM 
1580*12965SWilliam.Taylor@Oracle.COM 	/* QP on SRQ sets these to 0 */
1581*12965SWilliam.Taylor@Oracle.COM 	if (qp_srq_en) {
1582*12965SWilliam.Taylor@Oracle.COM 		rq_wqe_size = 0;
1583*12965SWilliam.Taylor@Oracle.COM 		rq_size	    = 0;
1584*12965SWilliam.Taylor@Oracle.COM 	} else {
1585*12965SWilliam.Taylor@Oracle.COM 		rq_wqe_size = 1 << qp->qp_rq_log_wqesz;
1586*12965SWilliam.Taylor@Oracle.COM 		rq_depth    = 1 << log_qp_rq_size;
1587*12965SWilliam.Taylor@Oracle.COM 		rq_size	    = rq_depth * rq_wqe_size;
1588*12965SWilliam.Taylor@Oracle.COM 	}
1589*12965SWilliam.Taylor@Oracle.COM 
1590*12965SWilliam.Taylor@Oracle.COM 	qp->qp_wqinfo.qa_size = sq_size + rq_size;
1591*12965SWilliam.Taylor@Oracle.COM 	qp->qp_wqinfo.qa_alloc_align = PAGESIZE;
1592*12965SWilliam.Taylor@Oracle.COM 	qp->qp_wqinfo.qa_bind_align  = PAGESIZE;
1593*12965SWilliam.Taylor@Oracle.COM 	qp->qp_wqinfo.qa_location = HERMON_QUEUE_LOCATION_NORMAL;
1594*12965SWilliam.Taylor@Oracle.COM 	status = hermon_queue_alloc(state, &qp->qp_wqinfo, sleepflag);
1595*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
1596*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INSUFF_RESOURCE;
1597*12965SWilliam.Taylor@Oracle.COM 		goto qpalloc_fail7;
1598*12965SWilliam.Taylor@Oracle.COM 	}
1599*12965SWilliam.Taylor@Oracle.COM 
1600*12965SWilliam.Taylor@Oracle.COM 	/*
1601*12965SWilliam.Taylor@Oracle.COM 	 * Sort WQs in memory according to stride (*q_wqe_size), largest first
1602*12965SWilliam.Taylor@Oracle.COM 	 * If they are equal, still put the SQ first
1603*12965SWilliam.Taylor@Oracle.COM 	 */
1604*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sq_baseaddr = 0;
1605*12965SWilliam.Taylor@Oracle.COM 	qp->qp_rq_baseaddr = 0;
1606*12965SWilliam.Taylor@Oracle.COM 	if ((sq_wqe_size > rq_wqe_size) || (sq_wqe_size == rq_wqe_size)) {
1607*12965SWilliam.Taylor@Oracle.COM 		sq_buf = qp->qp_wqinfo.qa_buf_aligned;
1608*12965SWilliam.Taylor@Oracle.COM 
1609*12965SWilliam.Taylor@Oracle.COM 		/* if this QP is on an SRQ, set the rq_buf to NULL */
1610*12965SWilliam.Taylor@Oracle.COM 		if (qp_srq_en) {
1611*12965SWilliam.Taylor@Oracle.COM 			rq_buf = NULL;
1612*12965SWilliam.Taylor@Oracle.COM 		} else {
1613*12965SWilliam.Taylor@Oracle.COM 			rq_buf = (uint32_t *)((uintptr_t)sq_buf + sq_size);
1614*12965SWilliam.Taylor@Oracle.COM 			qp->qp_rq_baseaddr = sq_size;
1615*12965SWilliam.Taylor@Oracle.COM 		}
1616*12965SWilliam.Taylor@Oracle.COM 	} else {
1617*12965SWilliam.Taylor@Oracle.COM 		rq_buf = qp->qp_wqinfo.qa_buf_aligned;
1618*12965SWilliam.Taylor@Oracle.COM 		sq_buf = (uint32_t *)((uintptr_t)rq_buf + rq_size);
1619*12965SWilliam.Taylor@Oracle.COM 		qp->qp_sq_baseaddr = rq_size;
1620*12965SWilliam.Taylor@Oracle.COM 	}
1621*12965SWilliam.Taylor@Oracle.COM 
1622*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sq_wqhdr = hermon_wrid_wqhdr_create(sq_depth);
1623*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_sq_wqhdr == NULL) {
1624*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INSUFF_RESOURCE;
1625*12965SWilliam.Taylor@Oracle.COM 		goto qpalloc_fail8;
1626*12965SWilliam.Taylor@Oracle.COM 	}
1627*12965SWilliam.Taylor@Oracle.COM 	if (qp_srq_en) {
1628*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rq_wqavl.wqa_wq = srq->srq_wq_wqhdr;
1629*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rq_wqavl.wqa_srq_en = 1;
1630*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rq_wqavl.wqa_srq = srq;
1631*12965SWilliam.Taylor@Oracle.COM 	} else {
1632*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rq_wqhdr = hermon_wrid_wqhdr_create(rq_depth);
1633*12965SWilliam.Taylor@Oracle.COM 		if (qp->qp_rq_wqhdr == NULL) {
1634*12965SWilliam.Taylor@Oracle.COM 			status = IBT_INSUFF_RESOURCE;
1635*12965SWilliam.Taylor@Oracle.COM 			goto qpalloc_fail8;
1636*12965SWilliam.Taylor@Oracle.COM 		}
1637*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rq_wqavl.wqa_wq = qp->qp_rq_wqhdr;
1638*12965SWilliam.Taylor@Oracle.COM 	}
1639*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sq_wqavl.wqa_qpn = qp->qp_qpnum;
1640*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sq_wqavl.wqa_type = HERMON_WR_SEND;
1641*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sq_wqavl.wqa_wq = qp->qp_sq_wqhdr;
1642*12965SWilliam.Taylor@Oracle.COM 	qp->qp_rq_wqavl.wqa_qpn = qp->qp_qpnum;
1643*12965SWilliam.Taylor@Oracle.COM 	qp->qp_rq_wqavl.wqa_type = HERMON_WR_RECV;
1644*12965SWilliam.Taylor@Oracle.COM 
1645*12965SWilliam.Taylor@Oracle.COM 	/*
1646*12965SWilliam.Taylor@Oracle.COM 	 * Register the memory for the QP work queues.  The memory for the
1647*12965SWilliam.Taylor@Oracle.COM 	 * QP must be registered in the Hermon cMPT tables.  This gives us the
1648*12965SWilliam.Taylor@Oracle.COM 	 * LKey to specify in the QP context later.  Note: The memory for
1649*12965SWilliam.Taylor@Oracle.COM 	 * Hermon work queues (both Send and Recv) must be contiguous and
1650*12965SWilliam.Taylor@Oracle.COM 	 * registered as a single memory region.  Note: If the QP memory is
1651*12965SWilliam.Taylor@Oracle.COM 	 * user-mappable, force DDI_DMA_CONSISTENT mapping. Also, in order to
1652*12965SWilliam.Taylor@Oracle.COM 	 * meet the alignment restriction, we pass the "mro_bind_override_addr"
1653*12965SWilliam.Taylor@Oracle.COM 	 * flag in the call to hermon_mr_register(). This guarantees that the
1654*12965SWilliam.Taylor@Oracle.COM 	 * resulting IB vaddr will be zero-based (modulo the offset into the
1655*12965SWilliam.Taylor@Oracle.COM 	 * first page). If we fail here, we still have the bunch of resource
1656*12965SWilliam.Taylor@Oracle.COM 	 * and reference count cleanup to do.
1657*12965SWilliam.Taylor@Oracle.COM 	 */
1658*12965SWilliam.Taylor@Oracle.COM 	flag = (sleepflag == HERMON_SLEEP) ? IBT_MR_SLEEP :
1659*12965SWilliam.Taylor@Oracle.COM 	    IBT_MR_NOSLEEP;
1660*12965SWilliam.Taylor@Oracle.COM 	mr_attr.mr_vaddr    = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
1661*12965SWilliam.Taylor@Oracle.COM 	mr_attr.mr_len	    = qp->qp_wqinfo.qa_size;
1662*12965SWilliam.Taylor@Oracle.COM 	mr_attr.mr_as	    = NULL;
1663*12965SWilliam.Taylor@Oracle.COM 	mr_attr.mr_flags    = flag;
1664*12965SWilliam.Taylor@Oracle.COM 	/* HERMON_QUEUE_LOCATION_NORMAL */
1665*12965SWilliam.Taylor@Oracle.COM 	mr_op.mro_bind_type =
1666*12965SWilliam.Taylor@Oracle.COM 	    state->hs_cfg_profile->cp_iommu_bypass;
1667*12965SWilliam.Taylor@Oracle.COM 	mr_op.mro_bind_dmahdl = qp->qp_wqinfo.qa_dmahdl;
1668*12965SWilliam.Taylor@Oracle.COM 	mr_op.mro_bind_override_addr = 1;
1669*12965SWilliam.Taylor@Oracle.COM 	status = hermon_mr_register(state, pd, &mr_attr, &mr,
1670*12965SWilliam.Taylor@Oracle.COM 	    &mr_op, HERMON_QP_CMPT);
1671*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
1672*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INSUFF_RESOURCE;
1673*12965SWilliam.Taylor@Oracle.COM 		goto qpalloc_fail9;
1674*12965SWilliam.Taylor@Oracle.COM 	}
1675*12965SWilliam.Taylor@Oracle.COM 
1676*12965SWilliam.Taylor@Oracle.COM 	/*
1677*12965SWilliam.Taylor@Oracle.COM 	 * Calculate the offset between the kernel virtual address space
1678*12965SWilliam.Taylor@Oracle.COM 	 * and the IB virtual address space.  This will be used when
1679*12965SWilliam.Taylor@Oracle.COM 	 * posting work requests to properly initialize each WQE.
1680*12965SWilliam.Taylor@Oracle.COM 	 */
1681*12965SWilliam.Taylor@Oracle.COM 	qp_desc_off = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
1682*12965SWilliam.Taylor@Oracle.COM 	    (uint64_t)mr->mr_bindinfo.bi_addr;
1683*12965SWilliam.Taylor@Oracle.COM 
1684*12965SWilliam.Taylor@Oracle.COM 	/*
1685*12965SWilliam.Taylor@Oracle.COM 	 * Fill in all the return arguments (if necessary).  This includes
1686*12965SWilliam.Taylor@Oracle.COM 	 * real work queue sizes (in wqes), real SGLs, and QP number
1687*12965SWilliam.Taylor@Oracle.COM 	 */
1688*12965SWilliam.Taylor@Oracle.COM 	if (queuesz_p != NULL) {
1689*12965SWilliam.Taylor@Oracle.COM 		queuesz_p->cs_sq 	=
1690*12965SWilliam.Taylor@Oracle.COM 		    (1 << log_qp_sq_size) - qp->qp_sq_hdrmwqes;
1691*12965SWilliam.Taylor@Oracle.COM 		queuesz_p->cs_sq_sgl	= qp->qp_sq_sgl;
1692*12965SWilliam.Taylor@Oracle.COM 
1693*12965SWilliam.Taylor@Oracle.COM 		/* if this QP is on an SRQ, set these to 0 */
1694*12965SWilliam.Taylor@Oracle.COM 		if (qp_srq_en) {
1695*12965SWilliam.Taylor@Oracle.COM 			queuesz_p->cs_rq	= 0;
1696*12965SWilliam.Taylor@Oracle.COM 			queuesz_p->cs_rq_sgl	= 0;
1697*12965SWilliam.Taylor@Oracle.COM 		} else {
1698*12965SWilliam.Taylor@Oracle.COM 			queuesz_p->cs_rq	= (1 << log_qp_rq_size);
1699*12965SWilliam.Taylor@Oracle.COM 			queuesz_p->cs_rq_sgl	= qp->qp_rq_sgl;
1700*12965SWilliam.Taylor@Oracle.COM 		}
1701*12965SWilliam.Taylor@Oracle.COM 	}
1702*12965SWilliam.Taylor@Oracle.COM 
1703*12965SWilliam.Taylor@Oracle.COM 	/*
1704*12965SWilliam.Taylor@Oracle.COM 	 * Fill in the rest of the Hermon Queue Pair handle.
1705*12965SWilliam.Taylor@Oracle.COM 	 */
1706*12965SWilliam.Taylor@Oracle.COM 	qp->qp_qpcrsrcp		= NULL;
1707*12965SWilliam.Taylor@Oracle.COM 	qp->qp_rsrcp		= rsrc;
1708*12965SWilliam.Taylor@Oracle.COM 	qp->qp_state		= HERMON_QP_RESET;
1709*12965SWilliam.Taylor@Oracle.COM 	HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
1710*12965SWilliam.Taylor@Oracle.COM 	qp->qp_pdhdl		= pd;
1711*12965SWilliam.Taylor@Oracle.COM 	qp->qp_mrhdl		= mr;
1712*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sq_sigtype	= (attr_p->qp_flags & IBT_WR_SIGNALED) ?
1713*12965SWilliam.Taylor@Oracle.COM 	    HERMON_QP_SQ_WR_SIGNALED : HERMON_QP_SQ_ALL_SIGNALED;
1714*12965SWilliam.Taylor@Oracle.COM 	qp->qp_is_special	= 0;
1715*12965SWilliam.Taylor@Oracle.COM 	qp->qp_uarpg		= uarpg;
1716*12965SWilliam.Taylor@Oracle.COM 	qp->qp_umap_dhp		= (devmap_cookie_t)NULL;
1717*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sq_cqhdl		= sq_cq;
1718*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sq_bufsz		= (1 << log_qp_sq_size);
1719*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sq_logqsz	= log_qp_sq_size;
1720*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sq_buf		= sq_buf;
1721*12965SWilliam.Taylor@Oracle.COM 	qp->qp_desc_off		= qp_desc_off;
1722*12965SWilliam.Taylor@Oracle.COM 	qp->qp_rq_cqhdl		= rq_cq;
1723*12965SWilliam.Taylor@Oracle.COM 	qp->qp_rq_buf		= rq_buf;
1724*12965SWilliam.Taylor@Oracle.COM 	qp->qp_rlky		= (attr_p->qp_flags & IBT_FAST_REG_RES_LKEY) !=
1725*12965SWilliam.Taylor@Oracle.COM 	    0;
1726*12965SWilliam.Taylor@Oracle.COM 
1727*12965SWilliam.Taylor@Oracle.COM 	/* if this QP is on an SRQ, set rq_bufsz to 0 */
1728*12965SWilliam.Taylor@Oracle.COM 	if (qp_srq_en) {
1729*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rq_bufsz		= 0;
1730*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rq_logqsz	= 0;
1731*12965SWilliam.Taylor@Oracle.COM 	} else {
1732*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rq_bufsz		= (1 << log_qp_rq_size);
1733*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rq_logqsz	= log_qp_rq_size;
1734*12965SWilliam.Taylor@Oracle.COM 	}
1735*12965SWilliam.Taylor@Oracle.COM 
1736*12965SWilliam.Taylor@Oracle.COM 	qp->qp_forward_sqd_event  = 0;
1737*12965SWilliam.Taylor@Oracle.COM 	qp->qp_sqd_still_draining = 0;
1738*12965SWilliam.Taylor@Oracle.COM 	qp->qp_hdlrarg		= (void *)ibt_qphdl[ii];
1739*12965SWilliam.Taylor@Oracle.COM 	qp->qp_mcg_refcnt	= 0;
1740*12965SWilliam.Taylor@Oracle.COM 
1741*12965SWilliam.Taylor@Oracle.COM 	/*
1742*12965SWilliam.Taylor@Oracle.COM 	 * If this QP is to be associated with an SRQ, set the SRQ handle
1743*12965SWilliam.Taylor@Oracle.COM 	 */
1744*12965SWilliam.Taylor@Oracle.COM 	if (qp_srq_en) {
1745*12965SWilliam.Taylor@Oracle.COM 		qp->qp_srqhdl = srq;
1746*12965SWilliam.Taylor@Oracle.COM 		hermon_srq_refcnt_inc(qp->qp_srqhdl);
1747*12965SWilliam.Taylor@Oracle.COM 	} else {
1748*12965SWilliam.Taylor@Oracle.COM 		qp->qp_srqhdl = NULL;
1749*12965SWilliam.Taylor@Oracle.COM 	}
1750*12965SWilliam.Taylor@Oracle.COM 
1751*12965SWilliam.Taylor@Oracle.COM 	qp->qp_type = IBT_UD_RQP;
1752*12965SWilliam.Taylor@Oracle.COM 	qp->qp_serv_type = serv_type;
1753*12965SWilliam.Taylor@Oracle.COM 
1754*12965SWilliam.Taylor@Oracle.COM 	/*
1755*12965SWilliam.Taylor@Oracle.COM 	 * Initialize the RQ WQEs - unlike Arbel, no Rcv init is needed
1756*12965SWilliam.Taylor@Oracle.COM 	 */
1757*12965SWilliam.Taylor@Oracle.COM 
1758*12965SWilliam.Taylor@Oracle.COM 	/*
1759*12965SWilliam.Taylor@Oracle.COM 	 * Initialize the SQ WQEs - all that needs to be done is every 64 bytes
1760*12965SWilliam.Taylor@Oracle.COM 	 * set the quadword to all F's - high-order bit is owner (init to one)
1761*12965SWilliam.Taylor@Oracle.COM 	 * and the rest for the headroom definition of prefetching.
1762*12965SWilliam.Taylor@Oracle.COM 	 */
1763*12965SWilliam.Taylor@Oracle.COM 	if ((attr_p->qp_alloc_flags & IBT_QP_USES_FEXCH) == 0) {
1764*12965SWilliam.Taylor@Oracle.COM 		wqesz_shift = qp->qp_sq_log_wqesz;
1765*12965SWilliam.Taylor@Oracle.COM 		thewqesz    = 1 << wqesz_shift;
1766*12965SWilliam.Taylor@Oracle.COM 		thewqe = (uint64_t *)(void *)(qp->qp_sq_buf);
1767*12965SWilliam.Taylor@Oracle.COM 		for (i = 0; i < sq_depth; i++) {
1768*12965SWilliam.Taylor@Oracle.COM 			/*
1769*12965SWilliam.Taylor@Oracle.COM 			 * for each stride, go through and every 64 bytes
1770*12965SWilliam.Taylor@Oracle.COM 			 * write the init value - having set the address
1771*12965SWilliam.Taylor@Oracle.COM 			 * once, just keep incrementing it
1772*12965SWilliam.Taylor@Oracle.COM 			 */
1773*12965SWilliam.Taylor@Oracle.COM 			for (j = 0; j < thewqesz; j += 64, thewqe += 8) {
1774*12965SWilliam.Taylor@Oracle.COM 				*(uint32_t *)thewqe = 0xFFFFFFFF;
1775*12965SWilliam.Taylor@Oracle.COM 			}
1776*12965SWilliam.Taylor@Oracle.COM 		}
1777*12965SWilliam.Taylor@Oracle.COM 	}
1778*12965SWilliam.Taylor@Oracle.COM 
1779*12965SWilliam.Taylor@Oracle.COM 	/* Zero out the QP context */
1780*12965SWilliam.Taylor@Oracle.COM 	bzero(&qp->qpc, sizeof (hermon_hw_qpc_t));
1781*12965SWilliam.Taylor@Oracle.COM 
1782*12965SWilliam.Taylor@Oracle.COM 	/*
1783*12965SWilliam.Taylor@Oracle.COM 	 * Put QP handle in Hermon QPNum-to-QPHdl list.  Then fill in the
1784*12965SWilliam.Taylor@Oracle.COM 	 * "qphdl" and return success
1785*12965SWilliam.Taylor@Oracle.COM 	 */
1786*12965SWilliam.Taylor@Oracle.COM 	hermon_icm_set_num_to_hdl(state, HERMON_QPC, qpc->hr_indx + ii, qp);
1787*12965SWilliam.Taylor@Oracle.COM 
1788*12965SWilliam.Taylor@Oracle.COM 	mutex_init(&qp->qp_sq_lock, NULL, MUTEX_DRIVER,
1789*12965SWilliam.Taylor@Oracle.COM 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
1790*12965SWilliam.Taylor@Oracle.COM 
1791*12965SWilliam.Taylor@Oracle.COM 	qp->qp_rangep = qp_range_p;
1792*12965SWilliam.Taylor@Oracle.COM 
1793*12965SWilliam.Taylor@Oracle.COM 	qphdl[ii] = qp;
1794*12965SWilliam.Taylor@Oracle.COM 
1795*12965SWilliam.Taylor@Oracle.COM 	if (++ii < (1 << log2))
1796*12965SWilliam.Taylor@Oracle.COM 		goto for_each_qp;
1797*12965SWilliam.Taylor@Oracle.COM 
1798*12965SWilliam.Taylor@Oracle.COM 	return (DDI_SUCCESS);
1799*12965SWilliam.Taylor@Oracle.COM 
1800*12965SWilliam.Taylor@Oracle.COM /*
1801*12965SWilliam.Taylor@Oracle.COM  * The following is cleanup for all possible failure cases in this routine
1802*12965SWilliam.Taylor@Oracle.COM  */
1803*12965SWilliam.Taylor@Oracle.COM qpalloc_fail9:
1804*12965SWilliam.Taylor@Oracle.COM 	hermon_queue_free(&qp->qp_wqinfo);
1805*12965SWilliam.Taylor@Oracle.COM qpalloc_fail8:
1806*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_sq_wqhdr)
1807*12965SWilliam.Taylor@Oracle.COM 		hermon_wrid_wqhdr_destroy(qp->qp_sq_wqhdr);
1808*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_rq_wqhdr)
1809*12965SWilliam.Taylor@Oracle.COM 		hermon_wrid_wqhdr_destroy(qp->qp_rq_wqhdr);
1810*12965SWilliam.Taylor@Oracle.COM qpalloc_fail7:
1811*12965SWilliam.Taylor@Oracle.COM 	if (!qp_srq_en) {
1812*12965SWilliam.Taylor@Oracle.COM 		hermon_dbr_free(state, uarpg, qp->qp_rq_vdbr);
1813*12965SWilliam.Taylor@Oracle.COM 	}
1814*12965SWilliam.Taylor@Oracle.COM 
1815*12965SWilliam.Taylor@Oracle.COM qpalloc_fail6:
1816*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_free(state, &rsrc);
1817*12965SWilliam.Taylor@Oracle.COM qpalloc_fail4:
1818*12965SWilliam.Taylor@Oracle.COM 	hermon_cq_refcnt_dec(rq_cq);
1819*12965SWilliam.Taylor@Oracle.COM qpalloc_fail2:
1820*12965SWilliam.Taylor@Oracle.COM 	hermon_cq_refcnt_dec(sq_cq);
1821*12965SWilliam.Taylor@Oracle.COM qpalloc_fail1:
1822*12965SWilliam.Taylor@Oracle.COM 	hermon_pd_refcnt_dec(pd);
1823*12965SWilliam.Taylor@Oracle.COM qpalloc_fail0:
1824*12965SWilliam.Taylor@Oracle.COM 	if (ii == 0) {
1825*12965SWilliam.Taylor@Oracle.COM 		if (qp_range_p)
1826*12965SWilliam.Taylor@Oracle.COM 			kmem_free(qp_range_p, sizeof (*qp_range_p));
1827*12965SWilliam.Taylor@Oracle.COM 		hermon_rsrc_free(state, &qpc);
1828*12965SWilliam.Taylor@Oracle.COM 	} else {
1829*12965SWilliam.Taylor@Oracle.COM 		/* qp_range_p and qpc rsrc will be freed in hermon_qp_free */
1830*12965SWilliam.Taylor@Oracle.COM 
1831*12965SWilliam.Taylor@Oracle.COM 		mutex_enter(&qp->qp_rangep->hqpr_lock);
1832*12965SWilliam.Taylor@Oracle.COM 		qp_range_p->hqpr_refcnt = ii;
1833*12965SWilliam.Taylor@Oracle.COM 		mutex_exit(&qp->qp_rangep->hqpr_lock);
1834*12965SWilliam.Taylor@Oracle.COM 		while (--ii >= 0) {
1835*12965SWilliam.Taylor@Oracle.COM 			ibc_qpn_hdl_t qpn_hdl;
1836*12965SWilliam.Taylor@Oracle.COM 			int free_status;
1837*12965SWilliam.Taylor@Oracle.COM 
1838*12965SWilliam.Taylor@Oracle.COM 			free_status = hermon_qp_free(state, &qphdl[ii],
1839*12965SWilliam.Taylor@Oracle.COM 			    IBC_FREE_QP_AND_QPN, &qpn_hdl, sleepflag);
1840*12965SWilliam.Taylor@Oracle.COM 			if (free_status != DDI_SUCCESS)
1841*12965SWilliam.Taylor@Oracle.COM 				cmn_err(CE_CONT, "!qp_range: status 0x%x: "
1842*12965SWilliam.Taylor@Oracle.COM 				    "error status %x during free",
1843*12965SWilliam.Taylor@Oracle.COM 				    status, free_status);
1844*12965SWilliam.Taylor@Oracle.COM 		}
1845*12965SWilliam.Taylor@Oracle.COM 	}
1846*12965SWilliam.Taylor@Oracle.COM 
1847*12965SWilliam.Taylor@Oracle.COM 	return (status);
1848*12965SWilliam.Taylor@Oracle.COM }
1849*12965SWilliam.Taylor@Oracle.COM 
1850*12965SWilliam.Taylor@Oracle.COM 
1851*12965SWilliam.Taylor@Oracle.COM /*
18529517SBill.Taylor@Sun.COM  * hermon_qp_free()
18539517SBill.Taylor@Sun.COM  *    This function frees up the QP resources.  Depending on the value
18549517SBill.Taylor@Sun.COM  *    of the "free_qp_flags", the QP number may not be released until
18559517SBill.Taylor@Sun.COM  *    a subsequent call to hermon_qp_release_qpn().
18569517SBill.Taylor@Sun.COM  *
18579517SBill.Taylor@Sun.COM  *    Context: Can be called only from user or kernel context.
18589517SBill.Taylor@Sun.COM  */
18599517SBill.Taylor@Sun.COM /* ARGSUSED */
18609517SBill.Taylor@Sun.COM int
hermon_qp_free(hermon_state_t * state,hermon_qphdl_t * qphdl,ibc_free_qp_flags_t free_qp_flags,ibc_qpn_hdl_t * qpnh,uint_t sleepflag)18619517SBill.Taylor@Sun.COM hermon_qp_free(hermon_state_t *state, hermon_qphdl_t *qphdl,
18629517SBill.Taylor@Sun.COM     ibc_free_qp_flags_t free_qp_flags, ibc_qpn_hdl_t *qpnh,
18639517SBill.Taylor@Sun.COM     uint_t sleepflag)
18649517SBill.Taylor@Sun.COM {
18659517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*qpc, *rsrc;
18669517SBill.Taylor@Sun.COM 	hermon_umap_db_entry_t	*umapdb;
18679517SBill.Taylor@Sun.COM 	hermon_qpn_entry_t	*entry;
18689517SBill.Taylor@Sun.COM 	hermon_pdhdl_t		pd;
18699517SBill.Taylor@Sun.COM 	hermon_mrhdl_t		mr;
18709517SBill.Taylor@Sun.COM 	hermon_cqhdl_t		sq_cq, rq_cq;
18719517SBill.Taylor@Sun.COM 	hermon_srqhdl_t		srq;
18729517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
18739517SBill.Taylor@Sun.COM 	uint64_t		value;
18749517SBill.Taylor@Sun.COM 	uint_t			type, port;
18759517SBill.Taylor@Sun.COM 	uint_t			maxprot;
18769517SBill.Taylor@Sun.COM 	uint_t			qp_srq_en;
18779517SBill.Taylor@Sun.COM 	int			status;
18789517SBill.Taylor@Sun.COM 
18799517SBill.Taylor@Sun.COM 	/*
18809517SBill.Taylor@Sun.COM 	 * Pull all the necessary information from the Hermon Queue Pair
18819517SBill.Taylor@Sun.COM 	 * handle.  This is necessary here because the resource for the
18829517SBill.Taylor@Sun.COM 	 * QP handle is going to be freed up as part of this operation.
18839517SBill.Taylor@Sun.COM 	 */
18849517SBill.Taylor@Sun.COM 	qp	= *qphdl;
18859517SBill.Taylor@Sun.COM 	mutex_enter(&qp->qp_lock);
1886*12965SWilliam.Taylor@Oracle.COM 	qpc	= qp->qp_qpcrsrcp;	/* NULL if part of a "range" */
18879517SBill.Taylor@Sun.COM 	rsrc	= qp->qp_rsrcp;
18889517SBill.Taylor@Sun.COM 	pd	= qp->qp_pdhdl;
18899517SBill.Taylor@Sun.COM 	srq	= qp->qp_srqhdl;
18909517SBill.Taylor@Sun.COM 	mr	= qp->qp_mrhdl;
18919517SBill.Taylor@Sun.COM 	rq_cq	= qp->qp_rq_cqhdl;
18929517SBill.Taylor@Sun.COM 	sq_cq	= qp->qp_sq_cqhdl;
18939517SBill.Taylor@Sun.COM 	port	= qp->qp_portnum;
1894*12965SWilliam.Taylor@Oracle.COM 	qp_srq_en = qp->qp_alloc_flags & IBT_QP_USES_SRQ;
18959517SBill.Taylor@Sun.COM 
18969517SBill.Taylor@Sun.COM 	/*
18979517SBill.Taylor@Sun.COM 	 * If the QP is part of an MCG, then we fail the qp_free
18989517SBill.Taylor@Sun.COM 	 */
18999517SBill.Taylor@Sun.COM 	if (qp->qp_mcg_refcnt != 0) {
19009517SBill.Taylor@Sun.COM 		mutex_exit(&qp->qp_lock);
19019517SBill.Taylor@Sun.COM 		status = ibc_get_ci_failure(0);
19029517SBill.Taylor@Sun.COM 		goto qpfree_fail;
19039517SBill.Taylor@Sun.COM 	}
19049517SBill.Taylor@Sun.COM 
19059517SBill.Taylor@Sun.COM 	/*
19069517SBill.Taylor@Sun.COM 	 * If the QP is not already in "Reset" state, then transition to
19079517SBill.Taylor@Sun.COM 	 * "Reset".  This is necessary because software does not reclaim
19089517SBill.Taylor@Sun.COM 	 * ownership of the QP context until the QP is in the "Reset" state.
19099517SBill.Taylor@Sun.COM 	 * If the ownership transfer fails for any reason, then it is an
19109517SBill.Taylor@Sun.COM 	 * indication that something (either in HW or SW) has gone seriously
19119517SBill.Taylor@Sun.COM 	 * wrong.  So we print a warning message and return.
19129517SBill.Taylor@Sun.COM 	 */
19139517SBill.Taylor@Sun.COM 	if (qp->qp_state != HERMON_QP_RESET) {
19149517SBill.Taylor@Sun.COM 		if (hermon_qp_to_reset(state, qp) != DDI_SUCCESS) {
19159517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
19169517SBill.Taylor@Sun.COM 			HERMON_WARNING(state, "failed to reset QP context");
19179517SBill.Taylor@Sun.COM 			status = ibc_get_ci_failure(0);
19189517SBill.Taylor@Sun.COM 			goto qpfree_fail;
19199517SBill.Taylor@Sun.COM 		}
19209517SBill.Taylor@Sun.COM 		qp->qp_state = HERMON_QP_RESET;
1921*12965SWilliam.Taylor@Oracle.COM 		HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
19229517SBill.Taylor@Sun.COM 
19239517SBill.Taylor@Sun.COM 		/*
19249517SBill.Taylor@Sun.COM 		 * Do any additional handling necessary for the transition
19259517SBill.Taylor@Sun.COM 		 * to the "Reset" state (e.g. update the WRID lists)
19269517SBill.Taylor@Sun.COM 		 */
19279517SBill.Taylor@Sun.COM 		if (hermon_wrid_to_reset_handling(state, qp) != DDI_SUCCESS) {
19289517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
19299517SBill.Taylor@Sun.COM 			HERMON_WARNING(state, "failed to reset QP WRID list");
19309517SBill.Taylor@Sun.COM 			status = ibc_get_ci_failure(0);
19319517SBill.Taylor@Sun.COM 			goto qpfree_fail;
19329517SBill.Taylor@Sun.COM 		}
19339517SBill.Taylor@Sun.COM 	}
19349517SBill.Taylor@Sun.COM 
19359517SBill.Taylor@Sun.COM 	/*
19369517SBill.Taylor@Sun.COM 	 * If this was a user-mappable QP, then we need to remove its entry
19379517SBill.Taylor@Sun.COM 	 * from the "userland resources database".  If it is also currently
19389517SBill.Taylor@Sun.COM 	 * mmap()'d out to a user process, then we need to call
19399517SBill.Taylor@Sun.COM 	 * devmap_devmem_remap() to remap the QP memory to an invalid mapping.
19409517SBill.Taylor@Sun.COM 	 * We also need to invalidate the QP tracking information for the
19419517SBill.Taylor@Sun.COM 	 * user mapping.
19429517SBill.Taylor@Sun.COM 	 */
1943*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_alloc_flags & IBT_QP_USER_MAP) {
19449517SBill.Taylor@Sun.COM 		status = hermon_umap_db_find(state->hs_instance, qp->qp_qpnum,
19459517SBill.Taylor@Sun.COM 		    MLNX_UMAP_QPMEM_RSRC, &value, HERMON_UMAP_DB_REMOVE,
19469517SBill.Taylor@Sun.COM 		    &umapdb);
19479517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
19489517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
19499517SBill.Taylor@Sun.COM 			HERMON_WARNING(state, "failed to find in database");
19509517SBill.Taylor@Sun.COM 			return (ibc_get_ci_failure(0));
19519517SBill.Taylor@Sun.COM 		}
19529517SBill.Taylor@Sun.COM 		hermon_umap_db_free(umapdb);
19539517SBill.Taylor@Sun.COM 		if (qp->qp_umap_dhp != NULL) {
19549517SBill.Taylor@Sun.COM 			maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
19559517SBill.Taylor@Sun.COM 			status = devmap_devmem_remap(qp->qp_umap_dhp,
19569517SBill.Taylor@Sun.COM 			    state->hs_dip, 0, 0, qp->qp_wqinfo.qa_size,
19579517SBill.Taylor@Sun.COM 			    maxprot, DEVMAP_MAPPING_INVALID, NULL);
19589517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
19599517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
19609517SBill.Taylor@Sun.COM 				HERMON_WARNING(state, "failed in QP memory "
19619517SBill.Taylor@Sun.COM 				    "devmap_devmem_remap()");
19629517SBill.Taylor@Sun.COM 				return (ibc_get_ci_failure(0));
19639517SBill.Taylor@Sun.COM 			}
19649517SBill.Taylor@Sun.COM 			qp->qp_umap_dhp = (devmap_cookie_t)NULL;
19659517SBill.Taylor@Sun.COM 		}
19669517SBill.Taylor@Sun.COM 	}
19679517SBill.Taylor@Sun.COM 
19689517SBill.Taylor@Sun.COM 
19699517SBill.Taylor@Sun.COM 	/*
19709517SBill.Taylor@Sun.COM 	 * Put NULL into the Hermon QPNum-to-QPHdl list.  This will allow any
19719517SBill.Taylor@Sun.COM 	 * in-progress events to detect that the QP corresponding to this
19729517SBill.Taylor@Sun.COM 	 * number has been freed.  Note: it does depend in whether we are
19739517SBill.Taylor@Sun.COM 	 * freeing a special QP or not.
19749517SBill.Taylor@Sun.COM 	 */
1975*12965SWilliam.Taylor@Oracle.COM 	if (qpc == NULL) {
1976*12965SWilliam.Taylor@Oracle.COM 		hermon_icm_set_num_to_hdl(state, HERMON_QPC,
1977*12965SWilliam.Taylor@Oracle.COM 		    qp->qp_qpnum, NULL);
1978*12965SWilliam.Taylor@Oracle.COM 	} else if (qp->qp_is_special) {
1979*12965SWilliam.Taylor@Oracle.COM 		hermon_icm_set_num_to_hdl(state, HERMON_QPC,
1980*12965SWilliam.Taylor@Oracle.COM 		    qpc->hr_indx + port, NULL);
19819517SBill.Taylor@Sun.COM 	} else {
1982*12965SWilliam.Taylor@Oracle.COM 		hermon_icm_set_num_to_hdl(state, HERMON_QPC,
1983*12965SWilliam.Taylor@Oracle.COM 		    qpc->hr_indx, NULL);
19849517SBill.Taylor@Sun.COM 	}
19859517SBill.Taylor@Sun.COM 
19869517SBill.Taylor@Sun.COM 	/*
19879517SBill.Taylor@Sun.COM 	 * Drop the QP lock
19889517SBill.Taylor@Sun.COM 	 *    At this point the lock is no longer necessary.  We cannot
19899517SBill.Taylor@Sun.COM 	 *    protect from multiple simultaneous calls to free the same QP.
19909517SBill.Taylor@Sun.COM 	 *    In addition, since the QP lock is contained in the QP "software
19919517SBill.Taylor@Sun.COM 	 *    handle" resource, which we will free (see below), it is
19929517SBill.Taylor@Sun.COM 	 *    important that we have no further references to that memory.
19939517SBill.Taylor@Sun.COM 	 */
19949517SBill.Taylor@Sun.COM 	mutex_exit(&qp->qp_lock);
19959517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp))
19969517SBill.Taylor@Sun.COM 
19979517SBill.Taylor@Sun.COM 	/*
19989517SBill.Taylor@Sun.COM 	 * Free the QP resources
19999517SBill.Taylor@Sun.COM 	 *    Start by deregistering and freeing the memory for work queues.
20009517SBill.Taylor@Sun.COM 	 *    Next free any previously allocated context information
20019517SBill.Taylor@Sun.COM 	 *    (depending on QP type)
20029517SBill.Taylor@Sun.COM 	 *    Finally, decrement the necessary reference counts.
20039517SBill.Taylor@Sun.COM 	 * If this fails for any reason, then it is an indication that
20049517SBill.Taylor@Sun.COM 	 * something (either in HW or SW) has gone seriously wrong.  So we
20059517SBill.Taylor@Sun.COM 	 * print a warning message and return.
20069517SBill.Taylor@Sun.COM 	 */
20079517SBill.Taylor@Sun.COM 	status = hermon_mr_deregister(state, &mr, HERMON_MR_DEREG_ALL,
20089517SBill.Taylor@Sun.COM 	    sleepflag);
20099517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
20109517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "failed to deregister QP memory");
20119517SBill.Taylor@Sun.COM 		status = ibc_get_ci_failure(0);
20129517SBill.Taylor@Sun.COM 		goto qpfree_fail;
20139517SBill.Taylor@Sun.COM 	}
20149517SBill.Taylor@Sun.COM 
20159517SBill.Taylor@Sun.COM 	/* Free the memory for the QP */
20169517SBill.Taylor@Sun.COM 	hermon_queue_free(&qp->qp_wqinfo);
20179517SBill.Taylor@Sun.COM 
20189517SBill.Taylor@Sun.COM 	if (qp->qp_sq_wqhdr)
20199517SBill.Taylor@Sun.COM 		hermon_wrid_wqhdr_destroy(qp->qp_sq_wqhdr);
20209517SBill.Taylor@Sun.COM 	if (qp->qp_rq_wqhdr)
20219517SBill.Taylor@Sun.COM 		hermon_wrid_wqhdr_destroy(qp->qp_rq_wqhdr);
20229517SBill.Taylor@Sun.COM 
20239517SBill.Taylor@Sun.COM 	/* Free the dbr */
20249517SBill.Taylor@Sun.COM 	if (!qp_srq_en) {
20259517SBill.Taylor@Sun.COM 		hermon_dbr_free(state, qp->qp_uarpg, qp->qp_rq_vdbr);
20269517SBill.Taylor@Sun.COM 	}
20279517SBill.Taylor@Sun.COM 
20289517SBill.Taylor@Sun.COM 	/*
20299517SBill.Taylor@Sun.COM 	 * Free up the remainder of the QP resources.  Note: we have a few
20309517SBill.Taylor@Sun.COM 	 * different resources to free up depending on whether the QP is a
20319517SBill.Taylor@Sun.COM 	 * special QP or not.  As described above, if any of these fail for
20329517SBill.Taylor@Sun.COM 	 * any reason it is an indication that something (either in HW or SW)
20339517SBill.Taylor@Sun.COM 	 * has gone seriously wrong.  So we print a warning message and
20349517SBill.Taylor@Sun.COM 	 * return.
20359517SBill.Taylor@Sun.COM 	 */
20369517SBill.Taylor@Sun.COM 	if (qp->qp_is_special) {
20379517SBill.Taylor@Sun.COM 		type = (qp->qp_is_special == HERMON_QP_SMI) ?
20389517SBill.Taylor@Sun.COM 		    IBT_SMI_SQP : IBT_GSI_SQP;
20399517SBill.Taylor@Sun.COM 
20409517SBill.Taylor@Sun.COM 		/* Free up resources for the special QP */
20419517SBill.Taylor@Sun.COM 		status = hermon_special_qp_rsrc_free(state, type, port);
20429517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
20439517SBill.Taylor@Sun.COM 			HERMON_WARNING(state, "failed to free special QP rsrc");
20449517SBill.Taylor@Sun.COM 			status = ibc_get_ci_failure(0);
20459517SBill.Taylor@Sun.COM 			goto qpfree_fail;
20469517SBill.Taylor@Sun.COM 		}
20479517SBill.Taylor@Sun.COM 
2048*12965SWilliam.Taylor@Oracle.COM 	} else if (qp->qp_rangep) {
2049*12965SWilliam.Taylor@Oracle.COM 		int refcnt;
2050*12965SWilliam.Taylor@Oracle.COM 		mutex_enter(&qp->qp_rangep->hqpr_lock);
2051*12965SWilliam.Taylor@Oracle.COM 		refcnt = --qp->qp_rangep->hqpr_refcnt;
2052*12965SWilliam.Taylor@Oracle.COM 		mutex_exit(&qp->qp_rangep->hqpr_lock);
2053*12965SWilliam.Taylor@Oracle.COM 		if (refcnt == 0) {
2054*12965SWilliam.Taylor@Oracle.COM 			mutex_destroy(&qp->qp_rangep->hqpr_lock);
2055*12965SWilliam.Taylor@Oracle.COM 			hermon_rsrc_free(state, &qp->qp_rangep->hqpr_qpcrsrc);
2056*12965SWilliam.Taylor@Oracle.COM 			kmem_free(qp->qp_rangep, sizeof (*qp->qp_rangep));
2057*12965SWilliam.Taylor@Oracle.COM 		}
2058*12965SWilliam.Taylor@Oracle.COM 		qp->qp_rangep = NULL;
2059*12965SWilliam.Taylor@Oracle.COM 	} else if (qp->qp_qpn_hdl == NULL) {
2060*12965SWilliam.Taylor@Oracle.COM 		hermon_rsrc_free(state, &qpc);
20619517SBill.Taylor@Sun.COM 	} else {
20629517SBill.Taylor@Sun.COM 		/*
20639517SBill.Taylor@Sun.COM 		 * Check the flags and determine whether to release the
20649517SBill.Taylor@Sun.COM 		 * QPN or not, based on their value.
20659517SBill.Taylor@Sun.COM 		 */
20669517SBill.Taylor@Sun.COM 		if (free_qp_flags == IBC_FREE_QP_ONLY) {
20679517SBill.Taylor@Sun.COM 			entry = qp->qp_qpn_hdl;
20689517SBill.Taylor@Sun.COM 			hermon_qp_release_qpn(state, qp->qp_qpn_hdl,
20699517SBill.Taylor@Sun.COM 			    HERMON_QPN_FREE_ONLY);
20709517SBill.Taylor@Sun.COM 			*qpnh = (ibc_qpn_hdl_t)entry;
20719517SBill.Taylor@Sun.COM 		} else {
20729517SBill.Taylor@Sun.COM 			hermon_qp_release_qpn(state, qp->qp_qpn_hdl,
20739517SBill.Taylor@Sun.COM 			    HERMON_QPN_RELEASE);
20749517SBill.Taylor@Sun.COM 		}
20759517SBill.Taylor@Sun.COM 	}
2076*12965SWilliam.Taylor@Oracle.COM 
20779517SBill.Taylor@Sun.COM 	mutex_destroy(&qp->qp_sq_lock);
20789517SBill.Taylor@Sun.COM 
20799517SBill.Taylor@Sun.COM 	/* Free the Hermon Queue Pair handle */
20809517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
20819517SBill.Taylor@Sun.COM 
20829517SBill.Taylor@Sun.COM 	/* Decrement the reference counts on CQs, PD and SRQ (if needed) */
20839517SBill.Taylor@Sun.COM 	hermon_cq_refcnt_dec(rq_cq);
20849517SBill.Taylor@Sun.COM 	hermon_cq_refcnt_dec(sq_cq);
20859517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
20869517SBill.Taylor@Sun.COM 	if (qp_srq_en == HERMON_QP_SRQ_ENABLED) {
20879517SBill.Taylor@Sun.COM 		hermon_srq_refcnt_dec(srq);
20889517SBill.Taylor@Sun.COM 	}
20899517SBill.Taylor@Sun.COM 
20909517SBill.Taylor@Sun.COM 	/* Set the qphdl pointer to NULL and return success */
20919517SBill.Taylor@Sun.COM 	*qphdl = NULL;
20929517SBill.Taylor@Sun.COM 
20939517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
20949517SBill.Taylor@Sun.COM 
20959517SBill.Taylor@Sun.COM qpfree_fail:
20969517SBill.Taylor@Sun.COM 	return (status);
20979517SBill.Taylor@Sun.COM }
20989517SBill.Taylor@Sun.COM 
20999517SBill.Taylor@Sun.COM 
21009517SBill.Taylor@Sun.COM /*
21019517SBill.Taylor@Sun.COM  * hermon_qp_query()
21029517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
21039517SBill.Taylor@Sun.COM  */
21049517SBill.Taylor@Sun.COM int
hermon_qp_query(hermon_state_t * state,hermon_qphdl_t qp,ibt_qp_query_attr_t * attr_p)21059517SBill.Taylor@Sun.COM hermon_qp_query(hermon_state_t *state, hermon_qphdl_t qp,
21069517SBill.Taylor@Sun.COM     ibt_qp_query_attr_t *attr_p)
21079517SBill.Taylor@Sun.COM {
21089517SBill.Taylor@Sun.COM 	ibt_cep_state_t		qp_state;
21099517SBill.Taylor@Sun.COM 	ibt_qp_ud_attr_t	*ud;
21109517SBill.Taylor@Sun.COM 	ibt_qp_rc_attr_t	*rc;
21119517SBill.Taylor@Sun.COM 	ibt_qp_uc_attr_t	*uc;
21129517SBill.Taylor@Sun.COM 	ibt_cep_flags_t		enable_flags;
21139517SBill.Taylor@Sun.COM 	hermon_hw_addr_path_t	*qpc_path, *qpc_alt_path;
21149517SBill.Taylor@Sun.COM 	ibt_cep_path_t		*path_ptr, *alt_path_ptr;
21159517SBill.Taylor@Sun.COM 	hermon_hw_qpc_t		*qpc;
21169517SBill.Taylor@Sun.COM 	int			status;
21179517SBill.Taylor@Sun.COM 	uint_t			tmp_sched_q, tmp_alt_sched_q;
21189517SBill.Taylor@Sun.COM 
21199517SBill.Taylor@Sun.COM 	mutex_enter(&qp->qp_lock);
21209517SBill.Taylor@Sun.COM 
21219517SBill.Taylor@Sun.COM 	/*
21229517SBill.Taylor@Sun.COM 	 * Grab the temporary QPC entry from QP software state
21239517SBill.Taylor@Sun.COM 	 */
21249517SBill.Taylor@Sun.COM 	qpc = &qp->qpc;
21259517SBill.Taylor@Sun.COM 
21269517SBill.Taylor@Sun.COM 	/* Convert the current Hermon QP state to IBTF QP state */
21279517SBill.Taylor@Sun.COM 	switch (qp->qp_state) {
21289517SBill.Taylor@Sun.COM 	case HERMON_QP_RESET:
21299517SBill.Taylor@Sun.COM 		qp_state = IBT_STATE_RESET;		/* "Reset" */
21309517SBill.Taylor@Sun.COM 		break;
21319517SBill.Taylor@Sun.COM 	case HERMON_QP_INIT:
21329517SBill.Taylor@Sun.COM 		qp_state = IBT_STATE_INIT;		/* Initialized */
21339517SBill.Taylor@Sun.COM 		break;
21349517SBill.Taylor@Sun.COM 	case HERMON_QP_RTR:
21359517SBill.Taylor@Sun.COM 		qp_state = IBT_STATE_RTR;		/* Ready to Receive */
21369517SBill.Taylor@Sun.COM 		break;
21379517SBill.Taylor@Sun.COM 	case HERMON_QP_RTS:
21389517SBill.Taylor@Sun.COM 		qp_state = IBT_STATE_RTS;		/* Ready to Send */
21399517SBill.Taylor@Sun.COM 		break;
21409517SBill.Taylor@Sun.COM 	case HERMON_QP_SQERR:
21419517SBill.Taylor@Sun.COM 		qp_state = IBT_STATE_SQE;		/* Send Queue Error */
21429517SBill.Taylor@Sun.COM 		break;
21439517SBill.Taylor@Sun.COM 	case HERMON_QP_SQD:
21449517SBill.Taylor@Sun.COM 		if (qp->qp_sqd_still_draining) {
21459517SBill.Taylor@Sun.COM 			qp_state = IBT_STATE_SQDRAIN;	/* SQ Draining */
21469517SBill.Taylor@Sun.COM 		} else {
21479517SBill.Taylor@Sun.COM 			qp_state = IBT_STATE_SQD;	/* SQ Drained */
21489517SBill.Taylor@Sun.COM 		}
21499517SBill.Taylor@Sun.COM 		break;
21509517SBill.Taylor@Sun.COM 	case HERMON_QP_ERR:
21519517SBill.Taylor@Sun.COM 		qp_state = IBT_STATE_ERROR;		/* Error */
21529517SBill.Taylor@Sun.COM 		break;
21539517SBill.Taylor@Sun.COM 	default:
21549517SBill.Taylor@Sun.COM 		mutex_exit(&qp->qp_lock);
21559517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
21569517SBill.Taylor@Sun.COM 	}
21579517SBill.Taylor@Sun.COM 	attr_p->qp_info.qp_state = qp_state;
21589517SBill.Taylor@Sun.COM 
21599517SBill.Taylor@Sun.COM 	/* SRQ Hook. */
21609517SBill.Taylor@Sun.COM 	attr_p->qp_srq = NULL;
21619517SBill.Taylor@Sun.COM 
21629517SBill.Taylor@Sun.COM 	/*
21639517SBill.Taylor@Sun.COM 	 * The following QP information is always returned, regardless of
21649517SBill.Taylor@Sun.COM 	 * the current QP state.  Note: Some special handling is necessary
21659517SBill.Taylor@Sun.COM 	 * for calculating the QP number on special QP (QP0 and QP1).
21669517SBill.Taylor@Sun.COM 	 */
2167*12965SWilliam.Taylor@Oracle.COM 	attr_p->qp_sq_cq    =
2168*12965SWilliam.Taylor@Oracle.COM 	    (qp->qp_sq_cqhdl == NULL) ? NULL : qp->qp_sq_cqhdl->cq_hdlrarg;
2169*12965SWilliam.Taylor@Oracle.COM 	attr_p->qp_rq_cq    =
2170*12965SWilliam.Taylor@Oracle.COM 	    (qp->qp_rq_cqhdl == NULL) ? NULL : qp->qp_rq_cqhdl->cq_hdlrarg;
21719517SBill.Taylor@Sun.COM 	if (qp->qp_is_special) {
21729517SBill.Taylor@Sun.COM 		attr_p->qp_qpn = (qp->qp_is_special == HERMON_QP_SMI) ? 0 : 1;
21739517SBill.Taylor@Sun.COM 	} else {
21749517SBill.Taylor@Sun.COM 		attr_p->qp_qpn = (ib_qpn_t)qp->qp_qpnum;
21759517SBill.Taylor@Sun.COM 	}
21769517SBill.Taylor@Sun.COM 	attr_p->qp_sq_sgl   = qp->qp_sq_sgl;
21779517SBill.Taylor@Sun.COM 	attr_p->qp_rq_sgl   = qp->qp_rq_sgl;
21789517SBill.Taylor@Sun.COM 	attr_p->qp_info.qp_sq_sz = qp->qp_sq_bufsz - qp->qp_sq_hdrmwqes;
21799517SBill.Taylor@Sun.COM 	attr_p->qp_info.qp_rq_sz = qp->qp_rq_bufsz;
21809517SBill.Taylor@Sun.COM 
21819517SBill.Taylor@Sun.COM 	/*
21829517SBill.Taylor@Sun.COM 	 * If QP is currently in the "Reset" state, then only the above are
21839517SBill.Taylor@Sun.COM 	 * returned
21849517SBill.Taylor@Sun.COM 	 */
21859517SBill.Taylor@Sun.COM 	if (qp_state == IBT_STATE_RESET) {
21869517SBill.Taylor@Sun.COM 		mutex_exit(&qp->qp_lock);
21879517SBill.Taylor@Sun.COM 		return (DDI_SUCCESS);
21889517SBill.Taylor@Sun.COM 	}
21899517SBill.Taylor@Sun.COM 
21909517SBill.Taylor@Sun.COM 	/*
21919517SBill.Taylor@Sun.COM 	 * Post QUERY_QP command to firmware
21929517SBill.Taylor@Sun.COM 	 *
21939517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are holding the "qp_lock".
21949517SBill.Taylor@Sun.COM 	 * Since we may be in the interrupt context (or subsequently raised
21959517SBill.Taylor@Sun.COM 	 * to interrupt level by priority inversion), we do not want to block
21969517SBill.Taylor@Sun.COM 	 * in this routine waiting for success.
21979517SBill.Taylor@Sun.COM 	 */
21989517SBill.Taylor@Sun.COM 	tmp_sched_q = qpc->pri_addr_path.sched_q;
21999517SBill.Taylor@Sun.COM 	tmp_alt_sched_q = qpc->alt_addr_path.sched_q;
22009517SBill.Taylor@Sun.COM 	status = hermon_cmn_query_cmd_post(state, QUERY_QP, 0, qp->qp_qpnum,
22019517SBill.Taylor@Sun.COM 	    qpc, sizeof (hermon_hw_qpc_t), HERMON_CMD_NOSLEEP_SPIN);
22029517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
22039517SBill.Taylor@Sun.COM 		mutex_exit(&qp->qp_lock);
22049517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN, "hermon%d: hermon_qp_query: QUERY_QP "
22059517SBill.Taylor@Sun.COM 		    "command failed: %08x\n", state->hs_instance, status);
22069517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
22079517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
22089517SBill.Taylor@Sun.COM 		}
22099517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
22109517SBill.Taylor@Sun.COM 	}
22119517SBill.Taylor@Sun.COM 	qpc->pri_addr_path.sched_q = tmp_sched_q;
22129517SBill.Taylor@Sun.COM 	qpc->alt_addr_path.sched_q = tmp_alt_sched_q;
22139517SBill.Taylor@Sun.COM 
22149517SBill.Taylor@Sun.COM 	/*
22159517SBill.Taylor@Sun.COM 	 * Fill in the additional QP info based on the QP's transport type.
22169517SBill.Taylor@Sun.COM 	 */
2217*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_type == IBT_UD_RQP) {
22189517SBill.Taylor@Sun.COM 
22199517SBill.Taylor@Sun.COM 		/* Fill in the UD-specific info */
22209517SBill.Taylor@Sun.COM 		ud = &attr_p->qp_info.qp_transport.ud;
22219517SBill.Taylor@Sun.COM 		ud->ud_qkey	= (ib_qkey_t)qpc->qkey;
22229517SBill.Taylor@Sun.COM 		ud->ud_sq_psn	= qpc->next_snd_psn;
22239517SBill.Taylor@Sun.COM 		ud->ud_pkey_ix	= qpc->pri_addr_path.pkey_indx;
22249517SBill.Taylor@Sun.COM 		/* port+1 for port 1/2 */
22259517SBill.Taylor@Sun.COM 		ud->ud_port	=
22269517SBill.Taylor@Sun.COM 		    (uint8_t)(((qpc->pri_addr_path.sched_q >> 6) & 0x01) + 1);
22279517SBill.Taylor@Sun.COM 
22289517SBill.Taylor@Sun.COM 		attr_p->qp_info.qp_trans = IBT_UD_SRV;
22299517SBill.Taylor@Sun.COM 
2230*12965SWilliam.Taylor@Oracle.COM 		if (qp->qp_serv_type == HERMON_QP_FEXCH) {
2231*12965SWilliam.Taylor@Oracle.COM 			ibt_pmr_desc_t *pmr;
2232*12965SWilliam.Taylor@Oracle.COM 			uint64_t heart_beat;
2233*12965SWilliam.Taylor@Oracle.COM 
2234*12965SWilliam.Taylor@Oracle.COM 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pmr))
2235*12965SWilliam.Taylor@Oracle.COM 			pmr = &attr_p->qp_query_fexch.fq_uni_mem_desc;
2236*12965SWilliam.Taylor@Oracle.COM 			pmr->pmd_iova = 0;
2237*12965SWilliam.Taylor@Oracle.COM 			pmr->pmd_lkey = pmr->pmd_rkey =
2238*12965SWilliam.Taylor@Oracle.COM 			    hermon_fcoib_qpn_to_mkey(state, qp->qp_qpnum);
2239*12965SWilliam.Taylor@Oracle.COM 			pmr->pmd_phys_buf_list_sz =
2240*12965SWilliam.Taylor@Oracle.COM 			    state->hs_fcoib.hfc_mtts_per_mpt;
2241*12965SWilliam.Taylor@Oracle.COM 			pmr->pmd_sync_required = 0;
2242*12965SWilliam.Taylor@Oracle.COM 
2243*12965SWilliam.Taylor@Oracle.COM 			pmr = &attr_p->qp_query_fexch.fq_bi_mem_desc;
2244*12965SWilliam.Taylor@Oracle.COM 			pmr->pmd_iova = 0;
2245*12965SWilliam.Taylor@Oracle.COM 			pmr->pmd_lkey = 0;
2246*12965SWilliam.Taylor@Oracle.COM 			pmr->pmd_rkey = 0;
2247*12965SWilliam.Taylor@Oracle.COM 			pmr->pmd_phys_buf_list_sz = 0;
2248*12965SWilliam.Taylor@Oracle.COM 			pmr->pmd_sync_required = 0;
2249*12965SWilliam.Taylor@Oracle.COM 
2250*12965SWilliam.Taylor@Oracle.COM 			attr_p->qp_query_fexch.fq_flags =
2251*12965SWilliam.Taylor@Oracle.COM 			    ((hermon_get_heart_beat_rq_cmd_post(state,
2252*12965SWilliam.Taylor@Oracle.COM 			    qp->qp_qpnum, &heart_beat) == HERMON_CMD_SUCCESS) &&
2253*12965SWilliam.Taylor@Oracle.COM 			    (heart_beat == 0)) ? IBT_FEXCH_HEART_BEAT_OK :
2254*12965SWilliam.Taylor@Oracle.COM 			    IBT_FEXCH_NO_FLAGS;
2255*12965SWilliam.Taylor@Oracle.COM 
2256*12965SWilliam.Taylor@Oracle.COM 			ud->ud_fc = qp->qp_fc_attr;
2257*12965SWilliam.Taylor@Oracle.COM 		} else if (qp->qp_serv_type == HERMON_QP_FCMND ||
2258*12965SWilliam.Taylor@Oracle.COM 		    qp->qp_serv_type == HERMON_QP_RFCI) {
2259*12965SWilliam.Taylor@Oracle.COM 			ud->ud_fc = qp->qp_fc_attr;
2260*12965SWilliam.Taylor@Oracle.COM 		}
2261*12965SWilliam.Taylor@Oracle.COM 
22629517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
22639517SBill.Taylor@Sun.COM 
22649517SBill.Taylor@Sun.COM 		/* Fill in the RC-specific info */
22659517SBill.Taylor@Sun.COM 		rc = &attr_p->qp_info.qp_transport.rc;
22669517SBill.Taylor@Sun.COM 		rc->rc_sq_psn	= qpc->next_snd_psn;
22679517SBill.Taylor@Sun.COM 		rc->rc_rq_psn	= qpc->next_rcv_psn;
22689517SBill.Taylor@Sun.COM 		rc->rc_dst_qpn	= qpc->rem_qpn;
22699517SBill.Taylor@Sun.COM 
22709517SBill.Taylor@Sun.COM 		/* Grab the path migration state information */
22719517SBill.Taylor@Sun.COM 		if (qpc->pm_state == HERMON_QP_PMSTATE_MIGRATED) {
22729517SBill.Taylor@Sun.COM 			rc->rc_mig_state = IBT_STATE_MIGRATED;
22739517SBill.Taylor@Sun.COM 		} else if (qpc->pm_state == HERMON_QP_PMSTATE_REARM) {
22749517SBill.Taylor@Sun.COM 			rc->rc_mig_state = IBT_STATE_REARMED;
22759517SBill.Taylor@Sun.COM 		} else {
22769517SBill.Taylor@Sun.COM 			rc->rc_mig_state = IBT_STATE_ARMED;
22779517SBill.Taylor@Sun.COM 		}
22789517SBill.Taylor@Sun.COM 		rc->rc_rdma_ra_out = (1 << qpc->sra_max);
22799517SBill.Taylor@Sun.COM 		rc->rc_rdma_ra_in  = (1 << qpc->rra_max);
22809517SBill.Taylor@Sun.COM 		rc->rc_min_rnr_nak = qpc->min_rnr_nak;
22819517SBill.Taylor@Sun.COM 		rc->rc_path_mtu	   = qpc->mtu;
22829517SBill.Taylor@Sun.COM 		rc->rc_retry_cnt   = qpc->retry_cnt;
22839517SBill.Taylor@Sun.COM 
22849517SBill.Taylor@Sun.COM 		/* Get the common primary address path fields */
22859517SBill.Taylor@Sun.COM 		qpc_path = &qpc->pri_addr_path;
22869517SBill.Taylor@Sun.COM 		path_ptr = &rc->rc_path;
22879517SBill.Taylor@Sun.COM 		hermon_get_addr_path(state, qpc_path, &path_ptr->cep_adds_vect,
22889517SBill.Taylor@Sun.COM 		    HERMON_ADDRPATH_QP);
22899517SBill.Taylor@Sun.COM 
22909517SBill.Taylor@Sun.COM 		/* Fill in the additional primary address path fields */
22919517SBill.Taylor@Sun.COM 		path_ptr->cep_pkey_ix	   = qpc_path->pkey_indx;
22929517SBill.Taylor@Sun.COM 		path_ptr->cep_hca_port_num =
22939517SBill.Taylor@Sun.COM 		    path_ptr->cep_adds_vect.av_port_num =
22949517SBill.Taylor@Sun.COM 		    (uint8_t)(((qpc_path->sched_q >> 6) & 0x01) + 1);
22959517SBill.Taylor@Sun.COM 		path_ptr->cep_timeout	   = qpc_path->ack_timeout;
22969517SBill.Taylor@Sun.COM 
22979517SBill.Taylor@Sun.COM 		/* Get the common alternate address path fields */
22989517SBill.Taylor@Sun.COM 		qpc_alt_path = &qpc->alt_addr_path;
22999517SBill.Taylor@Sun.COM 		alt_path_ptr = &rc->rc_alt_path;
23009517SBill.Taylor@Sun.COM 		hermon_get_addr_path(state, qpc_alt_path,
23019517SBill.Taylor@Sun.COM 		    &alt_path_ptr->cep_adds_vect, HERMON_ADDRPATH_QP);
23029517SBill.Taylor@Sun.COM 
23039517SBill.Taylor@Sun.COM 		/* Fill in the additional alternate address path fields */
23049517SBill.Taylor@Sun.COM 		alt_path_ptr->cep_pkey_ix	= qpc_alt_path->pkey_indx;
23059517SBill.Taylor@Sun.COM 		alt_path_ptr->cep_hca_port_num	=
23069517SBill.Taylor@Sun.COM 		    alt_path_ptr->cep_adds_vect.av_port_num =
23079517SBill.Taylor@Sun.COM 		    (uint8_t)(((qpc_alt_path->sched_q >> 6) & 0x01) + 1);
23089517SBill.Taylor@Sun.COM 		alt_path_ptr->cep_timeout	= qpc_alt_path->ack_timeout;
23099517SBill.Taylor@Sun.COM 
23109517SBill.Taylor@Sun.COM 		/* Get the RNR retry time from primary path */
23119517SBill.Taylor@Sun.COM 		rc->rc_rnr_retry_cnt = qpc->rnr_retry;
23129517SBill.Taylor@Sun.COM 
23139517SBill.Taylor@Sun.COM 		/* Set the enable flags based on RDMA/Atomic enable bits */
23149517SBill.Taylor@Sun.COM 		enable_flags = IBT_CEP_NO_FLAGS;
23159517SBill.Taylor@Sun.COM 		enable_flags |= ((qpc->rre == 0) ? 0 : IBT_CEP_RDMA_RD);
23169517SBill.Taylor@Sun.COM 		enable_flags |= ((qpc->rwe == 0) ? 0 : IBT_CEP_RDMA_WR);
23179517SBill.Taylor@Sun.COM 		enable_flags |= ((qpc->rae == 0) ? 0 : IBT_CEP_ATOMIC);
23189517SBill.Taylor@Sun.COM 		attr_p->qp_info.qp_flags = enable_flags;
23199517SBill.Taylor@Sun.COM 
23209517SBill.Taylor@Sun.COM 		attr_p->qp_info.qp_trans = IBT_RC_SRV;
23219517SBill.Taylor@Sun.COM 
23229517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
23239517SBill.Taylor@Sun.COM 
23249517SBill.Taylor@Sun.COM 		/* Fill in the UC-specific info */
23259517SBill.Taylor@Sun.COM 		uc = &attr_p->qp_info.qp_transport.uc;
23269517SBill.Taylor@Sun.COM 		uc->uc_sq_psn	= qpc->next_snd_psn;
23279517SBill.Taylor@Sun.COM 		uc->uc_rq_psn	= qpc->next_rcv_psn;
23289517SBill.Taylor@Sun.COM 		uc->uc_dst_qpn	= qpc->rem_qpn;
23299517SBill.Taylor@Sun.COM 
23309517SBill.Taylor@Sun.COM 		/* Grab the path migration state information */
23319517SBill.Taylor@Sun.COM 		if (qpc->pm_state == HERMON_QP_PMSTATE_MIGRATED) {
23329517SBill.Taylor@Sun.COM 			uc->uc_mig_state = IBT_STATE_MIGRATED;
23339517SBill.Taylor@Sun.COM 		} else if (qpc->pm_state == HERMON_QP_PMSTATE_REARM) {
23349517SBill.Taylor@Sun.COM 			uc->uc_mig_state = IBT_STATE_REARMED;
23359517SBill.Taylor@Sun.COM 		} else {
23369517SBill.Taylor@Sun.COM 			uc->uc_mig_state = IBT_STATE_ARMED;
23379517SBill.Taylor@Sun.COM 		}
23389517SBill.Taylor@Sun.COM 		uc->uc_path_mtu = qpc->mtu;
23399517SBill.Taylor@Sun.COM 
23409517SBill.Taylor@Sun.COM 		/* Get the common primary address path fields */
23419517SBill.Taylor@Sun.COM 		qpc_path = &qpc->pri_addr_path;
23429517SBill.Taylor@Sun.COM 		path_ptr = &uc->uc_path;
23439517SBill.Taylor@Sun.COM 		hermon_get_addr_path(state, qpc_path, &path_ptr->cep_adds_vect,
23449517SBill.Taylor@Sun.COM 		    HERMON_ADDRPATH_QP);
23459517SBill.Taylor@Sun.COM 
23469517SBill.Taylor@Sun.COM 		/* Fill in the additional primary address path fields */
23479517SBill.Taylor@Sun.COM 		path_ptr->cep_pkey_ix	   = qpc_path->pkey_indx;
23489517SBill.Taylor@Sun.COM 		path_ptr->cep_hca_port_num =
23499517SBill.Taylor@Sun.COM 		    path_ptr->cep_adds_vect.av_port_num =
23509517SBill.Taylor@Sun.COM 		    (uint8_t)(((qpc_path->sched_q >> 6) & 0x01) + 1);
23519517SBill.Taylor@Sun.COM 
23529517SBill.Taylor@Sun.COM 		/* Get the common alternate address path fields */
23539517SBill.Taylor@Sun.COM 		qpc_alt_path = &qpc->alt_addr_path;
23549517SBill.Taylor@Sun.COM 		alt_path_ptr = &uc->uc_alt_path;
23559517SBill.Taylor@Sun.COM 		hermon_get_addr_path(state, qpc_alt_path,
23569517SBill.Taylor@Sun.COM 		    &alt_path_ptr->cep_adds_vect, HERMON_ADDRPATH_QP);
23579517SBill.Taylor@Sun.COM 
23589517SBill.Taylor@Sun.COM 		/* Fill in the additional alternate address path fields */
23599517SBill.Taylor@Sun.COM 		alt_path_ptr->cep_pkey_ix	= qpc_alt_path->pkey_indx;
23609517SBill.Taylor@Sun.COM 		alt_path_ptr->cep_hca_port_num	=
23619517SBill.Taylor@Sun.COM 		    alt_path_ptr->cep_adds_vect.av_port_num =
23629517SBill.Taylor@Sun.COM 		    (uint8_t)(((qpc_alt_path->sched_q >> 6) & 0x01) + 1);
23639517SBill.Taylor@Sun.COM 
23649517SBill.Taylor@Sun.COM 		/*
23659517SBill.Taylor@Sun.COM 		 * Set the enable flags based on RDMA enable bits (by
23669517SBill.Taylor@Sun.COM 		 * definition UC doesn't support Atomic or RDMA Read)
23679517SBill.Taylor@Sun.COM 		 */
23689517SBill.Taylor@Sun.COM 		enable_flags = ((qpc->rwe == 0) ? 0 : IBT_CEP_RDMA_WR);
23699517SBill.Taylor@Sun.COM 		attr_p->qp_info.qp_flags = enable_flags;
23709517SBill.Taylor@Sun.COM 
23719517SBill.Taylor@Sun.COM 		attr_p->qp_info.qp_trans = IBT_UC_SRV;
23729517SBill.Taylor@Sun.COM 
23739517SBill.Taylor@Sun.COM 	} else {
23749517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unexpected QP transport type");
23759517SBill.Taylor@Sun.COM 		mutex_exit(&qp->qp_lock);
23769517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
23779517SBill.Taylor@Sun.COM 	}
23789517SBill.Taylor@Sun.COM 
23799517SBill.Taylor@Sun.COM 	/*
23809517SBill.Taylor@Sun.COM 	 * Under certain circumstances it is possible for the Hermon hardware
23819517SBill.Taylor@Sun.COM 	 * to transition to one of the error states without software directly
23829517SBill.Taylor@Sun.COM 	 * knowing about it.  The QueryQP() call is the one place where we
23839517SBill.Taylor@Sun.COM 	 * have an opportunity to sample and update our view of the QP state.
23849517SBill.Taylor@Sun.COM 	 */
23859517SBill.Taylor@Sun.COM 	if (qpc->state == HERMON_QP_SQERR) {
23869517SBill.Taylor@Sun.COM 		attr_p->qp_info.qp_state = IBT_STATE_SQE;
23879517SBill.Taylor@Sun.COM 		qp->qp_state = HERMON_QP_SQERR;
2388*12965SWilliam.Taylor@Oracle.COM 		HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQERR);
23899517SBill.Taylor@Sun.COM 	}
23909517SBill.Taylor@Sun.COM 	if (qpc->state == HERMON_QP_ERR) {
23919517SBill.Taylor@Sun.COM 		attr_p->qp_info.qp_state = IBT_STATE_ERROR;
23929517SBill.Taylor@Sun.COM 		qp->qp_state = HERMON_QP_ERR;
2393*12965SWilliam.Taylor@Oracle.COM 		HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
23949517SBill.Taylor@Sun.COM 	}
23959517SBill.Taylor@Sun.COM 	mutex_exit(&qp->qp_lock);
23969517SBill.Taylor@Sun.COM 
23979517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
23989517SBill.Taylor@Sun.COM }
23999517SBill.Taylor@Sun.COM 
24009517SBill.Taylor@Sun.COM 
24019517SBill.Taylor@Sun.COM /*
24029517SBill.Taylor@Sun.COM  * hermon_qp_create_qpn()
24039517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
24049517SBill.Taylor@Sun.COM  */
24059517SBill.Taylor@Sun.COM static int
hermon_qp_create_qpn(hermon_state_t * state,hermon_qphdl_t qp,hermon_rsrc_t * qpc)24069517SBill.Taylor@Sun.COM hermon_qp_create_qpn(hermon_state_t *state, hermon_qphdl_t qp,
24079517SBill.Taylor@Sun.COM     hermon_rsrc_t *qpc)
24089517SBill.Taylor@Sun.COM {
24099517SBill.Taylor@Sun.COM 	hermon_qpn_entry_t	query;
24109517SBill.Taylor@Sun.COM 	hermon_qpn_entry_t	*entry;
24119517SBill.Taylor@Sun.COM 	avl_index_t		where;
24129517SBill.Taylor@Sun.COM 
24139517SBill.Taylor@Sun.COM 	/*
24149517SBill.Taylor@Sun.COM 	 * Build a query (for the AVL tree lookup) and attempt to find
24159517SBill.Taylor@Sun.COM 	 * a previously added entry that has a matching QPC index.  If
24169517SBill.Taylor@Sun.COM 	 * no matching entry is found, then allocate, initialize, and
24179517SBill.Taylor@Sun.COM 	 * add an entry to the AVL tree.
24189517SBill.Taylor@Sun.COM 	 * If a matching entry is found, then increment its QPN counter
24199517SBill.Taylor@Sun.COM 	 * and reference counter.
24209517SBill.Taylor@Sun.COM 	 */
24219517SBill.Taylor@Sun.COM 	query.qpn_indx = qpc->hr_indx;
24229517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_qpn_avl_lock);
24239517SBill.Taylor@Sun.COM 	entry = (hermon_qpn_entry_t *)avl_find(&state->hs_qpn_avl,
24249517SBill.Taylor@Sun.COM 	    &query, &where);
24259517SBill.Taylor@Sun.COM 	if (entry == NULL) {
24269517SBill.Taylor@Sun.COM 		/*
24279517SBill.Taylor@Sun.COM 		 * Allocate and initialize a QPN entry, then insert
24289517SBill.Taylor@Sun.COM 		 * it into the AVL tree.
24299517SBill.Taylor@Sun.COM 		 */
24309517SBill.Taylor@Sun.COM 		entry = (hermon_qpn_entry_t *)kmem_zalloc(
24319517SBill.Taylor@Sun.COM 		    sizeof (hermon_qpn_entry_t), KM_NOSLEEP);
24329517SBill.Taylor@Sun.COM 		if (entry == NULL) {
24339517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_qpn_avl_lock);
24349517SBill.Taylor@Sun.COM 			return (DDI_FAILURE);
24359517SBill.Taylor@Sun.COM 		}
24369517SBill.Taylor@Sun.COM 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*entry))
24379517SBill.Taylor@Sun.COM 
24389517SBill.Taylor@Sun.COM 		entry->qpn_indx	   = qpc->hr_indx;
24399517SBill.Taylor@Sun.COM 		entry->qpn_refcnt  = 0;
24409517SBill.Taylor@Sun.COM 		entry->qpn_counter = 0;
24419517SBill.Taylor@Sun.COM 
24429517SBill.Taylor@Sun.COM 		avl_insert(&state->hs_qpn_avl, entry, where);
24439517SBill.Taylor@Sun.COM 	}
24449517SBill.Taylor@Sun.COM 
24459517SBill.Taylor@Sun.COM 	/*
24469517SBill.Taylor@Sun.COM 	 * Make the AVL tree entry point to the QP context resource that
24479517SBill.Taylor@Sun.COM 	 * it will be responsible for tracking
24489517SBill.Taylor@Sun.COM 	 */
24499517SBill.Taylor@Sun.COM 	entry->qpn_qpc = qpc;
24509517SBill.Taylor@Sun.COM 
24519517SBill.Taylor@Sun.COM 	/*
24529517SBill.Taylor@Sun.COM 	 * Setup the QP handle to point to the AVL tree entry.  Then
24539517SBill.Taylor@Sun.COM 	 * generate the new QP number from the entry's QPN counter value
24549517SBill.Taylor@Sun.COM 	 * and the hardware's QP context table index.
24559517SBill.Taylor@Sun.COM 	 */
24569517SBill.Taylor@Sun.COM 	qp->qp_qpn_hdl	= entry;
24579517SBill.Taylor@Sun.COM 	qp->qp_qpnum	= ((entry->qpn_counter <<
24589517SBill.Taylor@Sun.COM 	    state->hs_cfg_profile->cp_log_num_qp) | qpc->hr_indx) &
24599517SBill.Taylor@Sun.COM 	    HERMON_QP_MAXNUMBER_MSK;
24609517SBill.Taylor@Sun.COM 	qp->qp_ring = qp->qp_qpnum << 8;
24619517SBill.Taylor@Sun.COM 
24629517SBill.Taylor@Sun.COM 	/*
24639517SBill.Taylor@Sun.COM 	 * Increment the reference counter and QPN counter.  The QPN
24649517SBill.Taylor@Sun.COM 	 * counter always indicates the next available number for use.
24659517SBill.Taylor@Sun.COM 	 */
24669517SBill.Taylor@Sun.COM 	entry->qpn_counter++;
24679517SBill.Taylor@Sun.COM 	entry->qpn_refcnt++;
24689517SBill.Taylor@Sun.COM 
24699517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_qpn_avl_lock);
24709517SBill.Taylor@Sun.COM 
24719517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
24729517SBill.Taylor@Sun.COM }
24739517SBill.Taylor@Sun.COM 
24749517SBill.Taylor@Sun.COM 
24759517SBill.Taylor@Sun.COM /*
24769517SBill.Taylor@Sun.COM  * hermon_qp_release_qpn()
24779517SBill.Taylor@Sun.COM  *    Context: Can be called only from user or kernel context.
24789517SBill.Taylor@Sun.COM  */
24799517SBill.Taylor@Sun.COM void
hermon_qp_release_qpn(hermon_state_t * state,hermon_qpn_entry_t * entry,int flags)24809517SBill.Taylor@Sun.COM hermon_qp_release_qpn(hermon_state_t *state, hermon_qpn_entry_t *entry,
24819517SBill.Taylor@Sun.COM     int flags)
24829517SBill.Taylor@Sun.COM {
24839517SBill.Taylor@Sun.COM 	ASSERT(entry != NULL);
24849517SBill.Taylor@Sun.COM 
24859517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_qpn_avl_lock);
24869517SBill.Taylor@Sun.COM 
24879517SBill.Taylor@Sun.COM 	/*
24889517SBill.Taylor@Sun.COM 	 * If we are releasing the QP number here, then we decrement the
24899517SBill.Taylor@Sun.COM 	 * reference count and check for zero references.  If there are
24909517SBill.Taylor@Sun.COM 	 * zero references, then we free the QPC context (if it hadn't
24919517SBill.Taylor@Sun.COM 	 * already been freed during a HERMON_QPN_FREE_ONLY free, i.e. for
24929517SBill.Taylor@Sun.COM 	 * reuse with another similar QP number) and remove the tracking
24939517SBill.Taylor@Sun.COM 	 * structure from the QP number AVL tree and free the structure.
24949517SBill.Taylor@Sun.COM 	 * If we are not releasing the QP number here, then, as long as we
24959517SBill.Taylor@Sun.COM 	 * have not exhausted the usefulness of the QPC context (that is,
24969517SBill.Taylor@Sun.COM 	 * re-used it too many times without the reference count having
24979517SBill.Taylor@Sun.COM 	 * gone to zero), we free up the QPC context for use by another
24989517SBill.Taylor@Sun.COM 	 * thread (which will use it to construct a different QP number
24999517SBill.Taylor@Sun.COM 	 * from the same QPC table index).
25009517SBill.Taylor@Sun.COM 	 */
25019517SBill.Taylor@Sun.COM 	if (flags == HERMON_QPN_RELEASE) {
25029517SBill.Taylor@Sun.COM 		entry->qpn_refcnt--;
25039517SBill.Taylor@Sun.COM 
25049517SBill.Taylor@Sun.COM 		/*
25059517SBill.Taylor@Sun.COM 		 * If the reference count is zero, then we free the QPC
25069517SBill.Taylor@Sun.COM 		 * context (if it hadn't already been freed in an early
25079517SBill.Taylor@Sun.COM 		 * step, e.g. HERMON_QPN_FREE_ONLY) and remove/free the
25089517SBill.Taylor@Sun.COM 		 * tracking structure from the QP number AVL tree.
25099517SBill.Taylor@Sun.COM 		 */
25109517SBill.Taylor@Sun.COM 		if (entry->qpn_refcnt == 0) {
25119517SBill.Taylor@Sun.COM 			if (entry->qpn_qpc != NULL) {
25129517SBill.Taylor@Sun.COM 				hermon_rsrc_free(state, &entry->qpn_qpc);
25139517SBill.Taylor@Sun.COM 			}
25149517SBill.Taylor@Sun.COM 
25159517SBill.Taylor@Sun.COM 			/*
25169517SBill.Taylor@Sun.COM 			 * If the current entry has served it's useful
25179517SBill.Taylor@Sun.COM 			 * purpose (i.e. been reused the maximum allowable
25189517SBill.Taylor@Sun.COM 			 * number of times), then remove it from QP number
25199517SBill.Taylor@Sun.COM 			 * AVL tree and free it up.
25209517SBill.Taylor@Sun.COM 			 */
25219517SBill.Taylor@Sun.COM 			if (entry->qpn_counter >= (1 <<
25229517SBill.Taylor@Sun.COM 			    (24 - state->hs_cfg_profile->cp_log_num_qp))) {
25239517SBill.Taylor@Sun.COM 				avl_remove(&state->hs_qpn_avl, entry);
25249517SBill.Taylor@Sun.COM 				kmem_free(entry, sizeof (hermon_qpn_entry_t));
25259517SBill.Taylor@Sun.COM 			}
25269517SBill.Taylor@Sun.COM 		}
25279517SBill.Taylor@Sun.COM 
25289517SBill.Taylor@Sun.COM 	} else if (flags == HERMON_QPN_FREE_ONLY) {
25299517SBill.Taylor@Sun.COM 		/*
25309517SBill.Taylor@Sun.COM 		 * Even if we are not freeing the QP number, that will not
25319517SBill.Taylor@Sun.COM 		 * always prevent us from releasing the QPC context.  In fact,
25329517SBill.Taylor@Sun.COM 		 * since the QPC context only forms part of the whole QPN,
25339517SBill.Taylor@Sun.COM 		 * we want to free it up for use by other consumers.  But
25349517SBill.Taylor@Sun.COM 		 * if the reference count is non-zero (which it will always
25359517SBill.Taylor@Sun.COM 		 * be when we are doing HERMON_QPN_FREE_ONLY) and the counter
25369517SBill.Taylor@Sun.COM 		 * has reached its maximum value, then we cannot reuse the
25379517SBill.Taylor@Sun.COM 		 * QPC context until the reference count eventually reaches
25389517SBill.Taylor@Sun.COM 		 * zero (in HERMON_QPN_RELEASE, above).
25399517SBill.Taylor@Sun.COM 		 */
25409517SBill.Taylor@Sun.COM 		if (entry->qpn_counter < (1 <<
25419517SBill.Taylor@Sun.COM 		    (24 - state->hs_cfg_profile->cp_log_num_qp))) {
25429517SBill.Taylor@Sun.COM 			hermon_rsrc_free(state, &entry->qpn_qpc);
25439517SBill.Taylor@Sun.COM 		}
25449517SBill.Taylor@Sun.COM 	}
25459517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_qpn_avl_lock);
25469517SBill.Taylor@Sun.COM }
25479517SBill.Taylor@Sun.COM 
25489517SBill.Taylor@Sun.COM 
25499517SBill.Taylor@Sun.COM /*
25509517SBill.Taylor@Sun.COM  * hermon_qpn_avl_compare()
25519517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
25529517SBill.Taylor@Sun.COM  */
25539517SBill.Taylor@Sun.COM static int
hermon_qpn_avl_compare(const void * q,const void * e)25549517SBill.Taylor@Sun.COM hermon_qpn_avl_compare(const void *q, const void *e)
25559517SBill.Taylor@Sun.COM {
25569517SBill.Taylor@Sun.COM 	hermon_qpn_entry_t	*entry, *query;
25579517SBill.Taylor@Sun.COM 
25589517SBill.Taylor@Sun.COM 	entry = (hermon_qpn_entry_t *)e;
25599517SBill.Taylor@Sun.COM 	query = (hermon_qpn_entry_t *)q;
25609517SBill.Taylor@Sun.COM 
25619517SBill.Taylor@Sun.COM 	if (query->qpn_indx < entry->qpn_indx) {
25629517SBill.Taylor@Sun.COM 		return (-1);
25639517SBill.Taylor@Sun.COM 	} else if (query->qpn_indx > entry->qpn_indx) {
25649517SBill.Taylor@Sun.COM 		return (+1);
25659517SBill.Taylor@Sun.COM 	} else {
25669517SBill.Taylor@Sun.COM 		return (0);
25679517SBill.Taylor@Sun.COM 	}
25689517SBill.Taylor@Sun.COM }
25699517SBill.Taylor@Sun.COM 
25709517SBill.Taylor@Sun.COM 
25719517SBill.Taylor@Sun.COM /*
25729517SBill.Taylor@Sun.COM  * hermon_qpn_avl_init()
25739517SBill.Taylor@Sun.COM  *    Context: Only called from attach() path context
25749517SBill.Taylor@Sun.COM  */
25759517SBill.Taylor@Sun.COM void
hermon_qpn_avl_init(hermon_state_t * state)25769517SBill.Taylor@Sun.COM hermon_qpn_avl_init(hermon_state_t *state)
25779517SBill.Taylor@Sun.COM {
25789517SBill.Taylor@Sun.COM 	/* Initialize the lock used for QP number (QPN) AVL tree access */
25799517SBill.Taylor@Sun.COM 	mutex_init(&state->hs_qpn_avl_lock, NULL, MUTEX_DRIVER,
25809517SBill.Taylor@Sun.COM 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
25819517SBill.Taylor@Sun.COM 
25829517SBill.Taylor@Sun.COM 	/* Initialize the AVL tree for the QP number (QPN) storage */
25839517SBill.Taylor@Sun.COM 	avl_create(&state->hs_qpn_avl, hermon_qpn_avl_compare,
25849517SBill.Taylor@Sun.COM 	    sizeof (hermon_qpn_entry_t),
25859517SBill.Taylor@Sun.COM 	    offsetof(hermon_qpn_entry_t, qpn_avlnode));
25869517SBill.Taylor@Sun.COM }
25879517SBill.Taylor@Sun.COM 
25889517SBill.Taylor@Sun.COM 
25899517SBill.Taylor@Sun.COM /*
25909517SBill.Taylor@Sun.COM  * hermon_qpn_avl_fini()
25919517SBill.Taylor@Sun.COM  *    Context: Only called from attach() and/or detach() path contexts
25929517SBill.Taylor@Sun.COM  */
25939517SBill.Taylor@Sun.COM void
hermon_qpn_avl_fini(hermon_state_t * state)25949517SBill.Taylor@Sun.COM hermon_qpn_avl_fini(hermon_state_t *state)
25959517SBill.Taylor@Sun.COM {
25969517SBill.Taylor@Sun.COM 	hermon_qpn_entry_t	*entry;
25979517SBill.Taylor@Sun.COM 	void			*cookie;
25989517SBill.Taylor@Sun.COM 
25999517SBill.Taylor@Sun.COM 	/*
26009517SBill.Taylor@Sun.COM 	 * Empty all entries (if necessary) and destroy the AVL tree
26019517SBill.Taylor@Sun.COM 	 * that was used for QP number (QPN) tracking.
26029517SBill.Taylor@Sun.COM 	 */
26039517SBill.Taylor@Sun.COM 	cookie = NULL;
26049517SBill.Taylor@Sun.COM 	while ((entry = (hermon_qpn_entry_t *)avl_destroy_nodes(
26059517SBill.Taylor@Sun.COM 	    &state->hs_qpn_avl, &cookie)) != NULL) {
26069517SBill.Taylor@Sun.COM 		kmem_free(entry, sizeof (hermon_qpn_entry_t));
26079517SBill.Taylor@Sun.COM 	}
26089517SBill.Taylor@Sun.COM 	avl_destroy(&state->hs_qpn_avl);
26099517SBill.Taylor@Sun.COM 
26109517SBill.Taylor@Sun.COM 	/* Destroy the lock used for QP number (QPN) AVL tree access */
26119517SBill.Taylor@Sun.COM 	mutex_destroy(&state->hs_qpn_avl_lock);
26129517SBill.Taylor@Sun.COM }
26139517SBill.Taylor@Sun.COM 
26149517SBill.Taylor@Sun.COM 
26159517SBill.Taylor@Sun.COM /*
26169517SBill.Taylor@Sun.COM  * hermon_qphdl_from_qpnum()
26179517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
26189517SBill.Taylor@Sun.COM  *
26199517SBill.Taylor@Sun.COM  *    This routine is important because changing the unconstrained
26209517SBill.Taylor@Sun.COM  *    portion of the QP number is critical to the detection of a
26219517SBill.Taylor@Sun.COM  *    potential race condition in the QP event handler code (i.e. the case
26229517SBill.Taylor@Sun.COM  *    where a QP is freed and alloc'd again before an event for the
26239517SBill.Taylor@Sun.COM  *    "old" QP can be handled).
26249517SBill.Taylor@Sun.COM  *
26259517SBill.Taylor@Sun.COM  *    While this is not a perfect solution (not sure that one exists)
26269517SBill.Taylor@Sun.COM  *    it does help to mitigate the chance that this race condition will
26279517SBill.Taylor@Sun.COM  *    cause us to deliver a "stale" event to the new QP owner.  Note:
26289517SBill.Taylor@Sun.COM  *    this solution does not scale well because the number of constrained
26299517SBill.Taylor@Sun.COM  *    bits increases (and, hence, the number of unconstrained bits
26309517SBill.Taylor@Sun.COM  *    decreases) as the number of supported QPs grows.  For small and
26319517SBill.Taylor@Sun.COM  *    intermediate values, it should hopefully provide sufficient
26329517SBill.Taylor@Sun.COM  *    protection.
26339517SBill.Taylor@Sun.COM  */
26349517SBill.Taylor@Sun.COM hermon_qphdl_t
hermon_qphdl_from_qpnum(hermon_state_t * state,uint_t qpnum)26359517SBill.Taylor@Sun.COM hermon_qphdl_from_qpnum(hermon_state_t *state, uint_t qpnum)
26369517SBill.Taylor@Sun.COM {
26379517SBill.Taylor@Sun.COM 	uint_t	qpindx, qpmask;
26389517SBill.Taylor@Sun.COM 
26399517SBill.Taylor@Sun.COM 	/* Calculate the QP table index from the qpnum */
26409517SBill.Taylor@Sun.COM 	qpmask = (1 << state->hs_cfg_profile->cp_log_num_qp) - 1;
26419517SBill.Taylor@Sun.COM 	qpindx = qpnum & qpmask;
2642*12965SWilliam.Taylor@Oracle.COM 	return (hermon_icm_num_to_hdl(state, HERMON_QPC, qpindx));
26439517SBill.Taylor@Sun.COM }
26449517SBill.Taylor@Sun.COM 
26459517SBill.Taylor@Sun.COM 
26469517SBill.Taylor@Sun.COM /*
26479517SBill.Taylor@Sun.COM  * hermon_special_qp_rsrc_alloc
26489517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
26499517SBill.Taylor@Sun.COM  */
26509517SBill.Taylor@Sun.COM static int
hermon_special_qp_rsrc_alloc(hermon_state_t * state,ibt_sqp_type_t type,uint_t port,hermon_rsrc_t ** qp_rsrc)26519517SBill.Taylor@Sun.COM hermon_special_qp_rsrc_alloc(hermon_state_t *state, ibt_sqp_type_t type,
26529517SBill.Taylor@Sun.COM     uint_t port, hermon_rsrc_t **qp_rsrc)
26539517SBill.Taylor@Sun.COM {
26549517SBill.Taylor@Sun.COM 	uint_t		mask, flags;
26559517SBill.Taylor@Sun.COM 	int		status;
26569517SBill.Taylor@Sun.COM 
26579517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_spec_qplock);
26589517SBill.Taylor@Sun.COM 	flags = state->hs_spec_qpflags;
26599517SBill.Taylor@Sun.COM 	if (type == IBT_SMI_SQP) {
26609517SBill.Taylor@Sun.COM 		/*
26619517SBill.Taylor@Sun.COM 		 * Check here to see if the driver has been configured
26629517SBill.Taylor@Sun.COM 		 * to instruct the Hermon firmware to handle all incoming
26639517SBill.Taylor@Sun.COM 		 * SMP messages (i.e. messages sent to SMA).  If so,
26649517SBill.Taylor@Sun.COM 		 * then we will treat QP0 as if it has already been
26659517SBill.Taylor@Sun.COM 		 * allocated (for internal use).  Otherwise, if we allow
26669517SBill.Taylor@Sun.COM 		 * the allocation to happen, it will cause unexpected
26679517SBill.Taylor@Sun.COM 		 * behaviors (e.g. Hermon SMA becomes unresponsive).
26689517SBill.Taylor@Sun.COM 		 */
26699517SBill.Taylor@Sun.COM 		if (state->hs_cfg_profile->cp_qp0_agents_in_fw != 0) {
26709517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_spec_qplock);
26719517SBill.Taylor@Sun.COM 			return (IBT_QP_IN_USE);
26729517SBill.Taylor@Sun.COM 		}
26739517SBill.Taylor@Sun.COM 
26749517SBill.Taylor@Sun.COM 		/*
26759517SBill.Taylor@Sun.COM 		 * If this is the first QP0 allocation, then post
26769517SBill.Taylor@Sun.COM 		 * a CONF_SPECIAL_QP firmware command
26779517SBill.Taylor@Sun.COM 		 */
26789517SBill.Taylor@Sun.COM 		if ((flags & HERMON_SPECIAL_QP0_RSRC_MASK) == 0) {
26799517SBill.Taylor@Sun.COM 			status = hermon_conf_special_qp_cmd_post(state,
26809517SBill.Taylor@Sun.COM 			    state->hs_spec_qp0->hr_indx, HERMON_CMD_QP_SMI,
26819517SBill.Taylor@Sun.COM 			    HERMON_CMD_NOSLEEP_SPIN,
26829517SBill.Taylor@Sun.COM 			    HERMON_CMD_SPEC_QP_OPMOD(
26839517SBill.Taylor@Sun.COM 			    state->hs_cfg_profile->cp_qp0_agents_in_fw,
26849517SBill.Taylor@Sun.COM 			    state->hs_cfg_profile->cp_qp1_agents_in_fw));
26859517SBill.Taylor@Sun.COM 			if (status != HERMON_CMD_SUCCESS) {
26869517SBill.Taylor@Sun.COM 				mutex_exit(&state->hs_spec_qplock);
26879517SBill.Taylor@Sun.COM 				cmn_err(CE_NOTE, "hermon%d: CONF_SPECIAL_QP "
26889517SBill.Taylor@Sun.COM 				    "command failed: %08x\n",
26899517SBill.Taylor@Sun.COM 				    state->hs_instance, status);
26909517SBill.Taylor@Sun.COM 				return (IBT_INSUFF_RESOURCE);
26919517SBill.Taylor@Sun.COM 			}
26929517SBill.Taylor@Sun.COM 		}
26939517SBill.Taylor@Sun.COM 
26949517SBill.Taylor@Sun.COM 		/*
26959517SBill.Taylor@Sun.COM 		 * Now check (and, if necessary, modify) the flags to indicate
26969517SBill.Taylor@Sun.COM 		 * whether the allocation was successful
26979517SBill.Taylor@Sun.COM 		 */
26989517SBill.Taylor@Sun.COM 		mask = (1 << (HERMON_SPECIAL_QP0_RSRC + port));
26999517SBill.Taylor@Sun.COM 		if (flags & mask) {
27009517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_spec_qplock);
27019517SBill.Taylor@Sun.COM 			return (IBT_QP_IN_USE);
27029517SBill.Taylor@Sun.COM 		}
27039517SBill.Taylor@Sun.COM 		state->hs_spec_qpflags |= mask;
27049517SBill.Taylor@Sun.COM 		*qp_rsrc = state->hs_spec_qp0;
27059517SBill.Taylor@Sun.COM 
27069517SBill.Taylor@Sun.COM 	} else {
27079517SBill.Taylor@Sun.COM 		/*
27089517SBill.Taylor@Sun.COM 		 * If this is the first QP1 allocation, then post
27099517SBill.Taylor@Sun.COM 		 * a CONF_SPECIAL_QP firmware command
27109517SBill.Taylor@Sun.COM 		 */
27119517SBill.Taylor@Sun.COM 		if ((flags & HERMON_SPECIAL_QP1_RSRC_MASK) == 0) {
27129517SBill.Taylor@Sun.COM 			status = hermon_conf_special_qp_cmd_post(state,
27139517SBill.Taylor@Sun.COM 			    state->hs_spec_qp1->hr_indx, HERMON_CMD_QP_GSI,
27149517SBill.Taylor@Sun.COM 			    HERMON_CMD_NOSLEEP_SPIN,
27159517SBill.Taylor@Sun.COM 			    HERMON_CMD_SPEC_QP_OPMOD(
27169517SBill.Taylor@Sun.COM 			    state->hs_cfg_profile->cp_qp0_agents_in_fw,
27179517SBill.Taylor@Sun.COM 			    state->hs_cfg_profile->cp_qp1_agents_in_fw));
27189517SBill.Taylor@Sun.COM 			if (status != HERMON_CMD_SUCCESS) {
27199517SBill.Taylor@Sun.COM 				mutex_exit(&state->hs_spec_qplock);
27209517SBill.Taylor@Sun.COM 				cmn_err(CE_NOTE, "hermon%d: CONF_SPECIAL_QP "
27219517SBill.Taylor@Sun.COM 				    "command failed: %08x\n",
27229517SBill.Taylor@Sun.COM 				    state->hs_instance, status);
27239517SBill.Taylor@Sun.COM 				return (IBT_INSUFF_RESOURCE);
27249517SBill.Taylor@Sun.COM 			}
27259517SBill.Taylor@Sun.COM 		}
27269517SBill.Taylor@Sun.COM 
27279517SBill.Taylor@Sun.COM 		/*
27289517SBill.Taylor@Sun.COM 		 * Now check (and, if necessary, modify) the flags to indicate
27299517SBill.Taylor@Sun.COM 		 * whether the allocation was successful
27309517SBill.Taylor@Sun.COM 		 */
27319517SBill.Taylor@Sun.COM 		mask = (1 << (HERMON_SPECIAL_QP1_RSRC + port));
27329517SBill.Taylor@Sun.COM 		if (flags & mask) {
27339517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_spec_qplock);
27349517SBill.Taylor@Sun.COM 			return (IBT_QP_IN_USE);
27359517SBill.Taylor@Sun.COM 		}
27369517SBill.Taylor@Sun.COM 		state->hs_spec_qpflags |= mask;
27379517SBill.Taylor@Sun.COM 		*qp_rsrc = state->hs_spec_qp1;
27389517SBill.Taylor@Sun.COM 	}
27399517SBill.Taylor@Sun.COM 
27409517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_spec_qplock);
27419517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
27429517SBill.Taylor@Sun.COM }
27439517SBill.Taylor@Sun.COM 
27449517SBill.Taylor@Sun.COM 
27459517SBill.Taylor@Sun.COM /*
27469517SBill.Taylor@Sun.COM  * hermon_special_qp_rsrc_free
27479517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
27489517SBill.Taylor@Sun.COM  */
27499517SBill.Taylor@Sun.COM static int
hermon_special_qp_rsrc_free(hermon_state_t * state,ibt_sqp_type_t type,uint_t port)27509517SBill.Taylor@Sun.COM hermon_special_qp_rsrc_free(hermon_state_t *state, ibt_sqp_type_t type,
27519517SBill.Taylor@Sun.COM     uint_t port)
27529517SBill.Taylor@Sun.COM {
27539517SBill.Taylor@Sun.COM 	uint_t		mask, flags;
27549517SBill.Taylor@Sun.COM 	int		status;
27559517SBill.Taylor@Sun.COM 
27569517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_spec_qplock);
27579517SBill.Taylor@Sun.COM 	if (type == IBT_SMI_SQP) {
27589517SBill.Taylor@Sun.COM 		mask = (1 << (HERMON_SPECIAL_QP0_RSRC + port));
27599517SBill.Taylor@Sun.COM 		state->hs_spec_qpflags &= ~mask;
27609517SBill.Taylor@Sun.COM 		flags = state->hs_spec_qpflags;
27619517SBill.Taylor@Sun.COM 
27629517SBill.Taylor@Sun.COM 		/*
27639517SBill.Taylor@Sun.COM 		 * If this is the last QP0 free, then post a CONF_SPECIAL_QP
27649517SBill.Taylor@Sun.COM 		 * NOW, If this is the last Special QP free, then post a
27659517SBill.Taylor@Sun.COM 		 * CONF_SPECIAL_QP firmware command - it'll stop them all
27669517SBill.Taylor@Sun.COM 		 */
27679517SBill.Taylor@Sun.COM 		if (flags) {
27689517SBill.Taylor@Sun.COM 			status = hermon_conf_special_qp_cmd_post(state, 0,
27699517SBill.Taylor@Sun.COM 			    HERMON_CMD_QP_SMI, HERMON_CMD_NOSLEEP_SPIN, 0);
27709517SBill.Taylor@Sun.COM 			if (status != HERMON_CMD_SUCCESS) {
27719517SBill.Taylor@Sun.COM 				mutex_exit(&state->hs_spec_qplock);
27729517SBill.Taylor@Sun.COM 				cmn_err(CE_NOTE, "hermon%d: CONF_SPECIAL_QP "
27739517SBill.Taylor@Sun.COM 				    "command failed: %08x\n",
27749517SBill.Taylor@Sun.COM 				    state->hs_instance, status);
27759517SBill.Taylor@Sun.COM 				if (status == HERMON_CMD_INVALID_STATUS) {
27769517SBill.Taylor@Sun.COM 					hermon_fm_ereport(state, HCA_SYS_ERR,
27779517SBill.Taylor@Sun.COM 					    HCA_ERR_SRV_LOST);
27789517SBill.Taylor@Sun.COM 				}
27799517SBill.Taylor@Sun.COM 				return (ibc_get_ci_failure(0));
27809517SBill.Taylor@Sun.COM 			}
27819517SBill.Taylor@Sun.COM 		}
27829517SBill.Taylor@Sun.COM 	} else {
27839517SBill.Taylor@Sun.COM 		mask = (1 << (HERMON_SPECIAL_QP1_RSRC + port));
27849517SBill.Taylor@Sun.COM 		state->hs_spec_qpflags &= ~mask;
27859517SBill.Taylor@Sun.COM 		flags = state->hs_spec_qpflags;
27869517SBill.Taylor@Sun.COM 
27879517SBill.Taylor@Sun.COM 		/*
27889517SBill.Taylor@Sun.COM 		 * If this is the last QP1 free, then post a CONF_SPECIAL_QP
27899517SBill.Taylor@Sun.COM 		 * NOW, if this is the last special QP free, then post a
27909517SBill.Taylor@Sun.COM 		 * CONF_SPECIAL_QP firmware command - it'll stop them all
27919517SBill.Taylor@Sun.COM 		 */
27929517SBill.Taylor@Sun.COM 		if (flags) {
27939517SBill.Taylor@Sun.COM 			status = hermon_conf_special_qp_cmd_post(state, 0,
27949517SBill.Taylor@Sun.COM 			    HERMON_CMD_QP_GSI, HERMON_CMD_NOSLEEP_SPIN, 0);
27959517SBill.Taylor@Sun.COM 			if (status != HERMON_CMD_SUCCESS) {
27969517SBill.Taylor@Sun.COM 				mutex_exit(&state->hs_spec_qplock);
27979517SBill.Taylor@Sun.COM 				cmn_err(CE_NOTE, "hermon%d: CONF_SPECIAL_QP "
27989517SBill.Taylor@Sun.COM 				    "command failed: %08x\n",
27999517SBill.Taylor@Sun.COM 				    state->hs_instance, status);
28009517SBill.Taylor@Sun.COM 				if (status == HERMON_CMD_INVALID_STATUS) {
28019517SBill.Taylor@Sun.COM 					hermon_fm_ereport(state, HCA_SYS_ERR,
28029517SBill.Taylor@Sun.COM 					    HCA_ERR_SRV_LOST);
28039517SBill.Taylor@Sun.COM 				}
28049517SBill.Taylor@Sun.COM 				return (ibc_get_ci_failure(0));
28059517SBill.Taylor@Sun.COM 			}
28069517SBill.Taylor@Sun.COM 		}
28079517SBill.Taylor@Sun.COM 	}
28089517SBill.Taylor@Sun.COM 
28099517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_spec_qplock);
28109517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
28119517SBill.Taylor@Sun.COM }
28129517SBill.Taylor@Sun.COM 
28139517SBill.Taylor@Sun.COM 
28149517SBill.Taylor@Sun.COM /*
28159517SBill.Taylor@Sun.COM  * hermon_qp_sgl_to_logwqesz()
28169517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
28179517SBill.Taylor@Sun.COM  */
28189517SBill.Taylor@Sun.COM static void
hermon_qp_sgl_to_logwqesz(hermon_state_t * state,uint_t num_sgl,uint_t real_max_sgl,hermon_qp_wq_type_t wq_type,uint_t * logwqesz,uint_t * max_sgl)28199517SBill.Taylor@Sun.COM hermon_qp_sgl_to_logwqesz(hermon_state_t *state, uint_t num_sgl,
28209517SBill.Taylor@Sun.COM     uint_t real_max_sgl, hermon_qp_wq_type_t wq_type,
28219517SBill.Taylor@Sun.COM     uint_t *logwqesz, uint_t *max_sgl)
28229517SBill.Taylor@Sun.COM {
28239517SBill.Taylor@Sun.COM 	uint_t	max_size, log2, actual_sgl;
28249517SBill.Taylor@Sun.COM 
28259517SBill.Taylor@Sun.COM 	switch (wq_type) {
28269517SBill.Taylor@Sun.COM 	case HERMON_QP_WQ_TYPE_SENDQ_UD:
28279517SBill.Taylor@Sun.COM 		/*
28289517SBill.Taylor@Sun.COM 		 * Use requested maximum SGL to calculate max descriptor size
28299517SBill.Taylor@Sun.COM 		 * (while guaranteeing that the descriptor size is a
28309517SBill.Taylor@Sun.COM 		 * power-of-2 cachelines).
28319517SBill.Taylor@Sun.COM 		 */
28329517SBill.Taylor@Sun.COM 		max_size = (HERMON_QP_WQE_MLX_SND_HDRS + (num_sgl << 4));
28339517SBill.Taylor@Sun.COM 		log2 = highbit(max_size);
28349517SBill.Taylor@Sun.COM 		if ((max_size & (max_size - 1)) == 0) {
28359517SBill.Taylor@Sun.COM 			log2 = log2 - 1;
28369517SBill.Taylor@Sun.COM 		}
28379517SBill.Taylor@Sun.COM 
28389517SBill.Taylor@Sun.COM 		/* Make sure descriptor is at least the minimum size */
28399517SBill.Taylor@Sun.COM 		log2 = max(log2, HERMON_QP_WQE_LOG_MINIMUM);
28409517SBill.Taylor@Sun.COM 
28419517SBill.Taylor@Sun.COM 		/* Calculate actual number of SGL (given WQE size) */
28429517SBill.Taylor@Sun.COM 		actual_sgl = ((1 << log2) -
28439517SBill.Taylor@Sun.COM 		    sizeof (hermon_hw_snd_wqe_ctrl_t)) >> 4;
28449517SBill.Taylor@Sun.COM 		break;
28459517SBill.Taylor@Sun.COM 
28469517SBill.Taylor@Sun.COM 	case HERMON_QP_WQ_TYPE_SENDQ_CONN:
28479517SBill.Taylor@Sun.COM 		/*
28489517SBill.Taylor@Sun.COM 		 * Use requested maximum SGL to calculate max descriptor size
28499517SBill.Taylor@Sun.COM 		 * (while guaranteeing that the descriptor size is a
28509517SBill.Taylor@Sun.COM 		 * power-of-2 cachelines).
28519517SBill.Taylor@Sun.COM 		 */
28529517SBill.Taylor@Sun.COM 		max_size = (HERMON_QP_WQE_MLX_SND_HDRS + (num_sgl << 4));
28539517SBill.Taylor@Sun.COM 		log2 = highbit(max_size);
28549517SBill.Taylor@Sun.COM 		if ((max_size & (max_size - 1)) == 0) {
28559517SBill.Taylor@Sun.COM 			log2 = log2 - 1;
28569517SBill.Taylor@Sun.COM 		}
28579517SBill.Taylor@Sun.COM 
28589517SBill.Taylor@Sun.COM 		/* Make sure descriptor is at least the minimum size */
28599517SBill.Taylor@Sun.COM 		log2 = max(log2, HERMON_QP_WQE_LOG_MINIMUM);
28609517SBill.Taylor@Sun.COM 
28619517SBill.Taylor@Sun.COM 		/* Calculate actual number of SGL (given WQE size) */
28629517SBill.Taylor@Sun.COM 		actual_sgl = ((1 << log2) - HERMON_QP_WQE_MLX_SND_HDRS) >> 4;
28639517SBill.Taylor@Sun.COM 		break;
28649517SBill.Taylor@Sun.COM 
28659517SBill.Taylor@Sun.COM 	case HERMON_QP_WQ_TYPE_RECVQ:
28669517SBill.Taylor@Sun.COM 		/*
28679517SBill.Taylor@Sun.COM 		 * Same as above (except for Recv WQEs)
28689517SBill.Taylor@Sun.COM 		 */
28699517SBill.Taylor@Sun.COM 		max_size = (HERMON_QP_WQE_MLX_RCV_HDRS + (num_sgl << 4));
28709517SBill.Taylor@Sun.COM 		log2 = highbit(max_size);
28719517SBill.Taylor@Sun.COM 		if ((max_size & (max_size - 1)) == 0) {
28729517SBill.Taylor@Sun.COM 			log2 = log2 - 1;
28739517SBill.Taylor@Sun.COM 		}
28749517SBill.Taylor@Sun.COM 
28759517SBill.Taylor@Sun.COM 		/* Make sure descriptor is at least the minimum size */
28769517SBill.Taylor@Sun.COM 		log2 = max(log2, HERMON_QP_WQE_LOG_MINIMUM);
28779517SBill.Taylor@Sun.COM 
28789517SBill.Taylor@Sun.COM 		/* Calculate actual number of SGL (given WQE size) */
28799517SBill.Taylor@Sun.COM 		actual_sgl = ((1 << log2) - HERMON_QP_WQE_MLX_RCV_HDRS) >> 4;
28809517SBill.Taylor@Sun.COM 		break;
28819517SBill.Taylor@Sun.COM 
28829517SBill.Taylor@Sun.COM 	case HERMON_QP_WQ_TYPE_SENDMLX_QP0:
28839517SBill.Taylor@Sun.COM 		/*
28849517SBill.Taylor@Sun.COM 		 * Same as above (except for MLX transport WQEs).  For these
28859517SBill.Taylor@Sun.COM 		 * WQEs we have to account for the space consumed by the
28869517SBill.Taylor@Sun.COM 		 * "inline" packet headers.  (This is smaller than for QP1
28879517SBill.Taylor@Sun.COM 		 * below because QP0 is not allowed to send packets with a GRH.
28889517SBill.Taylor@Sun.COM 		 */
28899517SBill.Taylor@Sun.COM 		max_size = (HERMON_QP_WQE_MLX_QP0_HDRS + (num_sgl << 4));
28909517SBill.Taylor@Sun.COM 		log2 = highbit(max_size);
28919517SBill.Taylor@Sun.COM 		if ((max_size & (max_size - 1)) == 0) {
28929517SBill.Taylor@Sun.COM 			log2 = log2 - 1;
28939517SBill.Taylor@Sun.COM 		}
28949517SBill.Taylor@Sun.COM 
28959517SBill.Taylor@Sun.COM 		/* Make sure descriptor is at least the minimum size */
28969517SBill.Taylor@Sun.COM 		log2 = max(log2, HERMON_QP_WQE_LOG_MINIMUM);
28979517SBill.Taylor@Sun.COM 
28989517SBill.Taylor@Sun.COM 		/* Calculate actual number of SGL (given WQE size) */
28999517SBill.Taylor@Sun.COM 		actual_sgl = ((1 << log2) - HERMON_QP_WQE_MLX_QP0_HDRS) >> 4;
29009517SBill.Taylor@Sun.COM 		break;
29019517SBill.Taylor@Sun.COM 
29029517SBill.Taylor@Sun.COM 	case HERMON_QP_WQ_TYPE_SENDMLX_QP1:
29039517SBill.Taylor@Sun.COM 		/*
29049517SBill.Taylor@Sun.COM 		 * Same as above.  For these WQEs we again have to account for
29059517SBill.Taylor@Sun.COM 		 * the space consumed by the "inline" packet headers.  (This
29069517SBill.Taylor@Sun.COM 		 * is larger than for QP0 above because we have to account for
29079517SBill.Taylor@Sun.COM 		 * the possibility of a GRH in each packet - and this
29089517SBill.Taylor@Sun.COM 		 * introduces an alignment issue that causes us to consume
29099517SBill.Taylor@Sun.COM 		 * an additional 8 bytes).
29109517SBill.Taylor@Sun.COM 		 */
29119517SBill.Taylor@Sun.COM 		max_size = (HERMON_QP_WQE_MLX_QP1_HDRS + (num_sgl << 4));
29129517SBill.Taylor@Sun.COM 		log2 = highbit(max_size);
29139517SBill.Taylor@Sun.COM 		if ((max_size & (max_size - 1)) == 0) {
29149517SBill.Taylor@Sun.COM 			log2 = log2 - 1;
29159517SBill.Taylor@Sun.COM 		}
29169517SBill.Taylor@Sun.COM 
29179517SBill.Taylor@Sun.COM 		/* Make sure descriptor is at least the minimum size */
29189517SBill.Taylor@Sun.COM 		log2 = max(log2, HERMON_QP_WQE_LOG_MINIMUM);
29199517SBill.Taylor@Sun.COM 
29209517SBill.Taylor@Sun.COM 		/* Calculate actual number of SGL (given WQE size) */
29219517SBill.Taylor@Sun.COM 		actual_sgl = ((1 << log2) - HERMON_QP_WQE_MLX_QP1_HDRS) >> 4;
29229517SBill.Taylor@Sun.COM 		break;
29239517SBill.Taylor@Sun.COM 
29249517SBill.Taylor@Sun.COM 	default:
29259517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unexpected work queue type");
29269517SBill.Taylor@Sun.COM 		break;
29279517SBill.Taylor@Sun.COM 	}
29289517SBill.Taylor@Sun.COM 
29299517SBill.Taylor@Sun.COM 	/* Fill in the return values */
29309517SBill.Taylor@Sun.COM 	*logwqesz = log2;
29319517SBill.Taylor@Sun.COM 	*max_sgl  = min(real_max_sgl, actual_sgl);
29329517SBill.Taylor@Sun.COM }
2933