19e39c5baSBill Taylor /*
29e39c5baSBill Taylor  * CDDL HEADER START
39e39c5baSBill Taylor  *
49e39c5baSBill Taylor  * The contents of this file are subject to the terms of the
59e39c5baSBill Taylor  * Common Development and Distribution License (the "License").
69e39c5baSBill Taylor  * You may not use this file except in compliance with the License.
79e39c5baSBill Taylor  *
89e39c5baSBill Taylor  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99e39c5baSBill Taylor  * or http://www.opensolaris.org/os/licensing.
109e39c5baSBill Taylor  * See the License for the specific language governing permissions
119e39c5baSBill Taylor  * and limitations under the License.
129e39c5baSBill Taylor  *
139e39c5baSBill Taylor  * When distributing Covered Code, include this CDDL HEADER in each
149e39c5baSBill Taylor  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159e39c5baSBill Taylor  * If applicable, add the following below this CDDL HEADER, with the
169e39c5baSBill Taylor  * fields enclosed by brackets "[]" replaced with your own identifying
179e39c5baSBill Taylor  * information: Portions Copyright [yyyy] [name of copyright owner]
189e39c5baSBill Taylor  *
199e39c5baSBill Taylor  * CDDL HEADER END
209e39c5baSBill Taylor  */
219e39c5baSBill Taylor 
229e39c5baSBill Taylor /*
2317a2b317SBill Taylor  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249e39c5baSBill Taylor  */
259e39c5baSBill Taylor 
269e39c5baSBill Taylor /*
279e39c5baSBill Taylor  * hermon_qp.c
289e39c5baSBill Taylor  *    Hermon Queue Pair Processing Routines
299e39c5baSBill Taylor  *
309e39c5baSBill Taylor  *    Implements all the routines necessary for allocating, freeing, and
319e39c5baSBill Taylor  *    querying the Hermon queue pairs.
329e39c5baSBill Taylor  */
339e39c5baSBill Taylor 
349e39c5baSBill Taylor #include <sys/types.h>
359e39c5baSBill Taylor #include <sys/conf.h>
369e39c5baSBill Taylor #include <sys/ddi.h>
379e39c5baSBill Taylor #include <sys/sunddi.h>
389e39c5baSBill Taylor #include <sys/modctl.h>
399e39c5baSBill Taylor #include <sys/bitmap.h>
409e39c5baSBill Taylor #include <sys/sysmacros.h>
419e39c5baSBill Taylor 
429e39c5baSBill Taylor #include <sys/ib/adapters/hermon/hermon.h>
439e39c5baSBill Taylor #include <sys/ib/ib_pkt_hdrs.h>
449e39c5baSBill Taylor 
459e39c5baSBill Taylor static int hermon_qp_create_qpn(hermon_state_t *state, hermon_qphdl_t qp,
469e39c5baSBill Taylor     hermon_rsrc_t *qpc);
479e39c5baSBill Taylor static int hermon_qpn_avl_compare(const void *q, const void *e);
489e39c5baSBill Taylor static int hermon_special_qp_rsrc_alloc(hermon_state_t *state,
499e39c5baSBill Taylor     ibt_sqp_type_t type, uint_t port, hermon_rsrc_t **qp_rsrc);
509e39c5baSBill Taylor static int hermon_special_qp_rsrc_free(hermon_state_t *state,
519e39c5baSBill Taylor     ibt_sqp_type_t type, uint_t port);
529e39c5baSBill Taylor static void hermon_qp_sgl_to_logwqesz(hermon_state_t *state, uint_t num_sgl,
539e39c5baSBill Taylor     uint_t real_max_sgl, hermon_qp_wq_type_t wq_type,
549e39c5baSBill Taylor     uint_t *logwqesz, uint_t *max_sgl);
559e39c5baSBill Taylor 
569e39c5baSBill Taylor /*
579e39c5baSBill Taylor  * hermon_qp_alloc()
589e39c5baSBill Taylor  *    Context: Can be called only from user or kernel context.
599e39c5baSBill Taylor  */
609e39c5baSBill Taylor int
hermon_qp_alloc(hermon_state_t * state,hermon_qp_info_t * qpinfo,uint_t sleepflag)619e39c5baSBill Taylor hermon_qp_alloc(hermon_state_t *state, hermon_qp_info_t *qpinfo,
629e39c5baSBill Taylor     uint_t sleepflag)
639e39c5baSBill Taylor {
649e39c5baSBill Taylor 	hermon_rsrc_t			*qpc, *rsrc;
6517a2b317SBill Taylor 	hermon_rsrc_type_t		rsrc_type;
669e39c5baSBill Taylor 	hermon_umap_db_entry_t		*umapdb;
679e39c5baSBill Taylor 	hermon_qphdl_t			qp;
689e39c5baSBill Taylor 	ibt_qp_alloc_attr_t		*attr_p;
6917a2b317SBill Taylor 	ibt_qp_alloc_flags_t		alloc_flags;
709e39c5baSBill Taylor 	ibt_qp_type_t			type;
719e39c5baSBill Taylor 	hermon_qp_wq_type_t		swq_type;
729e39c5baSBill Taylor 	ibtl_qp_hdl_t			ibt_qphdl;
739e39c5baSBill Taylor 	ibt_chan_sizes_t		*queuesz_p;
749e39c5baSBill Taylor 	ib_qpn_t			*qpn;
759e39c5baSBill Taylor 	hermon_qphdl_t			*qphdl;
769e39c5baSBill Taylor 	ibt_mr_attr_t			mr_attr;
779e39c5baSBill Taylor 	hermon_mr_options_t		mr_op;
789e39c5baSBill Taylor 	hermon_srqhdl_t			srq;
799e39c5baSBill Taylor 	hermon_pdhdl_t			pd;
809e39c5baSBill Taylor 	hermon_cqhdl_t			sq_cq, rq_cq;
819e39c5baSBill Taylor 	hermon_mrhdl_t			mr;
829e39c5baSBill Taylor 	uint64_t			value, qp_desc_off;
839e39c5baSBill Taylor 	uint64_t			*thewqe, thewqesz;
849e39c5baSBill Taylor 	uint32_t			*sq_buf, *rq_buf;
859e39c5baSBill Taylor 	uint32_t			log_qp_sq_size, log_qp_rq_size;
869e39c5baSBill Taylor 	uint32_t			sq_size, rq_size;
879e39c5baSBill Taylor 	uint32_t			sq_depth, rq_depth;
889e39c5baSBill Taylor 	uint32_t			sq_wqe_size, rq_wqe_size, wqesz_shift;
899e39c5baSBill Taylor 	uint32_t			max_sgl, max_recv_sgl, uarpg;
909e39c5baSBill Taylor 	uint_t				qp_is_umap;
919e39c5baSBill Taylor 	uint_t				qp_srq_en, i, j;
929e39c5baSBill Taylor 	int				status, flag;
939e39c5baSBill Taylor 
949e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*attr_p, *queuesz_p))
959e39c5baSBill Taylor 
969e39c5baSBill Taylor 	/*
979e39c5baSBill Taylor 	 * Extract the necessary info from the hermon_qp_info_t structure
989e39c5baSBill Taylor 	 */
999e39c5baSBill Taylor 	attr_p	  = qpinfo->qpi_attrp;
1009e39c5baSBill Taylor 	type	  = qpinfo->qpi_type;
1019e39c5baSBill Taylor 	ibt_qphdl = qpinfo->qpi_ibt_qphdl;
1029e39c5baSBill Taylor 	queuesz_p = qpinfo->qpi_queueszp;
1039e39c5baSBill Taylor 	qpn	  = qpinfo->qpi_qpn;
1049e39c5baSBill Taylor 	qphdl	  = &qpinfo->qpi_qphdl;
10517a2b317SBill Taylor 	alloc_flags = attr_p->qp_alloc_flags;
10617a2b317SBill Taylor 
10717a2b317SBill Taylor 	/*
10817a2b317SBill Taylor 	 * Verify correctness of alloc_flags.
10917a2b317SBill Taylor 	 *
11017a2b317SBill Taylor 	 * 1. FEXCH and RSS are only allocated via qp_range.
11117a2b317SBill Taylor 	 */
11217a2b317SBill Taylor 	if (alloc_flags & (IBT_QP_USES_FEXCH | IBT_QP_USES_RSS)) {
11317a2b317SBill Taylor 		return (IBT_INVALID_PARAM);
11417a2b317SBill Taylor 	}
11517a2b317SBill Taylor 	rsrc_type = HERMON_QPC;
11617a2b317SBill Taylor 	qp_is_umap = 0;
11717a2b317SBill Taylor 
11817a2b317SBill Taylor 	/* 2. Make sure only one of these flags is set. */
11917a2b317SBill Taylor 	switch (alloc_flags &
12017a2b317SBill Taylor 	    (IBT_QP_USER_MAP | IBT_QP_USES_RFCI | IBT_QP_USES_FCMD)) {
12117a2b317SBill Taylor 	case IBT_QP_USER_MAP:
12217a2b317SBill Taylor 		qp_is_umap = 1;
12317a2b317SBill Taylor 		break;
12417a2b317SBill Taylor 	case IBT_QP_USES_RFCI:
12517a2b317SBill Taylor 		if (type != IBT_UD_RQP)
12617a2b317SBill Taylor 			return (IBT_INVALID_PARAM);
12717a2b317SBill Taylor 
12817a2b317SBill Taylor 		switch (attr_p->qp_fc.fc_hca_port) {
12917a2b317SBill Taylor 		case 1:
13017a2b317SBill Taylor 			rsrc_type = HERMON_QPC_RFCI_PORT1;
13117a2b317SBill Taylor 			break;
13217a2b317SBill Taylor 		case 2:
13317a2b317SBill Taylor 			rsrc_type = HERMON_QPC_RFCI_PORT2;
13417a2b317SBill Taylor 			break;
13517a2b317SBill Taylor 		default:
13617a2b317SBill Taylor 			return (IBT_INVALID_PARAM);
13717a2b317SBill Taylor 		}
13817a2b317SBill Taylor 		break;
13917a2b317SBill Taylor 	case IBT_QP_USES_FCMD:
14017a2b317SBill Taylor 		if (type != IBT_UD_RQP)
14117a2b317SBill Taylor 			return (IBT_INVALID_PARAM);
14217a2b317SBill Taylor 		break;
14317a2b317SBill Taylor 	case 0:
14417a2b317SBill Taylor 		break;
14517a2b317SBill Taylor 	default:
14617a2b317SBill Taylor 		return (IBT_INVALID_PARAM);	/* conflicting flags set */
14717a2b317SBill Taylor 	}
1489e39c5baSBill Taylor 
1499e39c5baSBill Taylor 	/*
1509e39c5baSBill Taylor 	 * Determine whether QP is being allocated for userland access or
1519e39c5baSBill Taylor 	 * whether it is being allocated for kernel access.  If the QP is
1529e39c5baSBill Taylor 	 * being allocated for userland access, then lookup the UAR
1539e39c5baSBill Taylor 	 * page number for the current process.  Note:  If this is not found
1549e39c5baSBill Taylor 	 * (e.g. if the process has not previously open()'d the Hermon driver),
1559e39c5baSBill Taylor 	 * then an error is returned.
1569e39c5baSBill Taylor 	 */
1579e39c5baSBill Taylor 	if (qp_is_umap) {
1589e39c5baSBill Taylor 		status = hermon_umap_db_find(state->hs_instance, ddi_get_pid(),
1599e39c5baSBill Taylor 		    MLNX_UMAP_UARPG_RSRC, &value, 0, NULL);
1609e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
16117a2b317SBill Taylor 			return (IBT_INVALID_PARAM);
1629e39c5baSBill Taylor 		}
1639e39c5baSBill Taylor 		uarpg = ((hermon_rsrc_t *)(uintptr_t)value)->hr_indx;
1649e39c5baSBill Taylor 	} else {
1659e39c5baSBill Taylor 		uarpg = state->hs_kernel_uar_index;
1669e39c5baSBill Taylor 	}
1679e39c5baSBill Taylor 
1689e39c5baSBill Taylor 	/*
1699e39c5baSBill Taylor 	 * Determine whether QP is being associated with an SRQ
1709e39c5baSBill Taylor 	 */
17117a2b317SBill Taylor 	qp_srq_en = (alloc_flags & IBT_QP_USES_SRQ) ? 1 : 0;
1729e39c5baSBill Taylor 	if (qp_srq_en) {
1739e39c5baSBill Taylor 		/*
1749e39c5baSBill Taylor 		 * Check for valid SRQ handle pointers
1759e39c5baSBill Taylor 		 */
1769e39c5baSBill Taylor 		if (attr_p->qp_ibc_srq_hdl == NULL) {
1779e39c5baSBill Taylor 			status = IBT_SRQ_HDL_INVALID;
1789e39c5baSBill Taylor 			goto qpalloc_fail;
1799e39c5baSBill Taylor 		}
1809e39c5baSBill Taylor 		srq = (hermon_srqhdl_t)attr_p->qp_ibc_srq_hdl;
1819e39c5baSBill Taylor 	}
1829e39c5baSBill Taylor 
1839e39c5baSBill Taylor 	/*
1849e39c5baSBill Taylor 	 * Check for valid QP service type (only UD/RC/UC supported)
1859e39c5baSBill Taylor 	 */
1869e39c5baSBill Taylor 	if (((type != IBT_UD_RQP) && (type != IBT_RC_RQP) &&
1879e39c5baSBill Taylor 	    (type != IBT_UC_RQP))) {
1889e39c5baSBill Taylor 		status = IBT_QP_SRV_TYPE_INVALID;
1899e39c5baSBill Taylor 		goto qpalloc_fail;
1909e39c5baSBill Taylor 	}
1919e39c5baSBill Taylor 
1929e39c5baSBill Taylor 
1939e39c5baSBill Taylor 	/*
1949e39c5baSBill Taylor 	 * Check for valid PD handle pointer
1959e39c5baSBill Taylor 	 */
1969e39c5baSBill Taylor 	if (attr_p->qp_pd_hdl == NULL) {
1979e39c5baSBill Taylor 		status = IBT_PD_HDL_INVALID;
1989e39c5baSBill Taylor 		goto qpalloc_fail;
1999e39c5baSBill Taylor 	}
2009e39c5baSBill Taylor 	pd = (hermon_pdhdl_t)attr_p->qp_pd_hdl;
2019e39c5baSBill Taylor 
2029e39c5baSBill Taylor 	/*
2039e39c5baSBill Taylor 	 * If on an SRQ, check to make sure the PD is the same
2049e39c5baSBill Taylor 	 */
2059e39c5baSBill Taylor 	if (qp_srq_en && (pd->pd_pdnum != srq->srq_pdhdl->pd_pdnum)) {
2069e39c5baSBill Taylor 		status = IBT_PD_HDL_INVALID;
2079e39c5baSBill Taylor 		goto qpalloc_fail;
2089e39c5baSBill Taylor 	}
2099e39c5baSBill Taylor 
2109e39c5baSBill Taylor 	/* Increment the reference count on the protection domain (PD) */
2119e39c5baSBill Taylor 	hermon_pd_refcnt_inc(pd);
2129e39c5baSBill Taylor 
2139e39c5baSBill Taylor 	/*
2149e39c5baSBill Taylor 	 * Check for valid CQ handle pointers
21517a2b317SBill Taylor 	 *
21617a2b317SBill Taylor 	 * FCMD QPs do not require a receive cq handle.
2179e39c5baSBill Taylor 	 */
21817a2b317SBill Taylor 	if (attr_p->qp_ibc_scq_hdl == NULL) {
2199e39c5baSBill Taylor 		status = IBT_CQ_HDL_INVALID;
2209e39c5baSBill Taylor 		goto qpalloc_fail1;
2219e39c5baSBill Taylor 	}
2229e39c5baSBill Taylor 	sq_cq = (hermon_cqhdl_t)attr_p->qp_ibc_scq_hdl;
22317a2b317SBill Taylor 	if ((attr_p->qp_ibc_rcq_hdl == NULL)) {
22417a2b317SBill Taylor 		if ((alloc_flags & IBT_QP_USES_FCMD) == 0) {
22517a2b317SBill Taylor 			status = IBT_CQ_HDL_INVALID;
22617a2b317SBill Taylor 			goto qpalloc_fail1;
22717a2b317SBill Taylor 		}
22817a2b317SBill Taylor 		rq_cq = sq_cq;	/* just use the send cq */
22917a2b317SBill Taylor 	} else
23017a2b317SBill Taylor 		rq_cq = (hermon_cqhdl_t)attr_p->qp_ibc_rcq_hdl;
2319e39c5baSBill Taylor 
2329e39c5baSBill Taylor 	/*
2339e39c5baSBill Taylor 	 * Increment the reference count on the CQs.  One or both of these
2349e39c5baSBill Taylor 	 * could return error if we determine that the given CQ is already
2359e39c5baSBill Taylor 	 * being used with a special (SMI/GSI) QP.
2369e39c5baSBill Taylor 	 */
2379e39c5baSBill Taylor 	status = hermon_cq_refcnt_inc(sq_cq, HERMON_CQ_IS_NORMAL);
2389e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
2399e39c5baSBill Taylor 		status = IBT_CQ_HDL_INVALID;
2409e39c5baSBill Taylor 		goto qpalloc_fail1;
2419e39c5baSBill Taylor 	}
2429e39c5baSBill Taylor 	status = hermon_cq_refcnt_inc(rq_cq, HERMON_CQ_IS_NORMAL);
2439e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
2449e39c5baSBill Taylor 		status = IBT_CQ_HDL_INVALID;
2459e39c5baSBill Taylor 		goto qpalloc_fail2;
2469e39c5baSBill Taylor 	}
2479e39c5baSBill Taylor 
2489e39c5baSBill Taylor 	/*
2499e39c5baSBill Taylor 	 * Allocate an QP context entry.  This will be filled in with all
2509e39c5baSBill Taylor 	 * the necessary parameters to define the Queue Pair.  Unlike
2519e39c5baSBill Taylor 	 * other Hermon hardware resources, ownership is not immediately
2529e39c5baSBill Taylor 	 * given to hardware in the final step here.  Instead, we must
2539e39c5baSBill Taylor 	 * wait until the QP is later transitioned to the "Init" state before
2549e39c5baSBill Taylor 	 * passing the QP to hardware.  If we fail here, we must undo all
2559e39c5baSBill Taylor 	 * the reference count (CQ and PD).
2569e39c5baSBill Taylor 	 */
25717a2b317SBill Taylor 	status = hermon_rsrc_alloc(state, rsrc_type, 1, sleepflag, &qpc);
2589e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
2599e39c5baSBill Taylor 		status = IBT_INSUFF_RESOURCE;
2609e39c5baSBill Taylor 		goto qpalloc_fail3;
2619e39c5baSBill Taylor 	}
2629e39c5baSBill Taylor 
2639e39c5baSBill Taylor 	/*
2649e39c5baSBill Taylor 	 * Allocate the software structure for tracking the queue pair
2659e39c5baSBill Taylor 	 * (i.e. the Hermon Queue Pair handle).  If we fail here, we must
2669e39c5baSBill Taylor 	 * undo the reference counts and the previous resource allocation.
2679e39c5baSBill Taylor 	 */
2689e39c5baSBill Taylor 	status = hermon_rsrc_alloc(state, HERMON_QPHDL, 1, sleepflag, &rsrc);
2699e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
2709e39c5baSBill Taylor 		status = IBT_INSUFF_RESOURCE;
2719e39c5baSBill Taylor 		goto qpalloc_fail4;
2729e39c5baSBill Taylor 	}
2739e39c5baSBill Taylor 	qp = (hermon_qphdl_t)rsrc->hr_addr;
2749e39c5baSBill Taylor 	bzero(qp, sizeof (struct hermon_sw_qp_s));
2759e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp))
2769e39c5baSBill Taylor 
27717a2b317SBill Taylor 	qp->qp_alloc_flags = alloc_flags;
27817a2b317SBill Taylor 
2799e39c5baSBill Taylor 	/*
2809e39c5baSBill Taylor 	 * Calculate the QP number from QPC index.  This routine handles
2819e39c5baSBill Taylor 	 * all of the operations necessary to keep track of used, unused,
2829e39c5baSBill Taylor 	 * and released QP numbers.
2839e39c5baSBill Taylor 	 */
28417a2b317SBill Taylor 	if (type == IBT_UD_RQP) {
28517a2b317SBill Taylor 		qp->qp_qpnum = qpc->hr_indx;
28617a2b317SBill Taylor 		qp->qp_ring = qp->qp_qpnum << 8;
28717a2b317SBill Taylor 		qp->qp_qpn_hdl = NULL;
28817a2b317SBill Taylor 	} else {
28917a2b317SBill Taylor 		status = hermon_qp_create_qpn(state, qp, qpc);
29017a2b317SBill Taylor 		if (status != DDI_SUCCESS) {
29117a2b317SBill Taylor 			status = IBT_INSUFF_RESOURCE;
29217a2b317SBill Taylor 			goto qpalloc_fail5;
29317a2b317SBill Taylor 		}
2949e39c5baSBill Taylor 	}
2959e39c5baSBill Taylor 
2969e39c5baSBill Taylor 	/*
2979e39c5baSBill Taylor 	 * If this will be a user-mappable QP, then allocate an entry for
2989e39c5baSBill Taylor 	 * the "userland resources database".  This will later be added to
2999e39c5baSBill Taylor 	 * the database (after all further QP operations are successful).
3009e39c5baSBill Taylor 	 * If we fail here, we must undo the reference counts and the
3019e39c5baSBill Taylor 	 * previous resource allocation.
3029e39c5baSBill Taylor 	 */
3039e39c5baSBill Taylor 	if (qp_is_umap) {
3049e39c5baSBill Taylor 		umapdb = hermon_umap_db_alloc(state->hs_instance, qp->qp_qpnum,
3059e39c5baSBill Taylor 		    MLNX_UMAP_QPMEM_RSRC, (uint64_t)(uintptr_t)rsrc);
3069e39c5baSBill Taylor 		if (umapdb == NULL) {
3079e39c5baSBill Taylor 			status = IBT_INSUFF_RESOURCE;
3089e39c5baSBill Taylor 			goto qpalloc_fail6;
3099e39c5baSBill Taylor 		}
3109e39c5baSBill Taylor 	}
3119e39c5baSBill Taylor 
3129e39c5baSBill Taylor 	/*
3139e39c5baSBill Taylor 	 * Allocate the doorbell record.  Hermon just needs one for the RQ,
3149e39c5baSBill Taylor 	 * if the QP is not associated with an SRQ, and use uarpg (above) as
3159e39c5baSBill Taylor 	 * the uar index
3169e39c5baSBill Taylor 	 */
3179e39c5baSBill Taylor 
3189e39c5baSBill Taylor 	if (!qp_srq_en) {
3199e39c5baSBill Taylor 		status = hermon_dbr_alloc(state, uarpg, &qp->qp_rq_dbr_acchdl,
3209e39c5baSBill Taylor 		    &qp->qp_rq_vdbr, &qp->qp_rq_pdbr, &qp->qp_rdbr_mapoffset);
3219e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
3229e39c5baSBill Taylor 			status = IBT_INSUFF_RESOURCE;
3239e39c5baSBill Taylor 			goto qpalloc_fail6;
3249e39c5baSBill Taylor 		}
3259e39c5baSBill Taylor 	}
3269e39c5baSBill Taylor 
3279e39c5baSBill Taylor 	qp->qp_uses_lso = (attr_p->qp_flags & IBT_USES_LSO);
3289e39c5baSBill Taylor 
3299e39c5baSBill Taylor 	/*
3309e39c5baSBill Taylor 	 * We verify that the requested number of SGL is valid (i.e.
3319e39c5baSBill Taylor 	 * consistent with the device limits and/or software-configured
3329e39c5baSBill Taylor 	 * limits).  If not, then obviously the same cleanup needs to be done.
3339e39c5baSBill Taylor 	 */
3349e39c5baSBill Taylor 	if (type == IBT_UD_RQP) {
3359e39c5baSBill Taylor 		max_sgl = state->hs_ibtfinfo.hca_attr->hca_ud_send_sgl_sz;
3369e39c5baSBill Taylor 		swq_type = HERMON_QP_WQ_TYPE_SENDQ_UD;
3379e39c5baSBill Taylor 	} else {
3389e39c5baSBill Taylor 		max_sgl = state->hs_ibtfinfo.hca_attr->hca_conn_send_sgl_sz;
3399e39c5baSBill Taylor 		swq_type = HERMON_QP_WQ_TYPE_SENDQ_CONN;
3409e39c5baSBill Taylor 	}
3419e39c5baSBill Taylor 	max_recv_sgl = state->hs_ibtfinfo.hca_attr->hca_recv_sgl_sz;
3429e39c5baSBill Taylor 	if ((attr_p->qp_sizes.cs_sq_sgl > max_sgl) ||
3439e39c5baSBill Taylor 	    (!qp_srq_en && (attr_p->qp_sizes.cs_rq_sgl > max_recv_sgl))) {
3449e39c5baSBill Taylor 		status = IBT_HCA_SGL_EXCEEDED;
3459e39c5baSBill Taylor 		goto qpalloc_fail7;
3469e39c5baSBill Taylor 	}
3479e39c5baSBill Taylor 
3489e39c5baSBill Taylor 	/*
3499e39c5baSBill Taylor 	 * Determine this QP's WQE stride (for both the Send and Recv WQEs).
3509e39c5baSBill Taylor 	 * This will depend on the requested number of SGLs.  Note: this
3519e39c5baSBill Taylor 	 * has the side-effect of also calculating the real number of SGLs
3529e39c5baSBill Taylor 	 * (for the calculated WQE size).
3539e39c5baSBill Taylor 	 *
3549e39c5baSBill Taylor 	 * For QP's on an SRQ, we set these to 0.
3559e39c5baSBill Taylor 	 */
3569e39c5baSBill Taylor 	if (qp_srq_en) {
3579e39c5baSBill Taylor 		qp->qp_rq_log_wqesz = 0;
3589e39c5baSBill Taylor 		qp->qp_rq_sgl = 0;
3599e39c5baSBill Taylor 	} else {
3609e39c5baSBill Taylor 		hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_rq_sgl,
3619e39c5baSBill Taylor 		    max_recv_sgl, HERMON_QP_WQ_TYPE_RECVQ,
3629e39c5baSBill Taylor 		    &qp->qp_rq_log_wqesz, &qp->qp_rq_sgl);
3639e39c5baSBill Taylor 	}
3649e39c5baSBill Taylor 	hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_sq_sgl,
3659e39c5baSBill Taylor 	    max_sgl, swq_type, &qp->qp_sq_log_wqesz, &qp->qp_sq_sgl);
3669e39c5baSBill Taylor 
3679e39c5baSBill Taylor 	sq_wqe_size = 1 << qp->qp_sq_log_wqesz;
3689e39c5baSBill Taylor 
3699e39c5baSBill Taylor 	/* NOTE: currently policy in driver, later maybe IBTF interface */
3709e39c5baSBill Taylor 	qp->qp_no_prefetch = 0;
3719e39c5baSBill Taylor 
3729e39c5baSBill Taylor 	/*
3739e39c5baSBill Taylor 	 * for prefetching, we need to add the number of wqes in
3749e39c5baSBill Taylor 	 * the 2k area plus one to the number requested, but
3759e39c5baSBill Taylor 	 * ONLY for send queue.  If no_prefetch == 1 (prefetch off)
3769e39c5baSBill Taylor 	 * it's exactly TWO wqes for the headroom
3779e39c5baSBill Taylor 	 */
3789e39c5baSBill Taylor 	if (qp->qp_no_prefetch)
3799e39c5baSBill Taylor 		qp->qp_sq_headroom = 2 * sq_wqe_size;
3809e39c5baSBill Taylor 	else
3819e39c5baSBill Taylor 		qp->qp_sq_headroom = sq_wqe_size + HERMON_QP_OH_SIZE;
3829e39c5baSBill Taylor 	/*
3839e39c5baSBill Taylor 	 * hdrm wqes must be integral since both sq_wqe_size &
3849e39c5baSBill Taylor 	 * HERMON_QP_OH_SIZE are power of 2
3859e39c5baSBill Taylor 	 */
3869e39c5baSBill Taylor 	qp->qp_sq_hdrmwqes = (qp->qp_sq_headroom / sq_wqe_size);
3879e39c5baSBill Taylor 
3889e39c5baSBill Taylor 
3899e39c5baSBill Taylor 	/*
3909e39c5baSBill Taylor 	 * Calculate the appropriate size for the work queues.
3919e39c5baSBill Taylor 	 * For send queue, add in the headroom wqes to the calculation.
3929e39c5baSBill Taylor 	 * Note:  All Hermon QP work queues must be a power-of-2 in size.  Also
3939e39c5baSBill Taylor 	 * they may not be any smaller than HERMON_QP_MIN_SIZE.  This step is
3949e39c5baSBill Taylor 	 * to round the requested size up to the next highest power-of-2
3959e39c5baSBill Taylor 	 */
3969e39c5baSBill Taylor 	/* first, adjust to a minimum and tell the caller the change */
3979e39c5baSBill Taylor 	attr_p->qp_sizes.cs_sq = max(attr_p->qp_sizes.cs_sq,
3989e39c5baSBill Taylor 	    HERMON_QP_MIN_SIZE);
3999e39c5baSBill Taylor 	attr_p->qp_sizes.cs_rq = max(attr_p->qp_sizes.cs_rq,
4009e39c5baSBill Taylor 	    HERMON_QP_MIN_SIZE);
4019e39c5baSBill Taylor 	/*
4029e39c5baSBill Taylor 	 * now, calculate the alloc size, taking into account
4039e39c5baSBill Taylor 	 * the headroom for the sq
4049e39c5baSBill Taylor 	 */
4059e39c5baSBill Taylor 	log_qp_sq_size = highbit(attr_p->qp_sizes.cs_sq + qp->qp_sq_hdrmwqes);
4069e39c5baSBill Taylor 	/* if the total is a power of two, reduce it */
407de710d24SJosef 'Jeff' Sipek 	if (ISP2(attr_p->qp_sizes.cs_sq + qp->qp_sq_hdrmwqes))	{
4089e39c5baSBill Taylor 		log_qp_sq_size = log_qp_sq_size - 1;
4099e39c5baSBill Taylor 	}
4109e39c5baSBill Taylor 
4119e39c5baSBill Taylor 	log_qp_rq_size = highbit(attr_p->qp_sizes.cs_rq);
412de710d24SJosef 'Jeff' Sipek 	if (ISP2(attr_p->qp_sizes.cs_rq)) {
4139e39c5baSBill Taylor 		log_qp_rq_size = log_qp_rq_size - 1;
4149e39c5baSBill Taylor 	}
4159e39c5baSBill Taylor 
4169e39c5baSBill Taylor 	/*
4179e39c5baSBill Taylor 	 * Next we verify that the rounded-up size is valid (i.e. consistent
4189e39c5baSBill Taylor 	 * with the device limits and/or software-configured limits).  If not,
4199e39c5baSBill Taylor 	 * then obviously we have a lot of cleanup to do before returning.
4209e39c5baSBill Taylor 	 *
4219e39c5baSBill Taylor 	 * NOTE: the first condition deals with the (test) case of cs_sq
4229e39c5baSBill Taylor 	 * being just less than 2^32.  In this case, the headroom addition
4239e39c5baSBill Taylor 	 * to the requested cs_sq will pass the test when it should not.
4249e39c5baSBill Taylor 	 * This test no longer lets that case slip through the check.
4259e39c5baSBill Taylor 	 */
4269e39c5baSBill Taylor 	if ((attr_p->qp_sizes.cs_sq >
4279e39c5baSBill Taylor 	    (1 << state->hs_cfg_profile->cp_log_max_qp_sz)) ||
4289e39c5baSBill Taylor 	    (log_qp_sq_size > state->hs_cfg_profile->cp_log_max_qp_sz) ||
4299e39c5baSBill Taylor 	    (!qp_srq_en && (log_qp_rq_size >
4309e39c5baSBill Taylor 	    state->hs_cfg_profile->cp_log_max_qp_sz))) {
4319e39c5baSBill Taylor 		status = IBT_HCA_WR_EXCEEDED;
4329e39c5baSBill Taylor 		goto qpalloc_fail7;
4339e39c5baSBill Taylor 	}
4349e39c5baSBill Taylor 
4359e39c5baSBill Taylor 	/*
4369e39c5baSBill Taylor 	 * Allocate the memory for QP work queues. Since Hermon work queues
4379e39c5baSBill Taylor 	 * are not allowed to cross a 32-bit (4GB) boundary, the alignment of
4389e39c5baSBill Taylor 	 * the work queue memory is very important.  We used to allocate
4399e39c5baSBill Taylor 	 * work queues (the combined receive and send queues) so that they
4409e39c5baSBill Taylor 	 * would be aligned on their combined size.  That alignment guaranteed
4419e39c5baSBill Taylor 	 * that they would never cross the 4GB boundary (Hermon work queues
4429e39c5baSBill Taylor 	 * are on the order of MBs at maximum).  Now we are able to relax
4439e39c5baSBill Taylor 	 * this alignment constraint by ensuring that the IB address assigned
4449e39c5baSBill Taylor 	 * to the queue memory (as a result of the hermon_mr_register() call)
4459e39c5baSBill Taylor 	 * is offset from zero.
4469e39c5baSBill Taylor 	 * Previously, we had wanted to use the ddi_dma_mem_alloc() routine to
4479e39c5baSBill Taylor 	 * guarantee the alignment, but when attempting to use IOMMU bypass
4489e39c5baSBill Taylor 	 * mode we found that we were not allowed to specify any alignment
4499e39c5baSBill Taylor 	 * that was more restrictive than the system page size.
4509e39c5baSBill Taylor 	 * So we avoided this constraint by passing two alignment values,
4519e39c5baSBill Taylor 	 * one for the memory allocation itself and the other for the DMA
4529e39c5baSBill Taylor 	 * handle (for later bind).  This used to cause more memory than
4539e39c5baSBill Taylor 	 * necessary to be allocated (in order to guarantee the more
4549e39c5baSBill Taylor 	 * restrictive alignment contraint).  But by guaranteeing the
4559e39c5baSBill Taylor 	 * zero-based IB virtual address for the queue, we are able to
4569e39c5baSBill Taylor 	 * conserve this memory.
4579e39c5baSBill Taylor 	 */
4589e39c5baSBill Taylor 	sq_wqe_size = 1 << qp->qp_sq_log_wqesz;
4599e39c5baSBill Taylor 	sq_depth    = 1 << log_qp_sq_size;
4609e39c5baSBill Taylor 	sq_size	    = sq_depth * sq_wqe_size;
4619e39c5baSBill Taylor 
4629e39c5baSBill Taylor 	/* QP on SRQ sets these to 0 */
4639e39c5baSBill Taylor 	if (qp_srq_en) {
4649e39c5baSBill Taylor 		rq_wqe_size = 0;
4659e39c5baSBill Taylor 		rq_size	    = 0;
4669e39c5baSBill Taylor 	} else {
4679e39c5baSBill Taylor 		rq_wqe_size = 1 << qp->qp_rq_log_wqesz;
4689e39c5baSBill Taylor 		rq_depth    = 1 << log_qp_rq_size;
4699e39c5baSBill Taylor 		rq_size	    = rq_depth * rq_wqe_size;
4709e39c5baSBill Taylor 	}
4719e39c5baSBill Taylor 
4729e39c5baSBill Taylor 	qp->qp_wqinfo.qa_size = sq_size + rq_size;
4739e39c5baSBill Taylor 
4749e39c5baSBill Taylor 	qp->qp_wqinfo.qa_alloc_align = PAGESIZE;
4759e39c5baSBill Taylor 	qp->qp_wqinfo.qa_bind_align  = PAGESIZE;
4769e39c5baSBill Taylor 
4779e39c5baSBill Taylor 	if (qp_is_umap) {
4789e39c5baSBill Taylor 		qp->qp_wqinfo.qa_location = HERMON_QUEUE_LOCATION_USERLAND;
4799e39c5baSBill Taylor 	} else {
4809e39c5baSBill Taylor 		qp->qp_wqinfo.qa_location = HERMON_QUEUE_LOCATION_NORMAL;
4819e39c5baSBill Taylor 	}
4829e39c5baSBill Taylor 	status = hermon_queue_alloc(state, &qp->qp_wqinfo, sleepflag);
4839e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
4849e39c5baSBill Taylor 		status = IBT_INSUFF_RESOURCE;
4859e39c5baSBill Taylor 		goto qpalloc_fail7;
4869e39c5baSBill Taylor 	}
4879e39c5baSBill Taylor 
4889e39c5baSBill Taylor 	/*
4899e39c5baSBill Taylor 	 * Sort WQs in memory according to stride (*q_wqe_size), largest first
4909e39c5baSBill Taylor 	 * If they are equal, still put the SQ first
4919e39c5baSBill Taylor 	 */
4929e39c5baSBill Taylor 	qp->qp_sq_baseaddr = 0;
4939e39c5baSBill Taylor 	qp->qp_rq_baseaddr = 0;
4949e39c5baSBill Taylor 	if ((sq_wqe_size > rq_wqe_size) || (sq_wqe_size == rq_wqe_size)) {
4959e39c5baSBill Taylor 		sq_buf = qp->qp_wqinfo.qa_buf_aligned;
4969e39c5baSBill Taylor 
4979e39c5baSBill Taylor 		/* if this QP is on an SRQ, set the rq_buf to NULL */
4989e39c5baSBill Taylor 		if (qp_srq_en) {
4999e39c5baSBill Taylor 			rq_buf = NULL;
5009e39c5baSBill Taylor 		} else {
5019e39c5baSBill Taylor 			rq_buf = (uint32_t *)((uintptr_t)sq_buf + sq_size);
5029e39c5baSBill Taylor 			qp->qp_rq_baseaddr = sq_size;
5039e39c5baSBill Taylor 		}
5049e39c5baSBill Taylor 	} else {
5059e39c5baSBill Taylor 		rq_buf = qp->qp_wqinfo.qa_buf_aligned;
5069e39c5baSBill Taylor 		sq_buf = (uint32_t *)((uintptr_t)rq_buf + rq_size);
5079e39c5baSBill Taylor 		qp->qp_sq_baseaddr = rq_size;
5089e39c5baSBill Taylor 	}
5099e39c5baSBill Taylor 
5109e39c5baSBill Taylor 	if (qp_is_umap == 0) {
5119e39c5baSBill Taylor 		qp->qp_sq_wqhdr = hermon_wrid_wqhdr_create(sq_depth);
5129e39c5baSBill Taylor 		if (qp->qp_sq_wqhdr == NULL) {
5139e39c5baSBill Taylor 			status = IBT_INSUFF_RESOURCE;
5149e39c5baSBill Taylor 			goto qpalloc_fail8;
5159e39c5baSBill Taylor 		}
5169e39c5baSBill Taylor 		if (qp_srq_en) {
5179e39c5baSBill Taylor 			qp->qp_rq_wqavl.wqa_wq = srq->srq_wq_wqhdr;
5189e39c5baSBill Taylor 			qp->qp_rq_wqavl.wqa_srq_en = 1;
5199e39c5baSBill Taylor 			qp->qp_rq_wqavl.wqa_srq = srq;
5209e39c5baSBill Taylor 		} else {
5219e39c5baSBill Taylor 			qp->qp_rq_wqhdr = hermon_wrid_wqhdr_create(rq_depth);
5229e39c5baSBill Taylor 			if (qp->qp_rq_wqhdr == NULL) {
5239e39c5baSBill Taylor 				status = IBT_INSUFF_RESOURCE;
5249e39c5baSBill Taylor 				goto qpalloc_fail8;
5259e39c5baSBill Taylor 			}
5269e39c5baSBill Taylor 			qp->qp_rq_wqavl.wqa_wq = qp->qp_rq_wqhdr;
5279e39c5baSBill Taylor 		}
5289e39c5baSBill Taylor 		qp->qp_sq_wqavl.wqa_qpn = qp->qp_qpnum;
5299e39c5baSBill Taylor 		qp->qp_sq_wqavl.wqa_type = HERMON_WR_SEND;
5309e39c5baSBill Taylor 		qp->qp_sq_wqavl.wqa_wq = qp->qp_sq_wqhdr;
5319e39c5baSBill Taylor 		qp->qp_rq_wqavl.wqa_qpn = qp->qp_qpnum;
5329e39c5baSBill Taylor 		qp->qp_rq_wqavl.wqa_type = HERMON_WR_RECV;
5339e39c5baSBill Taylor 	}
5349e39c5baSBill Taylor 
5359e39c5baSBill Taylor 	/*
5369e39c5baSBill Taylor 	 * Register the memory for the QP work queues.  The memory for the
5379e39c5baSBill Taylor 	 * QP must be registered in the Hermon cMPT tables.  This gives us the
5389e39c5baSBill Taylor 	 * LKey to specify in the QP context later.  Note: The memory for
5399e39c5baSBill Taylor 	 * Hermon work queues (both Send and Recv) must be contiguous and
5409e39c5baSBill Taylor 	 * registered as a single memory region.  Note: If the QP memory is
5419e39c5baSBill Taylor 	 * user-mappable, force DDI_DMA_CONSISTENT mapping. Also, in order to
5429e39c5baSBill Taylor 	 * meet the alignment restriction, we pass the "mro_bind_override_addr"
5439e39c5baSBill Taylor 	 * flag in the call to hermon_mr_register(). This guarantees that the
5449e39c5baSBill Taylor 	 * resulting IB vaddr will be zero-based (modulo the offset into the
5459e39c5baSBill Taylor 	 * first page). If we fail here, we still have the bunch of resource
5469e39c5baSBill Taylor 	 * and reference count cleanup to do.
5479e39c5baSBill Taylor 	 */
5489e39c5baSBill Taylor 	flag = (sleepflag == HERMON_SLEEP) ? IBT_MR_SLEEP :
5499e39c5baSBill Taylor 	    IBT_MR_NOSLEEP;
5509e39c5baSBill Taylor 	mr_attr.mr_vaddr    = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
5519e39c5baSBill Taylor 	mr_attr.mr_len	    = qp->qp_wqinfo.qa_size;
5529e39c5baSBill Taylor 	mr_attr.mr_as	    = NULL;
5539e39c5baSBill Taylor 	mr_attr.mr_flags    = flag;
5549e39c5baSBill Taylor 	if (qp_is_umap) {
5559e39c5baSBill Taylor 		mr_op.mro_bind_type = state->hs_cfg_profile->cp_iommu_bypass;
5569e39c5baSBill Taylor 	} else {
5579e39c5baSBill Taylor 		/* HERMON_QUEUE_LOCATION_NORMAL */
5589e39c5baSBill Taylor 		mr_op.mro_bind_type =
5599e39c5baSBill Taylor 		    state->hs_cfg_profile->cp_iommu_bypass;
5609e39c5baSBill Taylor 	}
5619e39c5baSBill Taylor 	mr_op.mro_bind_dmahdl = qp->qp_wqinfo.qa_dmahdl;
5629e39c5baSBill Taylor 	mr_op.mro_bind_override_addr = 1;
5639e39c5baSBill Taylor 	status = hermon_mr_register(state, pd, &mr_attr, &mr,
5649e39c5baSBill Taylor 	    &mr_op, HERMON_QP_CMPT);
5659e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
5669e39c5baSBill Taylor 		status = IBT_INSUFF_RESOURCE;
5679e39c5baSBill Taylor 		goto qpalloc_fail9;
5689e39c5baSBill Taylor 	}
5699e39c5baSBill Taylor 
5709e39c5baSBill Taylor 	/*
5719e39c5baSBill Taylor 	 * Calculate the offset between the kernel virtual address space
5729e39c5baSBill Taylor 	 * and the IB virtual address space.  This will be used when
5739e39c5baSBill Taylor 	 * posting work requests to properly initialize each WQE.
5749e39c5baSBill Taylor 	 */
5759e39c5baSBill Taylor 	qp_desc_off = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
5769e39c5baSBill Taylor 	    (uint64_t)mr->mr_bindinfo.bi_addr;
5779e39c5baSBill Taylor 
5789e39c5baSBill Taylor 	/*
5799e39c5baSBill Taylor 	 * Fill in all the return arguments (if necessary).  This includes
5809e39c5baSBill Taylor 	 * real work queue sizes (in wqes), real SGLs, and QP number
5819e39c5baSBill Taylor 	 */
5829e39c5baSBill Taylor 	if (queuesz_p != NULL) {
583*0b63ccafSToomas Soome 		queuesz_p->cs_sq	=
5849e39c5baSBill Taylor 		    (1 << log_qp_sq_size) - qp->qp_sq_hdrmwqes;
5859e39c5baSBill Taylor 		queuesz_p->cs_sq_sgl	= qp->qp_sq_sgl;
5869e39c5baSBill Taylor 
5879e39c5baSBill Taylor 		/* if this QP is on an SRQ, set these to 0 */
5889e39c5baSBill Taylor 		if (qp_srq_en) {
5899e39c5baSBill Taylor 			queuesz_p->cs_rq	= 0;
5909e39c5baSBill Taylor 			queuesz_p->cs_rq_sgl	= 0;
5919e39c5baSBill Taylor 		} else {
5929e39c5baSBill Taylor 			queuesz_p->cs_rq	= (1 << log_qp_rq_size);
5939e39c5baSBill Taylor 			queuesz_p->cs_rq_sgl	= qp->qp_rq_sgl;
5949e39c5baSBill Taylor 		}
5959e39c5baSBill Taylor 	}
5969e39c5baSBill Taylor 	if (qpn != NULL) {
5979e39c5baSBill Taylor 		*qpn = (ib_qpn_t)qp->qp_qpnum;
5989e39c5baSBill Taylor 	}
5999e39c5baSBill Taylor 
6009e39c5baSBill Taylor 	/*
6019e39c5baSBill Taylor 	 * Fill in the rest of the Hermon Queue Pair handle.
6029e39c5baSBill Taylor 	 */
6039e39c5baSBill Taylor 	qp->qp_qpcrsrcp		= qpc;
6049e39c5baSBill Taylor 	qp->qp_rsrcp		= rsrc;
6059e39c5baSBill Taylor 	qp->qp_state		= HERMON_QP_RESET;
6079e39c5baSBill Taylor 	qp->qp_pdhdl		= pd;
6089e39c5baSBill Taylor 	qp->qp_mrhdl		= mr;
6099e39c5baSBill Taylor 	qp->qp_sq_sigtype	= (attr_p->qp_flags & IBT_WR_SIGNALED) ?
6119e39c5baSBill Taylor 	qp->qp_is_special	= 0;
6129e39c5baSBill Taylor 	qp->qp_uarpg		= uarpg;
6139e39c5baSBill Taylor 	qp->qp_umap_dhp		= (devmap_cookie_t)NULL;
6149e39c5baSBill Taylor 	qp->qp_sq_cqhdl		= sq_cq;
6159e39c5baSBill Taylor 	qp->qp_sq_bufsz		= (1 << log_qp_sq_size);
6169e39c5baSBill Taylor 	qp->qp_sq_logqsz	= log_qp_sq_size;
6179e39c5baSBill Taylor 	qp->qp_sq_buf		= sq_buf;
6189e39c5baSBill Taylor 	qp->qp_desc_off		= qp_desc_off;
6199e39c5baSBill Taylor 	qp->qp_rq_cqhdl		= rq_cq;
6209e39c5baSBill Taylor 	qp->qp_rq_buf		= rq_buf;
6219e39c5baSBill Taylor 	qp->qp_rlky		= (attr_p->qp_flags & IBT_FAST_REG_RES_LKEY) !=
6229e39c5baSBill Taylor 	    0;
6239e39c5baSBill Taylor 
6249e39c5baSBill Taylor 	/* if this QP is on an SRQ, set rq_bufsz to 0 */
6259e39c5baSBill Taylor 	if (qp_srq_en) {
6269e39c5baSBill Taylor 		qp->qp_rq_bufsz		= 0;
6279e39c5baSBill Taylor 		qp->qp_rq_logqsz	= 0;
6289e39c5baSBill Taylor 	} else {
6299e39c5baSBill Taylor 		qp->qp_rq_bufsz		= (1 << log_qp_rq_size);
6309e39c5baSBill Taylor 		qp->qp_rq_logqsz	= log_qp_rq_size;
6319e39c5baSBill Taylor 	}
6329e39c5baSBill Taylor 
6339e39c5baSBill Taylor 	qp->qp_forward_sqd_event  = 0;
6349e39c5baSBill Taylor 	qp->qp_sqd_still_draining = 0;
6359e39c5baSBill Taylor 	qp->qp_hdlrarg		= (void *)ibt_qphdl;
6369e39c5baSBill Taylor 	qp->qp_mcg_refcnt	= 0;
6379e39c5baSBill Taylor 
6389e39c5baSBill Taylor 	/*
6399e39c5baSBill Taylor 	 * If this QP is to be associated with an SRQ, set the SRQ handle
6409e39c5baSBill Taylor 	 */
6419e39c5baSBill Taylor 	if (qp_srq_en) {
6429e39c5baSBill Taylor 		qp->qp_srqhdl = srq;
6439e39c5baSBill Taylor 		hermon_srq_refcnt_inc(qp->qp_srqhdl);
6449e39c5baSBill Taylor 	} else {
6459e39c5baSBill Taylor 		qp->qp_srqhdl = NULL;
6469e39c5baSBill Taylor 	}
6479e39c5baSBill Taylor 
6489e39c5baSBill Taylor 	/* Determine the QP service type */
64917a2b317SBill Taylor 	qp->qp_type = type;
6509e39c5baSBill Taylor 	if (type == IBT_RC_RQP) {
6519e39c5baSBill Taylor 		qp->qp_serv_type = HERMON_QP_RC;
6529e39c5baSBill Taylor 	} else if (type == IBT_UD_RQP) {
65317a2b317SBill Taylor 		if (alloc_flags & IBT_QP_USES_RFCI)
65417a2b317SBill Taylor 			qp->qp_serv_type = HERMON_QP_RFCI;
65517a2b317SBill Taylor 		else if (alloc_flags & IBT_QP_USES_FCMD)
65617a2b317SBill Taylor 			qp->qp_serv_type = HERMON_QP_FCMND;
65717a2b317SBill Taylor 		else
65817a2b317SBill Taylor 			qp->qp_serv_type = HERMON_QP_UD;
6599e39c5baSBill Taylor 	} else {
6609e39c5baSBill Taylor 		qp->qp_serv_type = HERMON_QP_UC;
6619e39c5baSBill Taylor 	}
6629e39c5baSBill Taylor 
6639e39c5baSBill Taylor 	/*
6649e39c5baSBill Taylor 	 * Initialize the RQ WQEs - unlike Arbel, no Rcv init is needed
6659e39c5baSBill Taylor 	 */
6669e39c5baSBill Taylor 
6679e39c5baSBill Taylor 	/*
6689e39c5baSBill Taylor 	 * Initialize the SQ WQEs - all that needs to be done is every 64 bytes
6699e39c5baSBill Taylor 	 * set the quadword to all F's - high-order bit is owner (init to one)
6709e39c5baSBill Taylor 	 * and the rest for the headroom definition of prefetching
6719e39c5baSBill Taylor 	 *
6729e39c5baSBill Taylor 	 */
6739e39c5baSBill Taylor 	wqesz_shift = qp->qp_sq_log_wqesz;
6749e39c5baSBill Taylor 	thewqesz    = 1 << wqesz_shift;
6759e39c5baSBill Taylor 	thewqe = (uint64_t *)(void *)(qp->qp_sq_buf);
6769e39c5baSBill Taylor 	if (qp_is_umap == 0) {
6779e39c5baSBill Taylor 		for (i = 0; i < sq_depth; i++) {
6789e39c5baSBill Taylor 			/*
6799e39c5baSBill Taylor 			 * for each stride, go through and every 64 bytes
6809e39c5baSBill Taylor 			 * write the init value - having set the address
6819e39c5baSBill Taylor 			 * once, just keep incrementing it
6829e39c5baSBill Taylor 			 */
6839e39c5baSBill Taylor 			for (j = 0; j < thewqesz; j += 64, thewqe += 8) {
6849e39c5baSBill Taylor 				*(uint32_t *)thewqe = 0xFFFFFFFF;
6859e39c5baSBill Taylor 			}
6869e39c5baSBill Taylor 		}
6879e39c5baSBill Taylor 	}
6889e39c5baSBill Taylor 
6899e39c5baSBill Taylor 	/* Zero out the QP context */
6909e39c5baSBill Taylor 	bzero(&qp->qpc, sizeof (hermon_hw_qpc_t));
6919e39c5baSBill Taylor 
6929e39c5baSBill Taylor 	/*
6939e39c5baSBill Taylor 	 * Put QP handle in Hermon QPNum-to-QPHdl list.  Then fill in the
6949e39c5baSBill Taylor 	 * "qphdl" and return success
6959e39c5baSBill Taylor 	 */
69617a2b317SBill Taylor 	hermon_icm_set_num_to_hdl(state, HERMON_QPC, qpc->hr_indx, qp);
6979e39c5baSBill Taylor 
6989e39c5baSBill Taylor 	/*
6999e39c5baSBill Taylor 	 * If this is a user-mappable QP, then we need to insert the previously
7009e39c5baSBill Taylor 	 * allocated entry into the "userland resources database".  This will
7019e39c5baSBill Taylor 	 * allow for later lookup during devmap() (i.e. mmap()) calls.
7029e39c5baSBill Taylor 	 */
7039e39c5baSBill Taylor 	if (qp_is_umap) {
7049e39c5baSBill Taylor 		hermon_umap_db_add(umapdb);
7059e39c5baSBill Taylor 	}
7069e39c5baSBill Taylor 	mutex_init(&qp->qp_sq_lock, NULL, MUTEX_DRIVER,
7079e39c5baSBill Taylor 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
7089e39c5baSBill Taylor 
7099e39c5baSBill Taylor 	*qphdl = qp;
7109e39c5baSBill Taylor 
7119e39c5baSBill Taylor 	return (DDI_SUCCESS);
7129e39c5baSBill Taylor 
7139e39c5baSBill Taylor /*
7149e39c5baSBill Taylor  * The following is cleanup for all possible failure cases in this routine
7159e39c5baSBill Taylor  */
7169e39c5baSBill Taylor qpalloc_fail9:
7179e39c5baSBill Taylor 	hermon_queue_free(&qp->qp_wqinfo);
7189e39c5baSBill Taylor qpalloc_fail8:
7199e39c5baSBill Taylor 	if (qp->qp_sq_wqhdr)
7209e39c5baSBill Taylor 		hermon_wrid_wqhdr_destroy(qp->qp_sq_wqhdr);
7219e39c5baSBill Taylor 	if (qp->qp_rq_wqhdr)
7229e39c5baSBill Taylor 		hermon_wrid_wqhdr_destroy(qp->qp_rq_wqhdr);
7239e39c5baSBill Taylor qpalloc_fail7:
7249e39c5baSBill Taylor 	if (qp_is_umap) {
7259e39c5baSBill Taylor 		hermon_umap_db_free(umapdb);
7269e39c5baSBill Taylor 	}
7279e39c5baSBill Taylor 	if (!qp_srq_en) {
7289e39c5baSBill Taylor 		hermon_dbr_free(state, uarpg, qp->qp_rq_vdbr);
7299e39c5baSBill Taylor 	}
7309e39c5baSBill Taylor 
7319e39c5baSBill Taylor qpalloc_fail6:
7329e39c5baSBill Taylor 	/*
7339e39c5baSBill Taylor 	 * Releasing the QPN will also free up the QPC context.  Update
7349e39c5baSBill Taylor 	 * the QPC context pointer to indicate this.
7359e39c5baSBill Taylor 	 */
73617a2b317SBill Taylor 	if (qp->qp_qpn_hdl) {
73717a2b317SBill Taylor 		hermon_qp_release_qpn(state, qp->qp_qpn_hdl,
73817a2b317SBill Taylor 		    HERMON_QPN_RELEASE);
73917a2b317SBill Taylor 	} else {
74017a2b317SBill Taylor 		hermon_rsrc_free(state, &qpc);
74117a2b317SBill Taylor 	}
7429e39c5baSBill Taylor 	qpc = NULL;
7439e39c5baSBill Taylor qpalloc_fail5:
7449e39c5baSBill Taylor 	hermon_rsrc_free(state, &rsrc);
7459e39c5baSBill Taylor qpalloc_fail4:
7469e39c5baSBill Taylor 	if (qpc) {
7479e39c5baSBill Taylor 		hermon_rsrc_free(state, &qpc);
7489e39c5baSBill Taylor 	}
7499e39c5baSBill Taylor qpalloc_fail3:
7509e39c5baSBill Taylor 	hermon_cq_refcnt_dec(rq_cq);
7519e39c5baSBill Taylor qpalloc_fail2:
7529e39c5baSBill Taylor 	hermon_cq_refcnt_dec(sq_cq);
7539e39c5baSBill Taylor qpalloc_fail1:
7549e39c5baSBill Taylor 	hermon_pd_refcnt_dec(pd);
7559e39c5baSBill Taylor qpalloc_fail:
7569e39c5baSBill Taylor 	return (status);
7579e39c5baSBill Taylor }
7589e39c5baSBill Taylor 
7599e39c5baSBill Taylor 
7609e39c5baSBill Taylor 
7619e39c5baSBill Taylor /*
7629e39c5baSBill Taylor  * hermon_special_qp_alloc()
7639e39c5baSBill Taylor  *    Context: Can be called only from user or kernel context.
7649e39c5baSBill Taylor  */
7659e39c5baSBill Taylor int
hermon_special_qp_alloc(hermon_state_t * state,hermon_qp_info_t * qpinfo,uint_t sleepflag)7669e39c5baSBill Taylor hermon_special_qp_alloc(hermon_state_t *state, hermon_qp_info_t *qpinfo,
7679e39c5baSBill Taylor     uint_t sleepflag)
7689e39c5baSBill Taylor {
7699e39c5baSBill Taylor 	hermon_rsrc_t		*qpc, *rsrc;
7709e39c5baSBill Taylor 	hermon_qphdl_t		qp;
7719e39c5baSBill Taylor 	ibt_qp_alloc_attr_t	*attr_p;
7729e39c5baSBill Taylor 	ibt_sqp_type_t		type;
7739e39c5baSBill Taylor 	uint8_t			port;
7749e39c5baSBill Taylor 	ibtl_qp_hdl_t		ibt_qphdl;
7759e39c5baSBill Taylor 	ibt_chan_sizes_t	*queuesz_p;
7769e39c5baSBill Taylor 	hermon_qphdl_t		*qphdl;
7779e39c5baSBill Taylor 	ibt_mr_attr_t		mr_attr;
7789e39c5baSBill Taylor 	hermon_mr_options_t	mr_op;
7799e39c5baSBill Taylor 	hermon_pdhdl_t		pd;
7809e39c5baSBill Taylor 	hermon_cqhdl_t		sq_cq, rq_cq;
7819e39c5baSBill Taylor 	hermon_mrhdl_t		mr;
7829e39c5baSBill Taylor 	uint64_t		qp_desc_off;
7839e39c5baSBill Taylor 	uint64_t		*thewqe, thewqesz;
7849e39c5baSBill Taylor 	uint32_t		*sq_buf, *rq_buf;
7859e39c5baSBill Taylor 	uint32_t		log_qp_sq_size, log_qp_rq_size;
7869e39c5baSBill Taylor 	uint32_t		sq_size, rq_size, max_sgl;
7879e39c5baSBill Taylor 	uint32_t		uarpg;
7889e39c5baSBill Taylor 	uint32_t		sq_depth;
7899e39c5baSBill Taylor 	uint32_t		sq_wqe_size, rq_wqe_size, wqesz_shift;
7909e39c5baSBill Taylor 	int			status, flag, i, j;
7919e39c5baSBill Taylor 
7929e39c5baSBill Taylor 	/*
7939e39c5baSBill Taylor 	 * Extract the necessary info from the hermon_qp_info_t structure
7949e39c5baSBill Taylor 	 */
7959e39c5baSBill Taylor 	attr_p	  = qpinfo->qpi_attrp;
7969e39c5baSBill Taylor 	type	  = qpinfo->qpi_type;
7979e39c5baSBill Taylor 	port	  = qpinfo->qpi_port;
7989e39c5baSBill Taylor 	ibt_qphdl = qpinfo->qpi_ibt_qphdl;
7999e39c5baSBill Taylor 	queuesz_p = qpinfo->qpi_queueszp;
8009e39c5baSBill Taylor 	qphdl	  = &qpinfo->qpi_qphdl;
8019e39c5baSBill Taylor 
8029e39c5baSBill Taylor 	/*
8039e39c5baSBill Taylor 	 * Check for valid special QP type (only SMI & GSI supported)
8049e39c5baSBill Taylor 	 */
8059e39c5baSBill Taylor 	if ((type != IBT_SMI_SQP) && (type != IBT_GSI_SQP)) {
8069e39c5baSBill Taylor 		status = IBT_QP_SPECIAL_TYPE_INVALID;
8079e39c5baSBill Taylor 		goto spec_qpalloc_fail;
8089e39c5baSBill Taylor 	}
8099e39c5baSBill Taylor 
8109e39c5baSBill Taylor 	/*
8119e39c5baSBill Taylor 	 * Check for valid port number
8129e39c5baSBill Taylor 	 */
8139e39c5baSBill Taylor 	if (!hermon_portnum_is_valid(state, port)) {
8149e39c5baSBill Taylor 		status = IBT_HCA_PORT_INVALID;
8159e39c5baSBill Taylor 		goto spec_qpalloc_fail;
8169e39c5baSBill Taylor 	}
8179e39c5baSBill Taylor 	port = port - 1;
8189e39c5baSBill Taylor 
8199e39c5baSBill Taylor 	/*
8209e39c5baSBill Taylor 	 * Check for valid PD handle pointer
8219e39c5baSBill Taylor 	 */
8229e39c5baSBill Taylor 	if (attr_p->qp_pd_hdl == NULL) {
8239e39c5baSBill Taylor 		status = IBT_PD_HDL_INVALID;
8249e39c5baSBill Taylor 		goto spec_qpalloc_fail;
8259e39c5baSBill Taylor 	}
8269e39c5baSBill Taylor 	pd = (hermon_pdhdl_t)attr_p->qp_pd_hdl;
8279e39c5baSBill Taylor 
8289e39c5baSBill Taylor 	/* Increment the reference count on the PD */
8299e39c5baSBill Taylor 	hermon_pd_refcnt_inc(pd);
8309e39c5baSBill Taylor 
8319e39c5baSBill Taylor 	/*
8329e39c5baSBill Taylor 	 * Check for valid CQ handle pointers
8339e39c5baSBill Taylor 	 */
8349e39c5baSBill Taylor 	if ((attr_p->qp_ibc_scq_hdl == NULL) ||
8359e39c5baSBill Taylor 	    (attr_p->qp_ibc_rcq_hdl == NULL)) {
8369e39c5baSBill Taylor 		status = IBT_CQ_HDL_INVALID;
8379e39c5baSBill Taylor 		goto spec_qpalloc_fail1;
8389e39c5baSBill Taylor 	}
8399e39c5baSBill Taylor 	sq_cq = (hermon_cqhdl_t)attr_p->qp_ibc_scq_hdl;
8409e39c5baSBill Taylor 	rq_cq = (hermon_cqhdl_t)attr_p->qp_ibc_rcq_hdl;
8419e39c5baSBill Taylor 
8429e39c5baSBill Taylor 	/*
8439e39c5baSBill Taylor 	 * Increment the reference count on the CQs.  One or both of these
8449e39c5baSBill Taylor 	 * could return error if we determine that the given CQ is already
8459e39c5baSBill Taylor 	 * being used with a non-special QP (i.e. a normal QP).
8469e39c5baSBill Taylor 	 */
8479e39c5baSBill Taylor 	status = hermon_cq_refcnt_inc(sq_cq, HERMON_CQ_IS_SPECIAL);
8489e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
8499e39c5baSBill Taylor 		status = IBT_CQ_HDL_INVALID;
8509e39c5baSBill Taylor 		goto spec_qpalloc_fail1;
8519e39c5baSBill Taylor 	}
8529e39c5baSBill Taylor 	status = hermon_cq_refcnt_inc(rq_cq, HERMON_CQ_IS_SPECIAL);
8539e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
8549e39c5baSBill Taylor 		status = IBT_CQ_HDL_INVALID;
8559e39c5baSBill Taylor 		goto spec_qpalloc_fail2;
8569e39c5baSBill Taylor 	}
8579e39c5baSBill Taylor 
8589e39c5baSBill Taylor 	/*
8599e39c5baSBill Taylor 	 * Allocate the special QP resources.  Essentially, this allocation
8609e39c5baSBill Taylor 	 * amounts to checking if the request special QP has already been
8619e39c5baSBill Taylor 	 * allocated.  If successful, the QP context return is an actual
8629e39c5baSBill Taylor 	 * QP context that has been "aliased" to act as a special QP of the
8639e39c5baSBill Taylor 	 * appropriate type (and for the appropriate port).  Just as in
8649e39c5baSBill Taylor 	 * hermon_qp_alloc() above, ownership for this QP context is not
8659e39c5baSBill Taylor 	 * immediately given to hardware in the final step here.  Instead, we
8669e39c5baSBill Taylor 	 * wait until the QP is later transitioned to the "Init" state before
8679e39c5baSBill Taylor 	 * passing the QP to hardware.  If we fail here, we must undo all
8689e39c5baSBill Taylor 	 * the reference count (CQ and PD).
8699e39c5baSBill Taylor 	 */
8709e39c5baSBill Taylor 	status = hermon_special_qp_rsrc_alloc(state, type, port, &qpc);
8719e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
8729e39c5baSBill Taylor 		goto spec_qpalloc_fail3;
8739e39c5baSBill Taylor 	}
8749e39c5baSBill Taylor 
8759e39c5baSBill Taylor 	/*
8769e39c5baSBill Taylor 	 * Allocate the software structure for tracking the special queue
8779e39c5baSBill Taylor 	 * pair (i.e. the Hermon Queue Pair handle).  If we fail here, we
8789e39c5baSBill Taylor 	 * must undo the reference counts and the previous resource allocation.
8799e39c5baSBill Taylor 	 */
8809e39c5baSBill Taylor 	status = hermon_rsrc_alloc(state, HERMON_QPHDL, 1, sleepflag, &rsrc);
8819e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
8829e39c5baSBill Taylor 		status = IBT_INSUFF_RESOURCE;
8839e39c5baSBill Taylor 		goto spec_qpalloc_fail4;
8849e39c5baSBill Taylor 	}
8859e39c5baSBill Taylor 	qp = (hermon_qphdl_t)rsrc->hr_addr;
8869e39c5baSBill Taylor 
8879e39c5baSBill Taylor 	bzero(qp, sizeof (struct hermon_sw_qp_s));
8889e39c5baSBill Taylor 
8899e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp))
89017a2b317SBill Taylor 	qp->qp_alloc_flags = attr_p->qp_alloc_flags;
8919e39c5baSBill Taylor 
8929e39c5baSBill Taylor 	/*
8939e39c5baSBill Taylor 	 * Actual QP number is a combination of the index of the QPC and
8949e39c5baSBill Taylor 	 * the port number.  This is because the special QP contexts must
8959e39c5baSBill Taylor 	 * be allocated two-at-a-time.
8969e39c5baSBill Taylor 	 */
8979e39c5baSBill Taylor 	qp->qp_qpnum = qpc->hr_indx + port;
8989e39c5baSBill Taylor 	qp->qp_ring = qp->qp_qpnum << 8;
8999e39c5baSBill Taylor 
9009e39c5baSBill Taylor 	uarpg = state->hs_kernel_uar_index; /* must be for spec qp */
9019e39c5baSBill Taylor 	/*
9029e39c5baSBill Taylor 	 * Allocate the doorbell record.  Hermon uses only one for the RQ so
9039e39c5baSBill Taylor 	 * alloc a qp doorbell, using uarpg (above) as the uar index
9049e39c5baSBill Taylor 	 */
9059e39c5baSBill Taylor 
9069e39c5baSBill Taylor 	status = hermon_dbr_alloc(state, uarpg, &qp->qp_rq_dbr_acchdl,
9079e39c5baSBill Taylor 	    &qp->qp_rq_vdbr, &qp->qp_rq_pdbr, &qp->qp_rdbr_mapoffset);
9089e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
9099e39c5baSBill Taylor 		status = IBT_INSUFF_RESOURCE;
9109e39c5baSBill Taylor 		goto spec_qpalloc_fail5;
9119e39c5baSBill Taylor 	}
9129e39c5baSBill Taylor 	/*
9139e39c5baSBill Taylor 	 * Calculate the appropriate size for the work queues.
9149e39c5baSBill Taylor 	 * Note:  All Hermon QP work queues must be a power-of-2 in size.  Also
9159e39c5baSBill Taylor 	 * they may not be any smaller than HERMON_QP_MIN_SIZE.  This step is
9169e39c5baSBill Taylor 	 * to round the requested size up to the next highest power-of-2
9179e39c5baSBill Taylor 	 */
9189e39c5baSBill Taylor 	attr_p->qp_sizes.cs_sq =
9199e39c5baSBill Taylor 	    max(attr_p->qp_sizes.cs_sq, HERMON_QP_MIN_SIZE);
9209e39c5baSBill Taylor 	attr_p->qp_sizes.cs_rq =
9219e39c5baSBill Taylor 	    max(attr_p->qp_sizes.cs_rq, HERMON_QP_MIN_SIZE);
9229e39c5baSBill Taylor 	log_qp_sq_size = highbit(attr_p->qp_sizes.cs_sq);
923de710d24SJosef 'Jeff' Sipek 	if (ISP2(attr_p->qp_sizes.cs_sq)) {
9249e39c5baSBill Taylor 		log_qp_sq_size = log_qp_sq_size - 1;
9259e39c5baSBill Taylor 	}
9269e39c5baSBill Taylor 	log_qp_rq_size = highbit(attr_p->qp_sizes.cs_rq);
927de710d24SJosef 'Jeff' Sipek 	if (ISP2(attr_p->qp_sizes.cs_rq)) {
9289e39c5baSBill Taylor 		log_qp_rq_size = log_qp_rq_size - 1;
9299e39c5baSBill Taylor 	}
9309e39c5baSBill Taylor 
9319e39c5baSBill Taylor 	/*
9329e39c5baSBill Taylor 	 * Next we verify that the rounded-up size is valid (i.e. consistent
9339e39c5baSBill Taylor 	 * with the device limits and/or software-configured limits).  If not,
9349e39c5baSBill Taylor 	 * then obviously we have a bit of cleanup to do before returning.
9359e39c5baSBill Taylor 	 */
9369e39c5baSBill Taylor 	if ((log_qp_sq_size > state->hs_cfg_profile->cp_log_max_qp_sz) ||
9379e39c5baSBill Taylor 	    (log_qp_rq_size > state->hs_cfg_profile->cp_log_max_qp_sz)) {
9389e39c5baSBill Taylor 		status = IBT_HCA_WR_EXCEEDED;
9399e39c5baSBill Taylor 		goto spec_qpalloc_fail5a;
9409e39c5baSBill Taylor 	}
9419e39c5baSBill Taylor 
9429e39c5baSBill Taylor 	/*
9439e39c5baSBill Taylor 	 * Next we verify that the requested number of SGL is valid (i.e.
9449e39c5baSBill Taylor 	 * consistent with the device limits and/or software-configured
9459e39c5baSBill Taylor 	 * limits).  If not, then obviously the same cleanup needs to be done.
9469e39c5baSBill Taylor 	 */
9479e39c5baSBill Taylor 	max_sgl = state->hs_cfg_profile->cp_wqe_real_max_sgl;
9489e39c5baSBill Taylor 	if ((attr_p->qp_sizes.cs_sq_sgl > max_sgl) ||
9499e39c5baSBill Taylor 	    (attr_p->qp_sizes.cs_rq_sgl > max_sgl)) {
9509e39c5baSBill Taylor 		status = IBT_HCA_SGL_EXCEEDED;
9519e39c5baSBill Taylor 		goto spec_qpalloc_fail5a;
9529e39c5baSBill Taylor 	}
9539e39c5baSBill Taylor 
9549e39c5baSBill Taylor 	/*
9559e39c5baSBill Taylor 	 * Determine this QP's WQE stride (for both the Send and Recv WQEs).
9569e39c5baSBill Taylor 	 * This will depend on the requested number of SGLs.  Note: this
9579e39c5baSBill Taylor 	 * has the side-effect of also calculating the real number of SGLs
9589e39c5baSBill Taylor 	 * (for the calculated WQE size).
9599e39c5baSBill Taylor 	 */
9609e39c5baSBill Taylor 	hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_rq_sgl,
9619e39c5baSBill Taylor 	    max_sgl, HERMON_QP_WQ_TYPE_RECVQ,
9629e39c5baSBill Taylor 	    &qp->qp_rq_log_wqesz, &qp->qp_rq_sgl);
9639e39c5baSBill Taylor 	if (type == IBT_SMI_SQP) {
9649e39c5baSBill Taylor 		hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_sq_sgl,
9659e39c5baSBill Taylor 		    max_sgl, HERMON_QP_WQ_TYPE_SENDMLX_QP0,
9669e39c5baSBill Taylor 		    &qp->qp_sq_log_wqesz, &qp->qp_sq_sgl);
9679e39c5baSBill Taylor 	} else {
9689e39c5baSBill Taylor 		hermon_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_sq_sgl,
9699e39c5baSBill Taylor 		    max_sgl, HERMON_QP_WQ_TYPE_SENDMLX_QP1,
9709e39c5baSBill Taylor 		    &qp->qp_sq_log_wqesz, &